Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix] api 스키마 수정 사항 반영 #134

Merged
merged 6 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ComponentPropsWithoutRef, forwardRef } from 'react';
'use client';

import { ComponentPropsWithoutRef, forwardRef, useEffect, useRef } from 'react';
import { getTimeAgo } from '@web/utils';
import {
contentItemStyle,
Expand All @@ -11,6 +13,7 @@ import { Icon } from '@repo/ui/Icon';
import { IconButton } from '@repo/ui/IconButton';
import { Text } from '@repo/ui/Text';
import { Skeleton } from '@repo/ui/Skeleton';
import { mergeRefs } from '@repo/ui/utils';

export type ContentItemProps = {
/**
Expand Down Expand Up @@ -62,9 +65,16 @@ export const ContentItem = forwardRef<HTMLDivElement, ContentItemProps>(
},
ref
) => {
const itemRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (isSelected && itemRef.current) {
itemRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}, [isSelected]);
return (
<div
ref={ref}
ref={mergeRefs(ref, itemRef)}
className={`${contentItemStyle} ${className ?? ''}`}
{...props}
>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { createContext, Dispatch, SetStateAction } from 'react';
import { EditPost } from './_components/EditPost/EditPost';
import { EditSidebar } from './_components/EditSidebar/EditSidebar';
import { editDetailPage, flexColumn } from './EditDetail.css';
import { editDetailPage, flexColumn } from './page.css';
import { useState } from 'react';
import { Post } from '@web/types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { style } from '@vanilla-extract/css';
import { vars } from '@repo/theme';
import { globalStyle, style } from '@vanilla-extract/css';

export const wrapper = style({
width: '100%',
Expand Down Expand Up @@ -32,3 +33,21 @@ export const titleWrapper = style({
gap: '1.6rem',
padding: '1.6rem 1.2rem 3.2rem 1.2rem',
});

export const chipDropdownTrigger = style({
display: 'flex',
alignItems: 'center',
gap: '0.8rem',
padding: '1.2rem 0.8rem',
borderRadius: vars.borderRadius[12],

':hover': {
backgroundColor: vars.colors.grey25,
},
});

export const dropdownItem = style({
display: 'flex',
alignItems: 'center',
gap: '1rem',
});
Original file line number Diff line number Diff line change
@@ -1,47 +1,111 @@
'use client';

import { IconButton } from '@repo/ui/IconButton';
import { controlBar, postWrapper, titleWrapper, wrapper } from './EditPost.css';
import {
chipDropdownTrigger,
controlBar,
dropdownItem,
postWrapper,
titleWrapper,
wrapper,
} from './EditPost.css';
import { Text } from '@repo/ui/Text';
import { Badge } from '@repo/ui/Badge';
import { PostEditor } from '../PostEditor/PostEditor';
import { EditPromptField } from '../EditPromptField/EditPromptField';
import { FormProvider, useForm } from 'react-hook-form';
import { useParams, useRouter, useSearchParams } from 'next/navigation';
import { useGroupPostsQuery } from '@web/store/query/useGroupPostsQuery';
import { useAdjacentPosts } from '../../_hooks/useAdjacentPosts';
import { useEffect } from 'react';
import { queryClient } from '@web/store/query/QueryClientProvider';
import { getAllPostsQueryOptions } from '@web/store/query/useGetAllPostsQuery';
import { useGetAllPostsQuery } from '@web/store/query/useGetAllPostsQuery';
import { ROUTES } from '@web/routes';
import { Dropdown } from '@repo/ui/Dropdown';
import { Icon } from '@repo/ui/Icon';
import { useDeletePostMutation } from '@web/store/mutation/useDeletePostMutation';
import { useModal } from '@repo/ui/hooks';
import { Modal } from '@repo/ui/Modal';
import { Chip } from '@repo/ui/Chip';
import { PostStatus } from '@web/types';
import { ReactNode } from 'react';
import { useUpdatePostsMutation } from '@web/store/mutation/useUpdatePostsMutation';

const CHIP_DROPDOWN: Partial<Record<PostStatus, ReactNode>> = {
GENERATED: (
<Chip variant="grey" leftAddon={<Chip.Icon variant="grey" name="circle" />}>
생성된 글
</Chip>
),
EDITING: (
<Chip
variant="purple"
leftAddon={<Chip.Icon variant="purple" name="circle" />}
>
수정 중인 글
</Chip>
),
READY_TO_UPLOAD: (
<Chip
variant="green"
leftAddon={<Chip.Icon variant="green" name="circle" />}
>
업로드할 글
</Chip>
),
};

export function EditPost() {
const router = useRouter();
const modal = useModal();
const methods = useForm();
const { agentId, postGroupId } = useParams();
const searchParams = useSearchParams();
const postId = searchParams.get('postId');
const { data } = useGroupPostsQuery(Number(agentId), Number(postGroupId));
const post = data?.data?.posts.find((post) => String(post.id) === postId);

console.log('dfddf', data, post);
console.log('postId:', postId, 'Converted:', Number(postId));
const { data: posts } = useGetAllPostsQuery({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
});
const post = Object.values(posts?.data?.posts)
.flat()
.find((post) => String(post.id) === postId);
Comment on lines 61 to +68
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

posts?.data?.posts가 undefined일 수 있는 경우
Object.values(posts?.data?.posts)에서 posts?.data?.postsundefined이면 런타임 오류가 발생합니다. 안전한 처리가 필요합니다.

다음과 같이 수정하여 예외를 방지할 수 있습니다:

-  const post = Object.values(posts?.data?.posts)
-    .flat()
-    .find((post) => String(post.id) === postId);
+  const post = Object.values(posts?.data?.posts ?? {})
+    .flat()
+    .find((post) => String(post.id) === postId);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const postId = searchParams.get('postId');
const { data } = useGroupPostsQuery(Number(agentId), Number(postGroupId));
const post = data?.data?.posts.find((post) => String(post.id) === postId);
console.log('dfddf', data, post);
console.log('postId:', postId, 'Converted:', Number(postId));
const { data: posts } = useGetAllPostsQuery({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
});
const post = Object.values(posts?.data?.posts)
.flat()
.find((post) => String(post.id) === postId);
const postId = searchParams.get('postId');
const { data: posts } = useGetAllPostsQuery({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
});
const post = Object.values(posts?.data?.posts ?? {})
.flat()
.find((post) => String(post.id) === postId);


const { routePreviousPost, routeNextPost, canMoveUp, canMoveDown } =
useAdjacentPosts(data?.data?.posts, post);
useAdjacentPosts(posts?.data?.posts, post);

const { mutate: deletePost } = useDeletePostMutation({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
});

const handleDeletePost = () => {
modal.confirm({
title: '정말 삭제하시겠어요?',
description: '삭제된 글은 복구할 수 없어요',
icon: <Modal.Icon name="notice" color="warning500" />,
confirmButton: '삭제하기',
cancelButton: '취소',
confirmButtonProps: {
onClick: () => {
deletePost(Number(postId));
},
},
});
};

const { mutate: modifyPost, isPending } = useUpdatePostsMutation({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
});

// TODO 제거 예정 UT용...
useEffect(() => {
queryClient.invalidateQueries(
getAllPostsQueryOptions({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
})
);
queryClient.invalidateQueries({
queryKey: ['postGroup', 'Agents'],
const handleChipClick = (status: PostStatus) => {
if (!postId) return;
modifyPost({
posts: [
{
postId: Number(postId),
status: status,
},
],
});
}, []);
};

return (
<div className={wrapper}>
Expand All @@ -60,7 +124,23 @@ export function EditPost() {
</div>

<div>
<IconButton icon="dots" />
<Dropdown>
<Dropdown.Trigger>
<IconButton icon="dots" />
</Dropdown.Trigger>
<Dropdown.Content align="right">
<Dropdown.Item
value="option1"
className={dropdownItem}
onClick={handleDeletePost}
>
<Icon name="trash" size="2.4rem" color="grey400" />
<Text fontSize={18} fontWeight="medium" color="grey1000">
삭제하기
</Text>
</Dropdown.Item>
</Dropdown.Content>
</Dropdown>
<IconButton
icon="x"
iconType="stroke"
Expand All @@ -77,6 +157,36 @@ export function EditPost() {
</div>

<div className={postWrapper}>
<Dropdown>
<Dropdown.Trigger className={chipDropdownTrigger}>
{CHIP_DROPDOWN[post?.status || 'EDITING']}
<Dropdown.Icon
name="arrowLineBottom"
color="grey300"
size={'2.4rem'}
/>
</Dropdown.Trigger>
<Dropdown.Content align="left">
<Dropdown.Item
value="option1"
onClick={() => handleChipClick('GENERATED')}
>
{CHIP_DROPDOWN.GENERATED}
</Dropdown.Item>
<Dropdown.Item
value="option1"
onClick={() => handleChipClick('EDITING')}
>
{CHIP_DROPDOWN.EDITING}
</Dropdown.Item>
<Dropdown.Item
value="option1"
onClick={() => handleChipClick('READY_TO_UPLOAD')}
>
{CHIP_DROPDOWN.READY_TO_UPLOAD}
</Dropdown.Item>
</Dropdown.Content>
</Dropdown>
<div className={titleWrapper}>
<Text color="grey1000" fontSize={28} fontWeight="bold">
{post?.summary}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import { Checkbox } from '@repo/ui/Checkbox';
import { TextField } from '@repo/ui/TextField';
import { Controller, useForm, useFormContext } from 'react-hook-form';
import { Controller, useForm } from 'react-hook-form';
import { wrapper } from './EditPromptField.css';
import { Spacing } from '@repo/ui/Spacing';
import { isEmptyStringOrNil } from '@web/utils';
import { usePatchPromptMutation } from '@web/store/mutation/usePatchPromptMutation';
import { useParams, useSearchParams } from 'next/navigation';
import { useContext, useEffect } from 'react';
import { DetailPageContext } from '../../EditDetail';
import { useGroupPostsQuery } from '@web/store/query/useGroupPostsQuery';
import { useGetAllPostsQuery } from '@web/store/query/useGetAllPostsQuery';
import { useUpdatePromptMutation } from '@web/store/mutation/useUpdatePromptMutation';

export function EditPromptField() {
const { register, watch, control, handleSubmit } = useForm<{
Expand All @@ -22,28 +22,33 @@ export function EditPromptField() {
prompt: '',
},
});
const { loadingPosts, setLoadingPosts } = useContext(DetailPageContext);
const { setLoadingPosts } = useContext(DetailPageContext);
const isEntire = watch('isEntire');
const prompt = watch('prompt');
const isSubmitDisabled = isEmptyStringOrNil(prompt);
const { agentId, postGroupId } = useParams();
const searchParams = useSearchParams();
const postId = searchParams.get('postId');
const { data } = useGroupPostsQuery(Number(agentId), Number(postGroupId));
const { data } = useGetAllPostsQuery({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
});
const posts = data?.data.posts ?? [];
const editingPosts = posts
const editingPosts = Object.values(posts)
.flat()
.filter((post) => post.status === 'EDITING')
.map((post) => post.id);

const { mutate: patchPrompt, isPending } = usePatchPromptMutation({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
postId: Number(postId),
});
const { mutate: updatePrompt, isPending: isUpdatePromptPending } =
useUpdatePromptMutation({
agentId: Number(agentId),
postGroupId: Number(postGroupId),
postId: Number(postId),
});

// TODO 제거 예정
useEffect(() => {
if (isPending) {
if (isUpdatePromptPending) {
// 요청이 진행 중이면
if (isEntire) {
setLoadingPosts(editingPosts);
Expand All @@ -59,10 +64,16 @@ export function EditPromptField() {
setLoadingPosts((prev) => prev.filter((id) => id !== Number(postId)));
}
}
}, [isPending]);
}, [isUpdatePromptPending]);

const onSubmit = async (data: { isEntire: boolean; prompt: string }) => {
patchPrompt({ ...data });
const editingPostIds = posts.EDITING.map((item) => item.id);

if (isEntire) {
updatePrompt({ ...data, postsId: editingPostIds });
} else {
updatePrompt({ ...data });
}
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { style } from '@vanilla-extract/css';

export const sidebarWrapper = style({
width: '52rem',
height: '100vh',
height: 'fit-content',
overflow: 'hidden',
boxSizing: 'border-box',
flexShrink: '0',
background:
'linear-gradient(174deg, rgba(255, 255, 255, 0.55) -11.84%, rgba(243, 244, 249, 0.55) 29.91%, rgba(231, 232, 251, 0.55) 100%)',
Expand All @@ -16,6 +18,7 @@ export const breadcrumbWrapper = style({

export const contentWrapper = style({
padding: '0rem 6.4rem 3.2rem 6.4rem',
height: 'calc(100vh - 8rem)',
});

export const accordionTrigger = style({
Expand Down
Loading
Loading