Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend
This commit is contained in:
@@ -26,7 +26,7 @@ export const commentFormSchema = z.object({
|
||||
cmntCn: z.string(),
|
||||
wrtrNm: z.string().nullish(),
|
||||
cmntPswd: z.string(),
|
||||
cmntEvl: z.number().nullish(),
|
||||
cmntEvl: z.string().nullish(),
|
||||
});
|
||||
|
||||
export const commentUpdateFormSchema = commentFormSchema.omit({
|
||||
|
||||
@@ -311,7 +311,11 @@ function BbsForm({ form, bbsId, ...props }: BbsFormProps) {
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="cmntUseY" />
|
||||
<Label htmlFor="cmntUseY">사용</Label>
|
||||
<Label htmlFor="cmntUseY">일반댓글</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="C" id="cmntUseC" />
|
||||
<Label htmlFor="cmntUseC">평가댓글</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="cmntUseN" />
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
||||
import { keepPreviousData, useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { getCoreRowModel, type PaginationState } from "@tanstack/react-table";
|
||||
import { Button, Input, Label } from "@common/components";
|
||||
import { LwpoCodeApi, type LwpoCodeParams } from "@/entities/code";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useDataTable } from "@/shared/lib";
|
||||
import { useAlertStore, useDataTable } from "@/shared/lib";
|
||||
import { columns } from "../model/lwpocode-table-columns";
|
||||
import { LwpoCodeManagementDialog } from "./lwpocode-dialog";
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
|
||||
type LwpoCodeSectionProps = {
|
||||
upCd?: string;
|
||||
};
|
||||
|
||||
function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) {
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [lwpoCodeQuery, setLwpoCodeQuery] = useState<LwpoCodeParams>({
|
||||
lwpoCdNm: "",
|
||||
@@ -36,6 +36,13 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) {
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
const { mutateAsync: codeRefreshAll } = useMutation({
|
||||
mutationFn: LwpoCodeApi.codeRefreshAll,
|
||||
onSuccess: () => {
|
||||
alert("코드 갱신이 완료되었습니다.");
|
||||
},
|
||||
});
|
||||
|
||||
const { tableComponent } = useDataTable({
|
||||
query,
|
||||
tableOptions: {
|
||||
@@ -59,20 +66,6 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) {
|
||||
setPagination({ ...pagination, pageIndex: 0 });
|
||||
}, [upCd]);
|
||||
|
||||
const { mutateAsync: codeRefreshAll } = useMutation({
|
||||
mutationFn: () => LwpoCodeApi.codeRefreshAll(),
|
||||
onSuccess: () => {
|
||||
alert('저장되었습니다.')
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('에러 발생:', error)
|
||||
alert('에러가 발생했습니다.')
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="flex-1">
|
||||
<div className="card card-border">
|
||||
@@ -98,17 +91,17 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) {
|
||||
<div className="card card-border">
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium text-label">하위코드 목록</h3>
|
||||
<button onClick={() => codeRefreshAll()} className="btn">
|
||||
코드 리프레시
|
||||
</button>
|
||||
|
||||
<LwpoCodeManagementDialog
|
||||
open={dialogOpen}
|
||||
onOpenChange={setDialogOpen}
|
||||
>
|
||||
<Button>등록</Button>
|
||||
</LwpoCodeManagementDialog>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button color="emerald" onClick={() => codeRefreshAll()}>
|
||||
코드갱신
|
||||
</Button>
|
||||
<LwpoCodeManagementDialog
|
||||
open={dialogOpen}
|
||||
onOpenChange={setDialogOpen}
|
||||
>
|
||||
<Button>등록</Button>
|
||||
</LwpoCodeManagementDialog>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !m-4 h-[calc(100vh-35rem)] overflow-auto !p-0">
|
||||
{tableComponent}
|
||||
|
||||
@@ -64,12 +64,7 @@ function DateTimePicker({ date, classes, onDateChange }: DateTimePickerProps) {
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<div className="sm:flex">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={handleDateSelect}
|
||||
initialFocus
|
||||
/>
|
||||
<Calendar mode="single" selected={date} onSelect={handleDateSelect} />
|
||||
<div className="flex flex-col divide-y sm:h-[300px] sm:flex-row sm:divide-x sm:divide-y-0">
|
||||
<ScrollArea className="w-64 sm:w-auto">
|
||||
<div className="flex p-2 sm:flex-col">
|
||||
|
||||
@@ -4,7 +4,14 @@ import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Button, Input, Textarea } from "@common/components";
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
Label,
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
Textarea,
|
||||
} from "@common/components";
|
||||
import {
|
||||
CommentApi,
|
||||
commentFormSchema,
|
||||
@@ -14,6 +21,7 @@ import {
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import {
|
||||
useAlertStore,
|
||||
useMenuStore,
|
||||
useMutationWrapper,
|
||||
usePrompt,
|
||||
useUserStore,
|
||||
@@ -24,10 +32,11 @@ function PostComment({ bbsId, pstNo }: { bbsId: number; pstNo: number }) {
|
||||
const { prompt } = usePrompt();
|
||||
const { confirm } = useConfirm();
|
||||
const queryClient = useQueryClient();
|
||||
const bbsInfo = useMenuStore((state) => state.bbsInfo);
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const [editValue, setEditValue] = useState("");
|
||||
const [editingCmntNo, setEditingCmntNo] = useState<number | null>(null);
|
||||
const [editValue, setEditValue] = useState<string>("");
|
||||
|
||||
const { data: comments } = useQuery({
|
||||
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_COMMENTS, pstNo],
|
||||
@@ -123,6 +132,46 @@ function PostComment({ bbsId, pstNo }: { bbsId: number; pstNo: number }) {
|
||||
<div className="card card-border !p-8">
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
{bbsInfo?.cmntUseYn === "C" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cmntEvl"
|
||||
render={({ field }) => (
|
||||
<FormItem className="mb-4">
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
name="cmntEvl"
|
||||
value={field.value?.toString() ?? ""}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="5" id="cmntEvl5" />
|
||||
<Label htmlFor="cmntEvl5">매우만족 ★★★★★</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="4" id="cmntEvl4" />
|
||||
<Label htmlFor="cmntEvl4">만족 ★★★★</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="3" id="cmntEvl3" />
|
||||
<Label htmlFor="cmntEvl3">보통 ★★★</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="2" id="cmntEvl2" />
|
||||
<Label htmlFor="cmntEvl2">불만족 ★★</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="1" id="cmntEvl1" />
|
||||
<Label htmlFor="cmntEvl1">매우불만족 ★</Label>
|
||||
</div>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cmntCn"
|
||||
@@ -188,71 +237,80 @@ function PostComment({ bbsId, pstNo }: { bbsId: number; pstNo: number }) {
|
||||
if (comment.delYn === "Y") return null;
|
||||
return (
|
||||
<div
|
||||
className="flex justify-between gap-2 border-t border-gray-200 py-8"
|
||||
key={comment.cmntNo}
|
||||
className="flex flex-col border-t border-gray-200 py-8"
|
||||
>
|
||||
<div className="flex w-full gap-10">
|
||||
<div className="flex w-[10rem] shrink-0 flex-col">
|
||||
<span className="text-[1.4rem] font-bold text-label">
|
||||
{comment.wrtrNm}
|
||||
</span>
|
||||
<span className="text-[1.2rem] text-label">
|
||||
{dayjs(comment.regDt).format("YYYY.MM.DD")}
|
||||
</span>
|
||||
</div>
|
||||
{editingCmntNo === comment.cmntNo ? (
|
||||
<div className="flex flex-1 flex-col gap-2">
|
||||
<Textarea
|
||||
value={editValue}
|
||||
onChange={(e) => setEditValue(e.target.value)}
|
||||
maxLength={1000}
|
||||
className="h-[10rem] bg-background p-4 !text-[1.3rem] !leading-6"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
handleUpdateComment(comment.cmntNo, comment.wrtrNm)
|
||||
}
|
||||
>
|
||||
저장
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
color="gray"
|
||||
onClick={() => {
|
||||
setEditingCmntNo(null);
|
||||
setEditValue("");
|
||||
}}
|
||||
>
|
||||
취소
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<p className="break-all text-[1.4rem] text-foreground">
|
||||
{comment.cmntCn}
|
||||
</p>
|
||||
<div>
|
||||
{Array.from({ length: Number(comment.cmntEvl) }).map(
|
||||
(_, index) => (
|
||||
<span key={index}>★</span>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2 whitespace-nowrap">
|
||||
<Button
|
||||
size="icon"
|
||||
color="white"
|
||||
onClick={() => {
|
||||
setEditingCmntNo(comment.cmntNo);
|
||||
setEditValue(comment.cmntCn);
|
||||
}}
|
||||
>
|
||||
<i className="diveicon di-pencil" />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
color="white"
|
||||
onClick={() => handleDeleteComment(comment.cmntNo)}
|
||||
>
|
||||
<i className="diveicon di-trash" />
|
||||
</Button>
|
||||
<div className="flex justify-between">
|
||||
<div className="flex w-full gap-10">
|
||||
<div className="flex w-[10rem] shrink-0 flex-col">
|
||||
<span className="text-[1.4rem] font-bold text-label">
|
||||
{comment.wrtrNm}
|
||||
</span>
|
||||
<span className="text-[1.2rem] text-label">
|
||||
{dayjs(comment.regDt).format("YYYY.MM.DD")}
|
||||
</span>
|
||||
</div>
|
||||
{editingCmntNo === comment.cmntNo ? (
|
||||
<div className="flex flex-1 flex-col gap-2">
|
||||
<Textarea
|
||||
value={editValue}
|
||||
onChange={(e) => setEditValue(e.target.value)}
|
||||
maxLength={1000}
|
||||
className="h-[10rem] bg-background p-4 !text-[1.3rem] !leading-6"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
handleUpdateComment(comment.cmntNo, comment.wrtrNm)
|
||||
}
|
||||
>
|
||||
저장
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
color="gray"
|
||||
onClick={() => {
|
||||
setEditingCmntNo(null);
|
||||
setEditValue("");
|
||||
}}
|
||||
>
|
||||
취소
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<p className="break-all text-[1.4rem] text-foreground">
|
||||
{comment.cmntCn}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2 whitespace-nowrap">
|
||||
<Button
|
||||
size="icon"
|
||||
color="white"
|
||||
onClick={() => {
|
||||
setEditingCmntNo(comment.cmntNo);
|
||||
setEditValue(comment.cmntCn);
|
||||
}}
|
||||
>
|
||||
<i className="diveicon di-pencil" />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
color="white"
|
||||
onClick={() => handleDeleteComment(comment.cmntNo)}
|
||||
>
|
||||
<i className="diveicon di-trash" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user