diff --git a/apps/cs/app/(with-base-layout)/survey/page.tsx b/apps/cs/app/(with-base-layout)/survey/page.tsx new file mode 100644 index 000000000..85db42486 --- /dev/null +++ b/apps/cs/app/(with-base-layout)/survey/page.tsx @@ -0,0 +1,2 @@ +import { SurveyPage } from "@/pages/survey"; +export default SurveyPage; diff --git a/apps/cs/app/(with-base-layout)/survey/register/page.tsx b/apps/cs/app/(with-base-layout)/survey/register/page.tsx new file mode 100644 index 000000000..3d7307937 --- /dev/null +++ b/apps/cs/app/(with-base-layout)/survey/register/page.tsx @@ -0,0 +1,2 @@ +import { CreatePage } from "@/pages/survey"; +export default CreatePage; diff --git a/apps/cs/src/entities/posting/model/posting-interface.ts b/apps/cs/src/entities/posting/model/posting-interface.ts index 72c49bb03..202bffb82 100644 --- a/apps/cs/src/entities/posting/model/posting-interface.ts +++ b/apps/cs/src/entities/posting/model/posting-interface.ts @@ -5,6 +5,7 @@ export const POSTING_TYPE = { POPUP: "POPUP", BANNER: "BANNER", IMAGE: "IMAGE", + SURVEY: "SURVEY", } as const; export type PostingType = (typeof POSTING_TYPE)[keyof typeof POSTING_TYPE]; diff --git a/apps/cs/src/pages/survey/api/survey-service.ts b/apps/cs/src/pages/survey/api/survey-service.ts new file mode 100644 index 000000000..1b9931621 --- /dev/null +++ b/apps/cs/src/pages/survey/api/survey-service.ts @@ -0,0 +1,23 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { + SurveyParams, + SurveyList, + SurveyService, + SurveyFormData, +} from "../model/survey-interface"; + +export class SurveyApiService implements SurveyService { + public async getSurveyList(params: SurveyParams): Promise { + const response = await client.get(ENDPOINT.CMS_SERVICE.SURVEY, { + params, + }); + return response.data; + } + + public async createSurvey(data: SurveyFormData): Promise { + await client.post(ENDPOINT.CMS_SERVICE.SURVEY, data); + } +} + +export const SurveyApi = new SurveyApiService(); diff --git a/apps/cs/src/pages/survey/index.ts b/apps/cs/src/pages/survey/index.ts new file mode 100644 index 000000000..726f64a38 --- /dev/null +++ b/apps/cs/src/pages/survey/index.ts @@ -0,0 +1,2 @@ +export { SurveyPage } from "./ui/survey-page"; +export { CreatePage } from "./ui/create-page"; diff --git a/apps/cs/src/pages/survey/model/survey-interface.ts b/apps/cs/src/pages/survey/model/survey-interface.ts new file mode 100644 index 000000000..432d0490c --- /dev/null +++ b/apps/cs/src/pages/survey/model/survey-interface.ts @@ -0,0 +1,38 @@ +import { z } from "zod"; +import type { PageableList, PageableParams } from "@/shared/model"; + +export interface SurveyParams extends PageableParams { + keywordType?: string; + keyword?: string; + srvyTtl?: string; + srvyPrps?: string; + srvyTrgt?: string; + srvyWrtGdCn?: string; + delYn?: string; +} + +export interface Survey { + srvySn: number; + srvyTtl: string; + srvyPrps: string; + srvyTrgt: string; + srvyTrgtNm: string; + delYn: string; + regDt: string; + rgTrNm: string; +} + +export const surveyFormSchema = z.object({ + srvyTtl: z.string(), + srvyPrps: z.string(), + srvyTrgt: z.string().nullish(), + srvyWrtGdCn: z.string().nullish(), +}); + +export type SurveyList = PageableList; +export type SurveyFormData = z.infer; + +export interface SurveyService { + getSurveyList(params: SurveyParams): Promise; + createSurvey(data: SurveyFormData): Promise; +} diff --git a/apps/cs/src/pages/survey/model/table-columns.tsx b/apps/cs/src/pages/survey/model/table-columns.tsx new file mode 100644 index 000000000..b0b6114d0 --- /dev/null +++ b/apps/cs/src/pages/survey/model/table-columns.tsx @@ -0,0 +1,60 @@ +import type { ColumnDef } from "@tanstack/react-table"; +import { Checkbox } from "@common/components"; +import type { Survey } from "./survey-interface"; + +export const columns: ColumnDef[] = [ + { + id: "select", + header: ({ table }) => ( + e.stopPropagation()} + onCheckedChange={(checked) => + table.toggleAllPageRowsSelected(!!checked) + } + className="h-4 w-4 rounded border-gray-300" + /> + ), + cell: ({ row }) => ( + e.stopPropagation()} + onCheckedChange={(checked) => row.toggleSelected(!!checked)} + className="h-4 w-4 rounded border-gray-300" + /> + ), + meta: { + width: 50, + }, + }, + { + id: "no", + header: "NO", + cell: ({ row, table }) => { + const { pageIndex, pageSize } = table.getState().pagination; + const totalRows = table.getRowCount(); + return totalRows - (pageIndex * pageSize + row.index); + }, + meta: { + width: 50, + }, + }, + { + accessorKey: "srvyTtl", + header: "설문제목", + }, + { + accessorKey: "srvyTrgt", + header: "설문대상", + }, + { + id: "preview", + header: "설문 보기", + cell: () => {}, + }, + { + id: "result", + header: "설문 결과", + cell: () => {}, + }, +]; diff --git a/apps/cs/src/pages/survey/ui/create-page.tsx b/apps/cs/src/pages/survey/ui/create-page.tsx new file mode 100644 index 000000000..8ed685599 --- /dev/null +++ b/apps/cs/src/pages/survey/ui/create-page.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useForm } from "react-hook-form"; +import { useMutation } from "@tanstack/react-query"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useAlertStore } from "@/shared/lib"; +import { + surveyFormSchema, + type SurveyFormData, +} from "../model/survey-interface"; +import { SurveyApi } from "../api/survey-service"; +import { SurveyForm } from "./survey-form"; + +function CreatePage() { + const router = useRouter(); + const { setMessage: alert } = useAlertStore((state) => state); + + const { mutateAsync: createSurvey } = useMutation({ + mutationFn: (data: SurveyFormData) => SurveyApi.createSurvey(data), + onSuccess: () => { + alert("등록되었습니다.", router.back); + }, + }); + + const form = useForm({ + resolver: zodResolver(surveyFormSchema), + }); + + return ( +
+
+

설문 등록

+
+ +
+ ); +} + +export { CreatePage }; diff --git a/apps/cs/src/pages/survey/ui/survey-form.tsx b/apps/cs/src/pages/survey/ui/survey-form.tsx new file mode 100644 index 000000000..332f4af66 --- /dev/null +++ b/apps/cs/src/pages/survey/ui/survey-form.tsx @@ -0,0 +1,153 @@ +import { + Input, + Label, + RadioGroup, + RadioGroupItem, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Textarea, +} from "@common/components"; +import { FormWrapper } from "@/widgets/form-wrapper"; +import { CodeSelect } from "@/entities/code"; +import { FormControl, FormField, FormItem } from "@/shared/ui/form"; +import type { SurveyFormData } from "../model/survey-interface"; +import type { UseFormReturn } from "react-hook-form"; + +type SurveyFormProps = { + form: UseFormReturn; + handleSave: (data: SurveyFormData) => Promise; +}; + +function SurveyForm({ form, ...props }: SurveyFormProps) { + return ( + +
+ + + + + + + + 설문 제목 + + ( + + + + + + )} + /> + + + + 설문 목적 + + ( + + +