Skip to content

Commit

Permalink
백오피스 글귀 생성 관련 UI (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
bepyan authored Feb 1, 2024
2 parents 3f8e715 + d89622b commit 1ff8e96
Show file tree
Hide file tree
Showing 19 changed files with 497 additions and 122 deletions.
2 changes: 2 additions & 0 deletions apps/back-office/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@tanstack/react-query": "^5.17.19",
Expand All @@ -34,6 +35,7 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.49.3",
"sonner": "^1.3.1",
"vaul": "^0.8.9",
"zod": "^3.22.4",
"zustand": "^4.4.7"
},
Expand Down
19 changes: 13 additions & 6 deletions apps/back-office/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import ManageServiceTemplate from "~/components/manage-service/manage-service-template";
import {
ManageDrawerContent,
ManageDrawerRoot,
} from "~/components/manage-service/manage-drawer";
import ManageServiceTable from "~/components/manage-service/manage-table";

/**
* @todo 글 추가하기, 수정하기 컴포넌트는 여기다 띄우고
* 상태 관리 콜백만 ManageSderviceTemplate에 넘기면 될듯요
*/
export default function Page() {
return (
<div className="px-6 py-8 pb-[126px] space-y-7">
<div className="flex items-center mb-6">
<h1 className="text-2xl font-bold">서비스 관리</h1>
<ManageDrawerRoot>
<div className="px-6 py-8 pb-[126px] space-y-7">
<div className="flex items-center mb-6">
<h1 className="text-2xl font-bold">서비스 관리</h1>
</div>
<ManageServiceTable />
</div>
<ManageServiceTemplate />
</div>
<ManageDrawerContent />
</ManageDrawerRoot>
);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { create } from "zustand";

export const useManageDrawer = create<{
open: boolean;
// biome-ignore lint/suspicious/noExplicitAny: API 연동 후 타입 정의
data?: any;
setOpen: (open: boolean) => void;
openNewDrawer: () => void;
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
openEditDrawer: (data: any) => void;
}>((set) => ({
open: false,
data: undefined,
setOpen: (open) => set({ open }),
openNewDrawer: () => {
set({ open: true, data: undefined });
},
openEditDrawer: (data) => {
set({ open: true, data });
},
}));
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { useState } from "react";
import { getPhraseItemListMocks } from "~/components/manage-service/manage-service.meta";
import { PaginationData } from "~/types/pagination";
import { PhraseItemWithId } from "~/types/phrase";
import { ManagePagination } from "../manage-pagination";
import { OnCheck, OnDelete } from "../manage-service.type";
import { ManagePagination } from "../manage-table/pagination";

const useManagePagination = (
data: Array<PhraseItemWithId>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { UseFormProps } from "react-hook-form";
import * as z from "zod";

export const manageSchema = z.object({
title: z.string(),
image: z.string().optional(),
content: z.string(),
});

export const manageResolver = zodResolver(manageSchema);

export type ManageValues = z.infer<typeof manageSchema>;

export const defaultValues = {
title: "",
content: "",
} satisfies ManageValues;

export const manageFormProps = {
resolver: manageResolver,
defaultValues,
} satisfies UseFormProps<ManageValues>;
130 changes: 130 additions & 0 deletions apps/back-office/src/components/manage-service/manage-drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"use client";

import { Plus } from "lucide-react";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { Button } from "~/components/ui/button";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerMain,
} from "~/components/ui/drawer";
import { Form, FormControl, FormField, FormItem } from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import { Separator } from "~/components/ui/separator";
import { Textarea } from "~/components/ui/textarea";
import { useManageDrawer } from "./hooks/use-manage-drawer";
import { ManageValues, manageFormProps } from "./manage-drawer.meta";

export function ManageDrawerRoot(props: React.ComponentProps<typeof Drawer>) {
const { open, setOpen } = useManageDrawer();

return <Drawer {...props} modal={false} open={open} onOpenChange={setOpen} />;
}

export function ManageDrawerContent() {
const form = useForm<ManageValues>(manageFormProps);

const isDrawerOpen = useManageDrawer((v) => v.open);
const isEdit = useManageDrawer((v) => !!v.data);
const defaultValues = useManageDrawer((v) => v.data);
const closeDrawer = useManageDrawer((v) => () => v.setOpen(false));

useEffect(() => {
if (isDrawerOpen) {
form.reset(defaultValues ?? manageFormProps.defaultValues);
}
}, [form, isDrawerOpen, defaultValues]);

async function onSubmit(values: ManageValues) {
console.log(values);

if (isEdit) {
toast.success("수정되었습니다.");
} else {
toast.success("추가되었습니다.");
}

closeDrawer();
}

return (
<Form {...form}>
<DrawerContent asChild>
<form
className="min-w-[480px] w-1/3"
onSubmit={form.handleSubmit(onSubmit)}
>
<DrawerHeader />
<DrawerMain>
<FormField
control={form.control}
name="title"
render={({ field }) => (
<FormItem>
<FormControl>
<Textarea
className="min-h-9 text-2xl font-bold"
placeholder="제목 없음"
{...field}
/>
</FormControl>
</FormItem>
)}
/>
<Separator />
<div className="flex w-full items-center gap-1.5">
<Label
htmlFor="phrase-img"
className="text-base text-muted-foreground"
>
이미지를 추가해 주세요.
</Label>
<Input
id="phrase-img"
type="file"
accept="image/*"
multiple={true}
className="hidden"
/>
<Button variant="ghost" size="icon" className="ml-auto -my-2">
<Plus className="w-6 h-6 text-muted-foreground" />
</Button>
</div>
<Separator />
<FormField
control={form.control}
name="content"
render={({ field }) => (
<FormItem>
<FormControl>
<Textarea
placeholder="텍스트를 작성해 주세요"
className="h-full"
{...field}
/>
</FormControl>
</FormItem>
)}
/>
</DrawerMain>
<DrawerFooter>
<DrawerClose asChild>
<Button variant="secondary" size="lg">
취소
</Button>
</DrawerClose>
<Button variant="default" size="lg">
저장
</Button>
</DrawerFooter>
</form>
</DrawerContent>
</Form>
);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@ const phraseItemMocks: PhraseItem = {
likeCount: 9999999,
};

const getPhraseItemListMocks = (num: number): Array<PhraseItemWithId> =>
export const getPhraseItemListMocks = (num: number): Array<PhraseItemWithId> =>
Array.from({ length: num }, (_, idx) => ({
...phraseItemMocks,
id: idx + 1,
}));

const rowsPerPageOptions = [
export const rowsPerPageOptions = [
{ value: "10", label: "10개" },
{ value: "30", label: "30개" },
{ value: "50", label: "50개" },
{ value: "100", label: "100개" },
];

export { getPhraseItemListMocks, rowsPerPageOptions };
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import DisplayDataNumSelect from "~/components/manage-service/manage-table/display-data-num-select";
import { Button } from "~/components/ui/button";
import { Checkbox } from "~/components/ui/checkbox";

type Props = {
isAllDeleteChecked: boolean;
onCheckAllDelete: (checked: boolean) => void;
onRowSizeChange: (value: string) => void;
onClickCreate: () => void;
};

export const ManageActionBar = ({
isAllDeleteChecked,
onCheckAllDelete,
onRowSizeChange,
onClickCreate,
}: Props) => {
return (
<div className="flex justify-between items-center">
<div className="flex justify-center items-center">
<Checkbox
checked={isAllDeleteChecked}
className="m-4 data-[state=checked]:bg-slate-600"
onCheckedChange={onCheckAllDelete}
/>
<Button className="py-2 px-4 bg-slate-100 text-slate-900 font-semibold rounded-[6px] hover:bg-slate-100">
삭제
</Button>
</div>
<div className="flex justify-center items-center">
<DisplayDataNumSelect onValueChange={onRowSizeChange} />
<Button
className="py-2 px-4 bg-slate-900 ml-[12px] font-semibold rounded-[6px] hover:bg-slate-900"
onClick={onClickCreate}
>
추가하기
</Button>
</div>
</div>
);
};
Loading

0 comments on commit 1ff8e96

Please sign in to comment.