iipbs_cs #7

Merged
chanii8 merged 5 commits from iipbs_cs into main 2025-03-17 11:13:11 +09:00
6 changed files with 430 additions and 319 deletions
Showing only changes of commit daf9a52aec - Show all commits
+1
View File
@@ -11,6 +11,7 @@
"dependencies": {
"@common/assets": "workspace:*",
"@common/components": "workspace:*",
"@frontend-opensource/use-react-hooks": "^1.1.4",
"@hookform/resolvers": "^4.1.3",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-slot": "^1.1.2",
+12 -5
View File
@@ -25,6 +25,15 @@ export class SiteApiService implements SiteService {
return response.data;
}
public async createSite(data: SiteFormData): Promise<void> {
const validatedData = siteFormSchema.parse(data);
const response = await client.post<void>(
`${ENDPOINT.CMS_SERVICE.SITES}`,
validatedData,
);
return response.data;
}
public async modifySite(siteId: string, data: SiteFormData): Promise<void> {
const validatedData = siteFormSchema.parse(data);
const response = await client.put<void>(
@@ -34,11 +43,9 @@ export class SiteApiService implements SiteService {
return response.data;
}
public async createSite(data: SiteFormData): Promise<void> {
const validatedData = siteFormSchema.parse(data);
const response = await client.post<void>(
`${ENDPOINT.CMS_SERVICE.SITES}`,
validatedData,
public async deleteSite(siteId: string): Promise<void> {
const response = await client.delete<void>(
`${ENDPOINT.CMS_SERVICE.SITES}/${siteId}`,
);
return response.data;
}
+16 -5
View File
@@ -40,11 +40,17 @@ function ModifyPage({ siteId }: { siteId: string }) {
const { mutateAsync: modifySite } = useMutation({
mutationFn: (data: SiteFormData) => SiteApi.modifySite(siteId, data),
onSuccess: () => {
setIsModifySuccess(true);
setMessage("수정되었습니다.");
},
});
const [isModifySuccess, setIsModifySuccess] = useState(false);
const { mutateAsync: deleteSite } = useMutation({
mutationFn: () => SiteApi.deleteSite(siteId),
onSuccess: () => {
setMessage("삭제되었습니다.");
},
});
const [message, setMessage] = useState("");
const form = useForm<SiteFormData>({
resolver: zodResolver(siteFormSchema),
@@ -64,11 +70,16 @@ function ModifyPage({ siteId }: { siteId: string }) {
return (
<SitePageLayout>
<SiteForm form={form} siteId={siteId} handleSave={modifySite} />
<Dialog open={isModifySuccess} onOpenChange={() => router.back()}>
<SiteForm
form={form}
siteId={siteId}
handleSave={modifySite}
handleDelete={deleteSite}
/>
<Dialog open={!!message} onOpenChange={() => router.back()}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">수정되었습니다.</p>
<p className="text-center text-[1.4rem]">{message}</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
+45 -4
View File
@@ -1,8 +1,13 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { type UseFormReturn } from "react-hook-form";
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
Input,
Label,
RadioGroup,
@@ -32,10 +37,12 @@ type SiteFormProps = {
form: UseFormReturn<SiteFormData>;
siteId?: string;
handleSave: (data: SiteFormData) => void;
handleDelete: () => void;
};
function SiteForm({ form, siteId, handleSave }: SiteFormProps) {
function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
const router = useRouter();
const { message, confirm, onConfirm, onCancel } = useConfirm();
const [viewState, setViewState] = useState<Partial<ISiteDetail>>({});
const [representativeDomain, setRepresentativeDomain] = useState<string>("");
@@ -56,7 +63,14 @@ function SiteForm({ form, siteId, handleSave }: SiteFormProps) {
handleSave(data);
};
const onDelete = async () => {
if (await confirm("정말 삭제하시겠습니까?")) {
handleDelete();
}
};
return (
<>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<div className="card card-border !mt-6">
@@ -195,7 +209,9 @@ function SiteForm({ form, siteId, handleSave }: SiteFormProps) {
<div className="h-[3.2rem] w-[21.5rem] cursor-not-allowed rounded-md border border-input bg-form px-3 py-2 text-[1.3rem] opacity-50">
{representativeDomain}
</div>
<DomainManagementDialog handleSave={handleDomainSave} />
<DomainManagementDialog
handleSave={handleDomainSave}
/>
</div>
</TableCell>
</TableRow>
@@ -370,20 +386,45 @@ function SiteForm({ form, siteId, handleSave }: SiteFormProps) {
</div>
</div>
<div className="flex justify-center gap-4 pb-12 pt-10">
<Button size="lg" color="white" onClick={() => router.back()}>
<Button
size="lg"
color="white"
type="button"
onClick={() => router.back()}
>
목록
</Button>
<Button size="lg" type="submit">
저장
</Button>
{isModifyMode && (
<Button size="lg" color="red">
<Button size="lg" color="red" type="button" onClick={onDelete}>
삭제
</Button>
)}
</div>
</form>
</Form>
<Dialog open={!!message} onOpenChange={onCancel}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">{message}</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
<Button color="red" onClick={onConfirm}>
삭제
</Button>
</DialogClose>
<DialogClose asChild>
<Button color="white" onClick={onCancel}>
취소
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}
@@ -1,5 +1,6 @@
"use client";
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
import { BaseLayout } from "@common/components/ui";
import { AuthProvider } from "./auth-provider";
import { CookieProvider } from "./cookie-provider";
@@ -10,7 +11,9 @@ const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
<QueryProvider>
<CookieProvider>
<AuthProvider>
<ConfirmProvider>
<BaseLayout>{children}</BaseLayout>
</ConfirmProvider>
</AuthProvider>
</CookieProvider>
</QueryProvider>
+48
View File
@@ -42,6 +42,9 @@ importers:
'@common/components':
specifier: workspace:*
version: link:../../packages/common/components
'@frontend-opensource/use-react-hooks':
specifier: ^1.1.4
version: 1.1.4
'@hookform/resolvers':
specifier: ^4.1.3
version: 4.1.3(react-hook-form@7.54.2)
@@ -1140,6 +1143,15 @@ packages:
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
dev: false
/@frontend-opensource/use-react-hooks@1.1.4:
resolution: {integrity: sha512-otCSyciL5MVCNNYmdDdg2lEL6rbZ3XX1meYQCzapUSC4V6qx2YxMk1kUbhwEM/+vdxhYzBHsVBGD0rZWl5cgrw==}
dependencies:
async-wave: 1.8.6
fast-deep-equal: 3.1.3
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
dev: false
/@hookform/resolvers@4.1.3(react-hook-form@7.54.2):
resolution: {integrity: sha512-Jsv6UOWYTrEFJ/01ZrnwVXs7KDvP8XIo115i++5PWvNkNvkrsTfGiLS6w+eJ57CYtUtDQalUWovCZDHFJ8u1VQ==}
peerDependencies:
@@ -3703,6 +3715,17 @@ packages:
engines: {node: '>= 0.4'}
dev: true
/async-wave@1.8.6:
resolution: {integrity: sha512-wqWvr0Mrc1TrY92hN9MV0Xebxa6kt+T7QtjZ7FEMv+RUBa/Hfpz/UOgz0rB+7uqVK8TuBSXykOyU/k9gogdLkw==}
dependencies:
is-promise: 4.0.0
lodash.add: 3.7.0
lodash.clonedeep: 4.5.0
lodash.isequal: 4.5.0
lodash.isfunction: 3.0.9
lodash.size: 4.2.0
dev: false
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
@@ -5476,6 +5499,10 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
/is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
dev: false
/is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -5724,10 +5751,31 @@ packages:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: true
/lodash.add@3.7.0:
resolution: {integrity: sha512-/uxUZkB6vYiPoGSXADJJE+Ee4W2vU+bxZOFdvJdx+mDgv+qyAO76sWD84Q4FxsMgTjC1+gVFC9YNhdG243QRDw==}
dev: false
/lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
dev: false
/lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
dev: false
/lodash.isfunction@3.0.9:
resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==}
dev: false
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
/lodash.size@4.2.0:
resolution: {integrity: sha512-wbu3SF1XC5ijqm0piNxw59yCbuUf2kaShumYBLWUrcCvwh6C8odz6SY/wGVzCWTQTFL/1Ygbvqg2eLtspUVVAQ==}
dev: false
/lodash.sortby@4.7.0:
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
dev: true