@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.
- package/README.md +46 -50
- package/package.json +1 -1
- package/template/.env.example +5 -5
- package/template/package.json +55 -55
- package/template/pnpm-lock.yaml +4214 -4214
- package/template/public/mockServiceWorker.js +349 -349
- package/template/src/app/api/api.ts +178 -178
- package/template/src/app/api/queries.ts +326 -321
- package/template/src/app/api/queryKey.ts +7 -7
- package/template/src/app/api/token.ts +7 -7
- package/template/src/app/layout/Layout.tsx +33 -33
- package/template/src/app/layout/ListContents.tsx +9 -9
- package/template/src/app/layout/ListHeader.tsx +41 -41
- package/template/src/app/layout/MultiTabNav.tsx +101 -101
- package/template/src/app/layout/Sidebar.tsx +33 -33
- package/template/src/app/layout/UserInfo.tsx +94 -94
- package/template/src/app/layout/tabSwitchStore.ts +11 -11
- package/template/src/app/router/Router.tsx +56 -56
- package/template/src/app/store/index.ts +26 -26
- package/template/src/index.tsx +21 -21
- package/template/src/mocks/browser.ts +17 -17
- package/template/src/mocks/handlers.ts +43 -43
- package/template/src/mocks/scenarios.ts +57 -57
- package/template/src/pages/dashboard/index.tsx +541 -541
- package/template/src/pages/error/Error.tsx +29 -29
- package/template/src/pages/error/NotFound.tsx +27 -27
- package/template/src/pages/login/index.tsx +317 -317
- package/template/src/pages/post/PostFormModal.tsx +128 -128
- package/template/src/pages/post/detail/index.tsx +548 -548
- package/template/src/pages/post/index.tsx +266 -267
- package/template/src/pages/sample/SampleFormModal.tsx +115 -77
- package/template/src/pages/sample/detail/index.tsx +400 -424
- package/template/src/pages/sample/index.tsx +278 -269
- package/template/src/pages/sample/modal/index.tsx +300 -253
- package/template/src/pages/system/log/index.tsx +173 -173
- package/template/src/pages/user/config/columns.tsx +102 -109
- package/template/src/pages/user/config/schema.ts +54 -54
- package/template/src/pages/user/index.tsx +641 -641
- package/template/src/shared/components/CommentInput.tsx +243 -243
- package/template/src/shared/config/text.ts +27 -27
- package/template/src/shared/utils/format.ts +11 -11
- package/template/src/types/auth.ts +10 -10
- package/template/src/types/comment.ts +33 -33
- package/template/src/types/common.ts +19 -19
- package/template/src/types/dashboard.ts +53 -53
- package/template/src/types/index.ts +16 -16
- package/template/src/types/log.ts +21 -21
- package/template/src/types/post.ts +32 -32
- package/template/src/types/sample.ts +29 -28
- package/template/src/types/user.ts +51 -51
- package/template/src/vite-env.d.ts +10 -10
|
@@ -1,77 +1,115 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { useFormContext } from "react-hook-form";
|
|
3
|
+
import { Button, Modal, ModalBody, ModalFooter, ModalIconHeader, SubmitForm } from "@farmzone/fz-react-ui";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import { checkSampleNameAvailable } from "@/app/api/queries";
|
|
7
|
+
|
|
8
|
+
export const sampleFormSchema = z.object({
|
|
9
|
+
name: z.string().min(1, "이름을 입력해 주세요."),
|
|
10
|
+
description: z.string().min(1, "설명을 입력해 주세요."),
|
|
11
|
+
category: z.string(),
|
|
12
|
+
priority: z.coerce.number().min(1).max(10),
|
|
13
|
+
active: z.boolean(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type SampleFormData = z.infer<typeof sampleFormSchema>;
|
|
17
|
+
|
|
18
|
+
export const SAMPLE_FORM_DEFAULT_VALUES: SampleFormData = {
|
|
19
|
+
name: "",
|
|
20
|
+
description: "",
|
|
21
|
+
category: "BASIC",
|
|
22
|
+
priority: 1,
|
|
23
|
+
active: true,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const CATEGORY_OPTIONS = [
|
|
27
|
+
{ label: "기본", value: "BASIC" },
|
|
28
|
+
{ label: "고급", value: "ADVANCED" },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const PRIORITY_OPTIONS = Array.from({ length: 10 }, (_, i) => ({
|
|
32
|
+
label: String(i + 1),
|
|
33
|
+
value: String(i + 1),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
function SampleNameChecker({ originalName }: { originalName?: string }) {
|
|
37
|
+
const { watch, setError, clearErrors } = useFormContext();
|
|
38
|
+
const name = watch("name") as string;
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!name || name === originalName) {
|
|
42
|
+
clearErrors("name");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const timer = setTimeout(async () => {
|
|
46
|
+
const available = await checkSampleNameAvailable(name);
|
|
47
|
+
if (available) {
|
|
48
|
+
clearErrors("name");
|
|
49
|
+
} else {
|
|
50
|
+
setError("name", { type: "manual", message: "이미 사용 중인 샘플명입니다." });
|
|
51
|
+
}
|
|
52
|
+
}, 500);
|
|
53
|
+
return () => clearTimeout(timer);
|
|
54
|
+
}, [name, originalName, setError, clearErrors]);
|
|
55
|
+
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface SampleFormModalProps {
|
|
60
|
+
mode: "create" | "edit";
|
|
61
|
+
isOpen: boolean;
|
|
62
|
+
onClose: () => void;
|
|
63
|
+
defaultValues?: SampleFormData;
|
|
64
|
+
onSubmit: (data: SampleFormData) => Promise<void>;
|
|
65
|
+
isPending: boolean;
|
|
66
|
+
formKey?: string | number;
|
|
67
|
+
originalName?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function SampleFormModal({
|
|
71
|
+
mode,
|
|
72
|
+
isOpen,
|
|
73
|
+
onClose,
|
|
74
|
+
defaultValues,
|
|
75
|
+
onSubmit,
|
|
76
|
+
isPending,
|
|
77
|
+
formKey,
|
|
78
|
+
originalName,
|
|
79
|
+
}: SampleFormModalProps) {
|
|
80
|
+
const formId = mode === "create" ? "sample-create-form" : "sample-edit-form";
|
|
81
|
+
const title = mode === "create" ? "샘플 등록" : "샘플 수정";
|
|
82
|
+
const submitLabel = mode === "create" ? "등록" : "수정";
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<Modal isOpen={isOpen} onClose={onClose} contentClassName="max-w-3xl rounded-xl bg-white">
|
|
86
|
+
<ModalIconHeader type={mode} title={title} onClose={onClose} />
|
|
87
|
+
<ModalBody className="px-6 py-5">
|
|
88
|
+
<div className="overflow-hidden rounded-lg border border-gray-200">
|
|
89
|
+
<SubmitForm
|
|
90
|
+
key={formKey}
|
|
91
|
+
formId={formId}
|
|
92
|
+
schema={sampleFormSchema}
|
|
93
|
+
defaultValues={defaultValues ?? SAMPLE_FORM_DEFAULT_VALUES}
|
|
94
|
+
onSubmit={onSubmit}
|
|
95
|
+
>
|
|
96
|
+
<SampleNameChecker originalName={originalName} />
|
|
97
|
+
<SubmitForm.Row formKey="name" label="이름" required maxLength={100} />
|
|
98
|
+
<SubmitForm.Row formKey="description" formType="textarea" label="설명" required maxLength={500} />
|
|
99
|
+
<SubmitForm.Row formKey="category" formType="radio" label="카테고리" options={CATEGORY_OPTIONS} />
|
|
100
|
+
<SubmitForm.Row formKey="priority" formType="select" label="우선순위" options={PRIORITY_OPTIONS} />
|
|
101
|
+
<SubmitForm.Row formKey="active" formType="switch" label="사용 여부" />
|
|
102
|
+
</SubmitForm>
|
|
103
|
+
</div>
|
|
104
|
+
</ModalBody>
|
|
105
|
+
<ModalFooter className="flex justify-end gap-2 border-t border-gray-200 bg-neutral-50 px-5 py-3">
|
|
106
|
+
<Button type="submit" form={formId} variant="save" disabled={isPending}>
|
|
107
|
+
{isPending ? `${submitLabel} 중...` : submitLabel}
|
|
108
|
+
</Button>
|
|
109
|
+
<Button variant="outline" onClick={onClose}>
|
|
110
|
+
취소
|
|
111
|
+
</Button>
|
|
112
|
+
</ModalFooter>
|
|
113
|
+
</Modal>
|
|
114
|
+
);
|
|
115
|
+
}
|