@farmzone/fz-template-react 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +46 -50
  2. package/package.json +1 -1
  3. package/template/.env.example +5 -5
  4. package/template/package.json +55 -55
  5. package/template/pnpm-lock.yaml +4214 -4214
  6. package/template/public/mockServiceWorker.js +349 -349
  7. package/template/src/app/api/api.ts +178 -178
  8. package/template/src/app/api/queries.ts +326 -321
  9. package/template/src/app/api/queryKey.ts +7 -7
  10. package/template/src/app/api/token.ts +7 -7
  11. package/template/src/app/layout/Layout.tsx +33 -33
  12. package/template/src/app/layout/ListContents.tsx +9 -9
  13. package/template/src/app/layout/ListHeader.tsx +41 -41
  14. package/template/src/app/layout/MultiTabNav.tsx +101 -101
  15. package/template/src/app/layout/Sidebar.tsx +33 -33
  16. package/template/src/app/layout/UserInfo.tsx +94 -94
  17. package/template/src/app/layout/tabSwitchStore.ts +11 -11
  18. package/template/src/app/router/Router.tsx +56 -56
  19. package/template/src/app/store/index.ts +26 -26
  20. package/template/src/index.tsx +21 -21
  21. package/template/src/mocks/browser.ts +17 -17
  22. package/template/src/mocks/handlers.ts +43 -43
  23. package/template/src/mocks/scenarios.ts +57 -57
  24. package/template/src/pages/dashboard/index.tsx +541 -541
  25. package/template/src/pages/error/Error.tsx +29 -29
  26. package/template/src/pages/error/NotFound.tsx +27 -27
  27. package/template/src/pages/login/index.tsx +317 -317
  28. package/template/src/pages/post/PostFormModal.tsx +128 -128
  29. package/template/src/pages/post/detail/index.tsx +548 -548
  30. package/template/src/pages/post/index.tsx +266 -267
  31. package/template/src/pages/sample/SampleFormModal.tsx +115 -77
  32. package/template/src/pages/sample/detail/index.tsx +400 -424
  33. package/template/src/pages/sample/index.tsx +278 -269
  34. package/template/src/pages/sample/modal/index.tsx +300 -253
  35. package/template/src/pages/system/log/index.tsx +173 -173
  36. package/template/src/pages/user/config/columns.tsx +102 -109
  37. package/template/src/pages/user/config/schema.ts +54 -54
  38. package/template/src/pages/user/index.tsx +641 -641
  39. package/template/src/shared/components/CommentInput.tsx +243 -243
  40. package/template/src/shared/config/text.ts +27 -27
  41. package/template/src/shared/utils/format.ts +11 -11
  42. package/template/src/types/auth.ts +10 -10
  43. package/template/src/types/comment.ts +33 -33
  44. package/template/src/types/common.ts +19 -19
  45. package/template/src/types/dashboard.ts +53 -53
  46. package/template/src/types/index.ts +16 -16
  47. package/template/src/types/log.ts +21 -21
  48. package/template/src/types/post.ts +32 -32
  49. package/template/src/types/sample.ts +29 -28
  50. package/template/src/types/user.ts +51 -51
  51. package/template/src/vite-env.d.ts +10 -10
@@ -1,128 +1,128 @@
1
- import {
2
- Button,
3
- FileUploader,
4
- Modal,
5
- ModalBody,
6
- ModalFooter,
7
- ModalIconHeader,
8
- SubmitForm,
9
- } from "@farmzone/fz-react-ui";
10
- import { Paperclip, X } from "lucide-react";
11
- import { z } from "zod";
12
-
13
- import type { FileResponse } from "@/types";
14
-
15
- export const postFormSchema = z.object({
16
- title: z.string().min(1, "제목을 입력해 주세요."),
17
- content: z.string().min(1, "내용을 입력해 주세요."),
18
- noticeCategory: z.string(),
19
- visible: z.boolean(),
20
- });
21
-
22
- export type PostFormData = z.infer<typeof postFormSchema>;
23
-
24
- export const POST_FORM_DEFAULT_VALUES: PostFormData = {
25
- title: "",
26
- content: "",
27
- noticeCategory: "NOTICE",
28
- visible: true,
29
- };
30
-
31
- const NOTICE_CATEGORY_OPTIONS = [{ label: "공지", value: "NOTICE" }];
32
-
33
- interface PostFormModalProps {
34
- mode: "create" | "edit";
35
- isOpen: boolean;
36
- onClose: () => void;
37
- defaultValues?: PostFormData;
38
- onSubmit: (data: PostFormData) => Promise<void>;
39
- isPending: boolean;
40
- pendingFiles: Array<File>;
41
- onPendingFilesChange: (files: Array<File>) => void;
42
- existingFiles?: Array<FileResponse>;
43
- onDeleteExistingFile?: (id: number) => void;
44
- formKey?: string | number;
45
- }
46
-
47
- export function PostFormModal({
48
- mode,
49
- isOpen,
50
- onClose,
51
- defaultValues,
52
- onSubmit,
53
- isPending,
54
- pendingFiles,
55
- onPendingFilesChange,
56
- existingFiles,
57
- onDeleteExistingFile,
58
- formKey,
59
- }: PostFormModalProps) {
60
- const formId = mode === "create" ? "post-create-form" : "post-edit-form";
61
- const title = mode === "create" ? "게시글 등록" : "게시글 수정";
62
- const submitLabel = mode === "create" ? "등록" : "수정";
63
-
64
- return (
65
- <Modal isOpen={isOpen} onClose={onClose} contentClassName="max-w-3xl rounded-xl bg-white">
66
- <ModalIconHeader type={mode} title={title} onClose={onClose} />
67
- <ModalBody className="px-6 py-5">
68
- <div className="space-y-4">
69
- <div className="overflow-hidden rounded-lg border border-gray-200">
70
- <SubmitForm
71
- key={formKey}
72
- formId={formId}
73
- schema={postFormSchema}
74
- defaultValues={defaultValues ?? POST_FORM_DEFAULT_VALUES}
75
- onSubmit={onSubmit}
76
- >
77
- <SubmitForm.Row formKey="title" label="제목" required maxLength={200} />
78
- <SubmitForm.Row formKey="content" formType="textarea" label="내용" required maxLength={2000} />
79
- <SubmitForm.Row
80
- formKey="noticeCategory"
81
- formType="radio"
82
- label="카테고리"
83
- options={NOTICE_CATEGORY_OPTIONS}
84
- />
85
- <SubmitForm.Row formKey="visible" formType="switch" label="노출 여부" />
86
- </SubmitForm>
87
- </div>
88
-
89
- <div>
90
- <p className="mb-1.5 text-sm font-medium text-gray-700">첨부파일</p>
91
- {existingFiles && existingFiles.length > 0 && (
92
- <ul className="mb-3 space-y-1.5">
93
- {existingFiles.map((file) => (
94
- <li
95
- key={file.id}
96
- className="flex items-center justify-between rounded-md border border-gray-200 bg-gray-50 px-3 py-2"
97
- >
98
- <span className="flex items-center gap-1.5 truncate text-sm text-gray-700">
99
- <Paperclip size={13} className="shrink-0 text-gray-400" />
100
- {file.fileName}
101
- </span>
102
- <button
103
- type="button"
104
- onClick={() => onDeleteExistingFile?.(file.id)}
105
- className="ml-2 shrink-0 rounded p-0.5 text-gray-400 hover:bg-red-50 hover:text-red-500"
106
- aria-label="파일 삭제"
107
- >
108
- <X size={14} />
109
- </button>
110
- </li>
111
- ))}
112
- </ul>
113
- )}
114
- <FileUploader files={pendingFiles} onChange={onPendingFilesChange} multiple />
115
- </div>
116
- </div>
117
- </ModalBody>
118
- <ModalFooter className="flex justify-end gap-2 border-t border-gray-200 bg-neutral-50 px-5 py-3">
119
- <Button type="submit" form={formId} variant="save" disabled={isPending}>
120
- {isPending ? `${submitLabel} 중...` : submitLabel}
121
- </Button>
122
- <Button variant="outline" onClick={onClose}>
123
- 취소
124
- </Button>
125
- </ModalFooter>
126
- </Modal>
127
- );
128
- }
1
+ import {
2
+ Button,
3
+ FileUploader,
4
+ Modal,
5
+ ModalBody,
6
+ ModalFooter,
7
+ ModalIconHeader,
8
+ SubmitForm,
9
+ } from "@farmzone/fz-react-ui";
10
+ import { Paperclip, X } from "lucide-react";
11
+ import { z } from "zod";
12
+
13
+ import type { FileResponse } from "@/types";
14
+
15
+ export const postFormSchema = z.object({
16
+ title: z.string().min(1, "제목을 입력해 주세요."),
17
+ content: z.string().min(1, "내용을 입력해 주세요."),
18
+ noticeCategory: z.string(),
19
+ visible: z.boolean(),
20
+ });
21
+
22
+ export type PostFormData = z.infer<typeof postFormSchema>;
23
+
24
+ export const POST_FORM_DEFAULT_VALUES: PostFormData = {
25
+ title: "",
26
+ content: "",
27
+ noticeCategory: "NOTICE",
28
+ visible: true,
29
+ };
30
+
31
+ const NOTICE_CATEGORY_OPTIONS = [{ label: "공지", value: "NOTICE" }];
32
+
33
+ interface PostFormModalProps {
34
+ mode: "create" | "edit";
35
+ isOpen: boolean;
36
+ onClose: () => void;
37
+ defaultValues?: PostFormData;
38
+ onSubmit: (data: PostFormData) => Promise<void>;
39
+ isPending: boolean;
40
+ pendingFiles: Array<File>;
41
+ onPendingFilesChange: (files: Array<File>) => void;
42
+ existingFiles?: Array<FileResponse>;
43
+ onDeleteExistingFile?: (id: number) => void;
44
+ formKey?: string | number;
45
+ }
46
+
47
+ export function PostFormModal({
48
+ mode,
49
+ isOpen,
50
+ onClose,
51
+ defaultValues,
52
+ onSubmit,
53
+ isPending,
54
+ pendingFiles,
55
+ onPendingFilesChange,
56
+ existingFiles,
57
+ onDeleteExistingFile,
58
+ formKey,
59
+ }: PostFormModalProps) {
60
+ const formId = mode === "create" ? "post-create-form" : "post-edit-form";
61
+ const title = mode === "create" ? "게시글 등록" : "게시글 수정";
62
+ const submitLabel = mode === "create" ? "등록" : "수정";
63
+
64
+ return (
65
+ <Modal isOpen={isOpen} onClose={onClose} contentClassName="max-w-3xl rounded-xl bg-white">
66
+ <ModalIconHeader type={mode} title={title} onClose={onClose} />
67
+ <ModalBody className="px-6 py-5">
68
+ <div className="space-y-4">
69
+ <div className="overflow-hidden rounded-lg border border-gray-200">
70
+ <SubmitForm
71
+ key={formKey}
72
+ formId={formId}
73
+ schema={postFormSchema}
74
+ defaultValues={defaultValues ?? POST_FORM_DEFAULT_VALUES}
75
+ onSubmit={onSubmit}
76
+ >
77
+ <SubmitForm.Row formKey="title" label="제목" required maxLength={200} />
78
+ <SubmitForm.Row formKey="content" formType="textarea" label="내용" required maxLength={2000} />
79
+ <SubmitForm.Row
80
+ formKey="noticeCategory"
81
+ formType="radio"
82
+ label="카테고리"
83
+ options={NOTICE_CATEGORY_OPTIONS}
84
+ />
85
+ <SubmitForm.Row formKey="visible" formType="switch" label="노출 여부" />
86
+ </SubmitForm>
87
+ </div>
88
+
89
+ <div>
90
+ <p className="mb-1.5 text-sm font-medium text-gray-700">첨부파일</p>
91
+ {existingFiles && existingFiles.length > 0 && (
92
+ <ul className="mb-3 space-y-1.5">
93
+ {existingFiles.map((file) => (
94
+ <li
95
+ key={file.id}
96
+ className="flex items-center justify-between rounded-md border border-gray-200 bg-gray-50 px-3 py-2"
97
+ >
98
+ <span className="flex items-center gap-1.5 truncate text-sm text-gray-700">
99
+ <Paperclip size={13} className="shrink-0 text-gray-400" />
100
+ {file.fileName}
101
+ </span>
102
+ <button
103
+ type="button"
104
+ onClick={() => onDeleteExistingFile?.(file.id)}
105
+ className="ml-2 shrink-0 rounded p-0.5 text-gray-400 hover:bg-red-50 hover:text-red-500"
106
+ aria-label="파일 삭제"
107
+ >
108
+ <X size={14} />
109
+ </button>
110
+ </li>
111
+ ))}
112
+ </ul>
113
+ )}
114
+ <FileUploader files={pendingFiles} onChange={onPendingFilesChange} multiple />
115
+ </div>
116
+ </div>
117
+ </ModalBody>
118
+ <ModalFooter className="flex justify-end gap-2 border-t border-gray-200 bg-neutral-50 px-5 py-3">
119
+ <Button type="submit" form={formId} variant="save" disabled={isPending}>
120
+ {isPending ? `${submitLabel} 중...` : submitLabel}
121
+ </Button>
122
+ <Button variant="outline" onClick={onClose}>
123
+ 취소
124
+ </Button>
125
+ </ModalFooter>
126
+ </Modal>
127
+ );
128
+ }