feat: 모듈 API 등록 페이지 작업

This commit is contained in:
2025-04-16 15:44:59 +09:00
parent 49ce84254f
commit 6fd1154337
12 changed files with 263 additions and 16 deletions
@@ -0,0 +1,2 @@
import { CreatePage } from "@/pages/module";
export default CreatePage;
@@ -113,7 +113,6 @@ function BannerForm({ form, bnrSn, ...props }: BannerFormProps) {
<FormControl>
<CodeSelect
{...field}
value={field.value ?? ""}
upCd="BNRTYPE"
onValueChange={field.onChange}
/>
+1 -2
View File
@@ -128,7 +128,7 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
field.onChange(Number(value));
}}
className="w-[12rem] !text-[1.3rem]"
placeholder="정렬순서를 입력해주세요"
placeholder="정렬순서 입력"
/>
</FormControl>
</FormItem>
@@ -147,7 +147,6 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
<FormControl>
<CodeSelect
{...field}
value={field.value ?? ""}
upCd="IMGTYPE"
onValueChange={field.onChange}
/>
@@ -4,6 +4,8 @@ import type {
AuthorizationsService,
AuthorizationsParams,
AuthorizationsList,
AuthorizationFormData,
WithRoleAuthorizations,
} from "../model/authorizations-interface";
export class AuthorizationsApiService implements AuthorizationsService {
@@ -16,6 +18,16 @@ export class AuthorizationsApiService implements AuthorizationsService {
);
return response.data;
}
public async createAuthorization(
data: AuthorizationFormData,
): Promise<WithRoleAuthorizations> {
const response = await client.post<WithRoleAuthorizations>(
`${ENDPOINT.USER_SERVICE.AUTHORIZATIONS}`,
data,
);
return response.data;
}
}
export const AuthorizationsApi = new AuthorizationsApiService();
+1
View File
@@ -1 +1,2 @@
export { ModulePage } from "./ui/module-page";
export { CreatePage } from "./ui/create-page";
@@ -1,3 +1,4 @@
import { z } from "zod";
import type { PageableList, PageableParams } from "@/shared/model";
export interface AuthorizationsParams extends PageableParams {
@@ -16,10 +17,34 @@ export interface Authorizations {
mdfcnDt: string;
}
export interface WithRoleAuthorizations extends Authorizations {
roleAuthorizations: {
roleId: string;
authorizationNo: number;
authorizationName: string;
urlPatternValue: string;
httpMethodCode: string;
sortSeq: number;
createdAt: string;
}[];
}
export const authorizationFormSchema = z.object({
authorizationName: z.string(),
urlPatternValue: z.string(),
httpMethodCode: z.string(),
sortSeq: z.number(),
useYn: z.string(),
});
export type AuthorizationsList = PageableList<Authorizations>;
export type AuthorizationFormData = z.infer<typeof authorizationFormSchema>;
export interface AuthorizationsService {
getAuthorizationsList(
getAuthorizationsList: (
params: AuthorizationsParams,
): Promise<AuthorizationsList>;
) => Promise<AuthorizationsList>;
createAuthorization: (
data: AuthorizationFormData,
) => Promise<WithRoleAuthorizations>;
}
@@ -10,7 +10,7 @@ export const columns: ColumnDef<Authorizations>[] = [
},
{
accessorKey: "authorizationName",
header: "API 명",
header: "API명",
},
{
accessorKey: "urlPatternValue",
@@ -0,0 +1,45 @@
"use client";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation } from "@tanstack/react-query";
import { useAlertStore } from "@/shared/lib/use-alert-store";
import {
authorizationFormSchema,
type AuthorizationFormData,
} from "../model/authorizations-interface";
import { AuthorizationsApi } from "../api/authorization-service";
import { ModuleForm } from "./module-form";
function CreatePage() {
const router = useRouter();
const { setMessage: alert } = useAlertStore((state) => state);
const { mutateAsync: createAuthorization } = useMutation({
mutationFn: (data: AuthorizationFormData) =>
AuthorizationsApi.createAuthorization(data),
onSuccess: () => {
alert("등록되었습니다.", router.back);
},
});
const form = useForm<AuthorizationFormData>({
resolver: zodResolver(authorizationFormSchema),
defaultValues: {
sortSeq: 0,
useYn: "Y",
},
});
return (
<div className="card card-border !mt-6">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">모듈API 등록</h3>
</div>
<ModuleForm form={form} handleSave={createAuthorization} />
</div>
);
}
export { CreatePage };
+166
View File
@@ -0,0 +1,166 @@
"use client";
import type { UseFormReturn } from "react-hook-form";
import {
Input,
Label,
RadioGroup,
RadioGroupItem,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from "@common/components";
import { FormWrapper } from "@/widgets/form-wrapper";
import { CodeSelect } from "@/entities/code";
import { FormControl, FormField, FormItem } from "@/shared/ui/form";
import type {
AuthorizationFormData,
WithRoleAuthorizations,
} from "../model/authorizations-interface";
type BannerFormProps = {
form: UseFormReturn<AuthorizationFormData>;
authorizationNo?: number;
handleSave: (data: AuthorizationFormData) => Promise<WithRoleAuthorizations>;
handleDelete?: () => Promise<void>;
};
function ModuleForm({ form, authorizationNo, ...props }: BannerFormProps) {
return (
<FormWrapper form={form} isModifyMode={!!authorizationNo} {...props}>
<div className="card">
<Table variant="secondary">
<colgroup>
<col width="15%" />
<col width="85%" />
</colgroup>
<TableBody>
<TableRow>
<TableHead>API명</TableHead>
<TableCell className="border">
<FormField
control={form.control}
name="authorizationName"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
{...field}
value={field.value ?? ""}
className="!text-[1.3rem]"
placeholder="API명을 입력해주세요"
/>
</FormControl>
</FormItem>
)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableHead>API URL</TableHead>
<TableCell className="border">
<FormField
control={form.control}
name="urlPatternValue"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
{...field}
value={field.value ?? ""}
className="!text-[1.3rem]"
placeholder="API URL을 입력해주세요"
/>
</FormControl>
</FormItem>
)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableHead>요청 메소드</TableHead>
<TableCell className="border">
<FormField
control={form.control}
name="httpMethodCode"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormControl>
<CodeSelect
{...field}
upCd="HTTPMHD"
onValueChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableHead>정렬순서</TableHead>
<TableCell className="border">
<FormField
control={form.control}
name="sortSeq"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
{...field}
type="number"
min={0}
value={field.value ?? ""}
onChange={(e) => {
const value = e.target.value;
if (isNaN(Number(value))) return;
field.onChange(Number(value));
}}
className="w-[12rem] !text-[1.3rem]"
placeholder="정렬순서 입력"
/>
</FormControl>
</FormItem>
)}
/>
</TableCell>
</TableRow>
<TableRow>
<TableHead>사용여부</TableHead>
<TableCell className="border">
<FormField
control={form.control}
name="useYn"
render={({ field }) => (
<FormItem>
<FormControl>
<RadioGroup
{...field}
name="useYn"
onValueChange={field.onChange}
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="Y" id="useY" />
<Label htmlFor="useY">사용</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="N" id="useN" />
<Label htmlFor="useN">사용안함</Label>
</div>
</RadioGroup>
</FormControl>
</FormItem>
)}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
</FormWrapper>
);
}
export { ModuleForm };
+5 -7
View File
@@ -9,14 +9,14 @@ import {
type PaginationState,
} from "@tanstack/react-table";
import { Button, DataTable, Input, Label } from "@common/components";
import { CodeSelect } from "@/entities/code";
import { ENDPOINT } from "@/shared/config";
import { AuthorizationsApi } from "../api/authorization-service";
import type {
Authorizations,
AuthorizationsParams,
} from "../model/authorizations-interface";
import { columns } from "../model/table-columns";
import { CodeSelect } from "@/entities/code";
import { AuthorizationsApi } from "../api/authorization-service";
function ModulePage() {
const router = useRouter();
@@ -89,7 +89,7 @@ function ModulePage() {
</div>
<div className="flex items-center gap-2">
<Label htmlFor="keyword" className="text-label">
API 명
API명
</Label>
<Input
id="keyword"
@@ -108,10 +108,8 @@ function ModulePage() {
</div>
<div className="card card-border">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">콘텐츠 목록</h3>
<Button onClick={() => router.push("/contents/register")}>
등록
</Button>
<h3 className="text-2xl font-medium text-label">모듈API 목록</h3>
<Button onClick={() => router.push("/module/register")}>등록</Button>
</div>
<div className="card !m-[1.2rem] h-[49.5rem] overflow-auto !p-0">
<DataTable table={table} onRowClick={handleRowClick} viewPagination />
+1 -1
View File
@@ -110,8 +110,8 @@ function SiteForm({ form, siteId, ...props }: SiteFormProps) {
<FormControl>
<CodeSelect
{...field}
value={field.value ?? ""}
upCd="SITESKINCD"
value={field.value ?? ""}
onValueChange={field.onChange}
/>
</FormControl>
@@ -8,8 +8,8 @@ type FormWrapperProps<T extends FieldValues> = {
form: UseFormReturn<T>;
children: React.ReactNode;
isModifyMode?: boolean;
handleSave: (data: T) => Promise<void>;
handleDelete?: () => Promise<void>;
handleSave: (data: T) => Promise<unknown>;
handleDelete?: () => Promise<unknown>;
};
function FormWrapper<T extends FieldValues>({