From 235fe79c64e2a35ab79df390c5b825a3e8faa774 Mon Sep 17 00:00:00 2001 From: earthyoung Date: Sun, 5 Apr 2026 23:32:22 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20packages/common=20=ED=95=98?= =?UTF-8?q?=EC=9C=84=EC=9D=98=20apis,=20schemas,=20utils,=20contexts,=20ho?= =?UTF-8?q?oks=20namespace=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../elements/admin_signin_guard.tsx | 6 +- .../src/components/layouts/admin_editor.tsx | 37 +-- .../src/components/layouts/admin_list.tsx | 9 +- .../src/components/pages/account/account.tsx | 9 +- .../src/components/pages/account/manage.tsx | 16 +- .../src/components/pages/account/sign_in.tsx | 12 +- .../src/components/pages/file/upload.tsx | 6 +- .../pages/modification_audit/components.tsx | 41 +-- .../pages/modification_audit/dialogs.tsx | 20 +- .../pages/modification_audit/list.tsx | 9 +- .../pages/modification_audit/pages.tsx | 9 +- .../sub_pages/presentation_preview.tsx | 30 +- .../sub_pages/userext_preview.tsx | 10 +- .../src/components/pages/page/editor.tsx | 18 +- .../components/pages/presentation/editor.tsx | 39 +-- .../src/components/pages/sitemap/list.tsx | 18 +- .../src/components/pages/user/editor.tsx | 9 +- .../src/consts/mdx_components.ts | 22 +- apps/pyconkr-admin/src/main.tsx | 15 +- apps/pyconkr-admin/vite.config.ts | 1 + .../components/dialogs/change_password.tsx | 14 +- .../modification_audit_cancel_confirm.tsx | 9 +- .../components/dialogs/public_file_upload.tsx | 12 +- .../src/components/elements/error_page.tsx | 4 +- .../components/elements/multilang_field.tsx | 6 +- .../elements/public_file_selector.tsx | 11 +- .../src/components/elements/signin_guard.tsx | 6 +- .../src/components/layout.tsx | 10 +- .../src/components/pages/home.tsx | 13 +- .../pages/modification_audit_preview.tsx | 6 +- .../src/components/pages/profile_editor.tsx | 11 +- .../src/components/pages/session_editor.tsx | 16 +- .../src/components/pages/signin.tsx | 19 +- apps/pyconkr-participant-portal/src/main.tsx | 13 +- .../vite.config.mts | 1 + apps/pyconkr/src/App.tsx | 13 +- .../layout/Footer/Mobile/MobileFooter.tsx | 4 +- .../src/components/layout/Footer/index.tsx | 4 +- .../layout/Header/Mobile/MobileHeader.tsx | 4 +- .../layout/Header/Mobile/MobileNavigation.tsx | 6 +- .../src/components/layout/Header/index.tsx | 4 +- .../src/components/pages/dynamic_route.tsx | 27 +- .../components/pages/presentation_detail.tsx | 23 +- .../src/components/pages/sponsor_detail.tsx | 10 +- apps/pyconkr/src/consts/mdx_components.ts | 22 +- .../pyconkr/src/debug/page/component_test.tsx | 10 +- apps/pyconkr/src/debug/page/map_test.tsx | 17 +- apps/pyconkr/src/debug/page/mdi_test.tsx | 6 +- apps/pyconkr/src/main.tsx | 15 +- apps/pyconkr/vite.config.mts | 1 + packages/common/src/apis/admin_api.ts | 184 ++++++------ packages/common/src/apis/client.ts | 2 +- packages/common/src/apis/index.ts | 26 +- .../common/src/apis/participant_portal_api.ts | 154 +++++----- packages/common/src/apis/session.ts | 18 +- .../common/src/components/common_context.tsx | 6 +- .../common/src/components/error_handler.tsx | 2 +- packages/common/src/components/mdx.tsx | 2 +- .../mdx_components/session_list.tsx | 4 +- .../mdx_components/session_timetable.tsx | 4 +- packages/common/src/components/mdx_editor.tsx | 2 +- packages/common/src/contexts/index.ts | 42 ++- packages/common/src/hooks/index.ts | 24 +- packages/common/src/hooks/useAPI.ts | 90 +++--- packages/common/src/hooks/useAdminAPI.ts | 258 ++++++++-------- packages/common/src/hooks/useCommonContext.ts | 8 +- .../src/hooks/useParticipantPortalAPI.ts | 208 +++++++------ packages/common/src/index.ts | 14 +- packages/common/src/schemas/backendAPI.ts | 190 ++++++------ .../common/src/schemas/backendAdminAPI.ts | 260 ++++++++-------- .../schemas/backendParticipantPortalAPI.ts | 278 +++++++++--------- .../common/src/schemas/backendSessionAPI.ts | 56 ++-- packages/common/src/schemas/index.ts | 12 +- packages/common/src/utils/index.ts | 31 +- 74 files changed, 1243 insertions(+), 1285 deletions(-) diff --git a/apps/pyconkr-admin/src/components/elements/admin_signin_guard.tsx b/apps/pyconkr-admin/src/components/elements/admin_signin_guard.tsx index 9bad3a7..52e73e8 100644 --- a/apps/pyconkr-admin/src/components/elements/admin_signin_guard.tsx +++ b/apps/pyconkr-admin/src/components/elements/admin_signin_guard.tsx @@ -1,4 +1,4 @@ -import * as Common from "@frontend/common"; +import { useBackendAdminClient, useSignedInUserQuery } from "@frontend/common/src/hooks/useAdminAPI"; import { CircularProgress } from "@mui/material"; import { ErrorBoundary, Suspense } from "@suspensive/react"; import * as React from "react"; @@ -9,8 +9,8 @@ import { addSnackbar } from "../../utils/snackbar"; export const BackendAdminSignInGuard: React.FC<{ children: React.ReactNode }> = ErrorBoundary.with( { fallback: <>로그인 정보를 불러오는 중 문제가 발생했습니다. }, Suspense.with({ fallback: }, ({ children }) => { - const backendAdminAPIClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const { data } = Common.Hooks.BackendAdminAPI.useSignedInUserQuery(backendAdminAPIClient); + const backendAdminAPIClient = useBackendAdminClient(); + const { data } = useSignedInUserQuery(backendAdminAPIClient); if (!data) { addSnackbar("로그인 후 이용해주세요.", "error"); diff --git a/apps/pyconkr-admin/src/components/layouts/admin_editor.tsx b/apps/pyconkr-admin/src/components/layouts/admin_editor.tsx index bd9e981..c7d256a 100644 --- a/apps/pyconkr-admin/src/components/layouts/admin_editor.tsx +++ b/apps/pyconkr-admin/src/components/layouts/admin_editor.tsx @@ -1,4 +1,7 @@ -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; +import { useBackendAdminClient, useCreateMutation, useRemoveMutation, useSchemaQuery, useUpdateMutation } from "@frontend/common/src/hooks/useAdminAPI"; +import { filterPropertiesByLanguageInJsonSchema, filterReadOnlyPropertiesInJsonSchema, filterWritablePropertiesInJsonSchema } from "@frontend/common/src/utils"; +import { retrieve } from "@frontend/common/src/apis/admin_api"; import { Add, Close, Delete, Edit } from "@mui/icons-material"; import { Box, @@ -132,7 +135,7 @@ const fieldPropsToSelectedProps = (props: FieldProps): OutlinedSelectProps & { d }; const M2MSelect: Field = ErrorBoundary.with( - { fallback: Common.Components.ErrorFallback }, + { fallback: Components.ErrorFallback }, Suspense.with({ fallback: }, (props) => { const selectable = (props.schema.items as JSONSchema7).oneOf as DescriptedEnum[]; const selectableListObj: DescriptedEnumObject = selectable.reduce((a, i) => ({ ...a, [i.const]: i }), {} as DescriptedEnumObject); @@ -168,7 +171,7 @@ const MDRendererContainer = styled(Box)(({ theme }) => ({ })); const MDEditorField: Field = ErrorBoundary.with( - { fallback: Common.Components.ErrorFallback }, + { fallback: Components.ErrorFallback }, ({ disabled, formData, name, onChange: rawOnChange }) => { const [valueState, setValueState] = React.useState(formData?.toString() || ""); const onChange = (value?: string) => { @@ -180,10 +183,10 @@ const MDEditorField: Field = ErrorBoundary.with( - + - + @@ -234,7 +237,7 @@ const ReadOnlyValueField: React.FC<{ )} {fieldState.blob.type.startsWith("application/json") && fieldState.blobText && ( - + )} 링크 @@ -251,7 +254,7 @@ type InnerAdminEditorStateType = { }; const InnerAdminEditor: React.FC = ErrorBoundary.with( - { fallback: Common.Components.ErrorFallback }, + { fallback: Components.ErrorFallback }, Suspense.with( { fallback: }, ({ @@ -275,8 +278,8 @@ const InnerAdminEditor: React.FC = Err tab: 0, formData: undefined, }); - const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const { data: schemaInfo } = Common.Hooks.BackendAdminAPI.useSchemaQuery(backendAdminClient, app, resource); + const backendAdminClient = useBackendAdminClient(); + const { data: schemaInfo } = useSchemaQuery(backendAdminClient, app, resource); const setTab = (_: React.SyntheticEvent, tab: number) => setEditorState((ps) => ({ ...ps, tab })); const setFormData = (formData?: Record) => setEditorState((ps) => ({ ...ps, formData })); @@ -284,9 +287,9 @@ const InnerAdminEditor: React.FC = Err const selectedLanguage = editorState.tab === 0 ? "ko" : "en"; const notSelectedLanguage = editorState.tab === 0 ? "en" : "ko"; - const createMutation = Common.Hooks.BackendAdminAPI.useCreateMutation>(backendAdminClient, app, resource); - const modifyMutation = Common.Hooks.BackendAdminAPI.useUpdateMutation>(backendAdminClient, app, resource, id || ""); - const deleteMutation = Common.Hooks.BackendAdminAPI.useRemoveMutation(backendAdminClient, app, resource, id || "undefined"); + const createMutation = useCreateMutation>(backendAdminClient, app, resource); + const modifyMutation = useUpdateMutation>(backendAdminClient, app, resource, id || ""); + const deleteMutation = useRemoveMutation(backendAdminClient, app, resource, id || "undefined"); const submitMutation = id ? modifyMutation : createMutation; React.useEffect(() => { @@ -296,7 +299,7 @@ const InnerAdminEditor: React.FC = Err return; } - const initialData = await Common.BackendAdminAPIs.retrieve>(backendAdminClient, app, resource, id)(); + const initialData = await retrieve>(backendAdminClient, app, resource, id)(); setFormData({ ...initialData, ...context }); })(); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -344,13 +347,13 @@ const InnerAdminEditor: React.FC = Err .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {} as RJSFSchema); } - const writableSchema = Common.Utils.filterPropertiesByLanguageInJsonSchema( - Common.Utils.filterWritablePropertiesInJsonSchema(schemaInfo.schema), + const writableSchema = filterPropertiesByLanguageInJsonSchema( + filterWritablePropertiesInJsonSchema(schemaInfo.schema), schemaInfo.translation_fields, selectedLanguage ); - const readOnlySchema = Common.Utils.filterPropertiesByLanguageInJsonSchema( - Common.Utils.filterReadOnlyPropertiesInJsonSchema(schemaInfo.schema), + const readOnlySchema = filterPropertiesByLanguageInJsonSchema( + filterReadOnlyPropertiesInJsonSchema(schemaInfo.schema), schemaInfo.translation_fields, selectedLanguage ); diff --git a/apps/pyconkr-admin/src/components/layouts/admin_list.tsx b/apps/pyconkr-admin/src/components/layouts/admin_list.tsx index 64ba59a..c06ead9 100644 --- a/apps/pyconkr-admin/src/components/layouts/admin_list.tsx +++ b/apps/pyconkr-admin/src/components/layouts/admin_list.tsx @@ -1,4 +1,5 @@ -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; +import { useBackendAdminClient, useListQuery } from "@frontend/common/src/hooks/useAdminAPI"; import { Add } from "@mui/icons-material"; import { Box, Button, CircularProgress, Stack, Table, TableBody, TableCell, TableHead, TableRow, Typography } from "@mui/material"; import { ErrorBoundary, Suspense } from "@suspensive/react"; @@ -23,11 +24,11 @@ type ListRowType = { }; const InnerAdminList: React.FC = ErrorBoundary.with( - { fallback: Common.Components.ErrorFallback }, + { fallback: Components.ErrorFallback }, Suspense.with({ fallback: }, ({ app, resource, hideCreatedAt, hideUpdatedAt, hideCreateNew }) => { const navigate = useNavigate(); - const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const listQuery = Common.Hooks.BackendAdminAPI.useListQuery(backendAdminClient, app, resource); + const backendAdminClient = useBackendAdminClient(); + const listQuery = useListQuery(backendAdminClient, app, resource); return ( diff --git a/apps/pyconkr-admin/src/components/pages/account/account.tsx b/apps/pyconkr-admin/src/components/pages/account/account.tsx index 8b48725..7249f46 100644 --- a/apps/pyconkr-admin/src/components/pages/account/account.tsx +++ b/apps/pyconkr-admin/src/components/pages/account/account.tsx @@ -1,14 +1,15 @@ -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; +import { useBackendAdminClient, useSignedInUserQuery } from "@frontend/common/src/hooks/useAdminAPI"; import { CircularProgress } from "@mui/material"; import { ErrorBoundary, Suspense } from "@suspensive/react"; import * as React from "react"; import { Navigate } from "react-router-dom"; export const AccountRedirectPage: React.FC = ErrorBoundary.with( - { fallback: Common.Components.ErrorFallback }, + { fallback: Components.ErrorFallback }, Suspense.with({ fallback: }, () => { - const backendAdminAPIClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const { data } = Common.Hooks.BackendAdminAPI.useSignedInUserQuery(backendAdminAPIClient); + const backendAdminAPIClient = useBackendAdminClient(); + const { data } = useSignedInUserQuery(backendAdminAPIClient); return data ? : ; }) diff --git a/apps/pyconkr-admin/src/components/pages/account/manage.tsx b/apps/pyconkr-admin/src/components/pages/account/manage.tsx index 45c5b90..48328f6 100644 --- a/apps/pyconkr-admin/src/components/pages/account/manage.tsx +++ b/apps/pyconkr-admin/src/components/pages/account/manage.tsx @@ -1,4 +1,6 @@ -import * as Common from "@frontend/common"; +import { useBackendAdminClient, useChangePasswordMutation, useSignOutMutation } from "@frontend/common/src/hooks/useAdminAPI"; +import { getFormValue, isFormValid } from "@frontend/common/src/utils"; +import { me } from "@frontend/common/src/apis/admin_api"; import { Logout } from "@mui/icons-material"; import { Button, Stack, Tab, Tabs, TextField, Typography } from "@mui/material"; import * as React from "react"; @@ -16,9 +18,9 @@ export const AccountManagementPage: React.FC = () => { const changePasswordFormRef = React.useRef(null); const [pageState, setPageState] = React.useState<{ tab: number }>({ tab: 0 }); const navigate = useNavigate(); - const backendAdminAPIClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const signOutMutation = Common.Hooks.BackendAdminAPI.useSignOutMutation(backendAdminAPIClient); - const changePasswordMutation = Common.Hooks.BackendAdminAPI.useChangePasswordMutation(backendAdminAPIClient); + const backendAdminAPIClient = useBackendAdminClient(); + const signOutMutation = useSignOutMutation(backendAdminAPIClient); + const changePasswordMutation = useChangePasswordMutation(backendAdminAPIClient); const setTab = (_: React.SyntheticEvent, tab: number) => setPageState((ps) => ({ ...ps, tab })); @@ -37,12 +39,12 @@ export const AccountManagementPage: React.FC = () => { event.stopPropagation(); const form = changePasswordFormRef.current; - if (!Common.Utils.isFormValid(form)) { + if (!isFormValid(form)) { addSnackbar("폼에 오류가 있습니다. 다시 확인해주세요.", "error"); return; } - const formData = Common.Utils.getFormValue({ form }); + const formData = getFormValue({ form }); if (formData.new_password !== formData.new_password_confirm) { addSnackbar("새 비밀번호와 확인 비밀번호가 일치하지 않습니다.", "error"); return; @@ -59,7 +61,7 @@ export const AccountManagementPage: React.FC = () => { React.useEffect(() => { (async () => { - const userInfo = await Common.BackendAdminAPIs.me(backendAdminAPIClient)(); + const userInfo = await me(backendAdminAPIClient)(); if (!userInfo) { addSnackbar("로그아웃 상태입니다!", "error"); navigate("/"); diff --git a/apps/pyconkr-admin/src/components/pages/account/sign_in.tsx b/apps/pyconkr-admin/src/components/pages/account/sign_in.tsx index 8cd3424..82e4d1c 100644 --- a/apps/pyconkr-admin/src/components/pages/account/sign_in.tsx +++ b/apps/pyconkr-admin/src/components/pages/account/sign_in.tsx @@ -1,4 +1,6 @@ -import * as Common from "@frontend/common"; +import { useBackendAdminClient, useSignInMutation } from "@frontend/common/src/hooks/useAdminAPI"; +import { getFormValue } from "@frontend/common/src/utils"; +import { me } from "@frontend/common/src/apis/admin_api"; import { Login } from "@mui/icons-material"; import { Button, Stack, TextField, Typography } from "@mui/material"; import * as React from "react"; @@ -16,14 +18,14 @@ export const SignInPage: React.FC = () => { const [pageState, setPageState] = React.useState({ userJustSignedIn: false }); const setUserJustSignedIn = () => setPageState((ps) => ({ ...ps, userJustSignedIn: true })); - const backendAdminAPIClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const signInMutation = Common.Hooks.BackendAdminAPI.useSignInMutation(backendAdminAPIClient); + const backendAdminAPIClient = useBackendAdminClient(); + const signInMutation = useSignInMutation(backendAdminAPIClient); const handleSignIn = (event: React.FormEvent) => { event.preventDefault(); if (!formRef.current) return; - const formData = Common.Utils.getFormValue<{ + const formData = getFormValue<{ identity: string; password: string; }>({ form: formRef.current }); @@ -41,7 +43,7 @@ export const SignInPage: React.FC = () => { (async () => { if (pageState.userJustSignedIn) return; - const userInfo = await Common.BackendAdminAPIs.me(backendAdminAPIClient)(); + const userInfo = await me(backendAdminAPIClient)(); if (userInfo) { addSnackbar(`이미 ${userInfo.username}님으로 로그인되어 있습니다!`, "success"); navigate("/"); diff --git a/apps/pyconkr-admin/src/components/pages/file/upload.tsx b/apps/pyconkr-admin/src/components/pages/file/upload.tsx index 7fdd5ed..251a60d 100644 --- a/apps/pyconkr-admin/src/components/pages/file/upload.tsx +++ b/apps/pyconkr-admin/src/components/pages/file/upload.tsx @@ -1,4 +1,4 @@ -import * as Common from "@frontend/common"; +import { useBackendAdminClient, useUploadPublicFileMutation } from "@frontend/common/src/hooks/useAdminAPI"; import { CloudUpload, PermMedia } from "@mui/icons-material"; import { Box, Button, Input, Stack, Typography } from "@mui/material"; import * as React from "react"; @@ -25,8 +25,8 @@ const InnerPublicFileUploadPage: React.FC = () => { }); const fileInputRef = React.useRef(null); const fileDragBoxRef = React.useRef(null); - const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const uploadPublicFileMutation = Common.Hooks.BackendAdminAPI.useUploadPublicFileMutation(backendAdminClient); + const backendAdminClient = useBackendAdminClient(); + const uploadPublicFileMutation = useUploadPublicFileMutation(backendAdminClient); const forceRerender = React.useCallback( () => diff --git a/apps/pyconkr-admin/src/components/pages/modification_audit/components.tsx b/apps/pyconkr-admin/src/components/pages/modification_audit/components.tsx index 816bb7b..5d69658 100644 --- a/apps/pyconkr-admin/src/components/pages/modification_audit/components.tsx +++ b/apps/pyconkr-admin/src/components/pages/modification_audit/components.tsx @@ -1,4 +1,5 @@ -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; +import { useBackendAdminClient, usePublicFileQuery } from "@frontend/common/src/hooks/useAdminAPI"; import { Accordion, AccordionDetails, @@ -78,30 +79,30 @@ export const PreviewTextField: React.FC = ({ originalDataset, export const PreviewMarkdownField: React.FC = ({ originalDataset, previewDataset, name, label }) => { return originalDataset[name] === previewDataset[name] ? ( - + - + - + ) : ( - + - + - + 기존 값을 보려면 여기를 클릭해주세요. - + - + - + @@ -114,21 +115,21 @@ const ImageFallback: React.FC = () => ( ); -const WidthSpecifiedFallbackImage = styled(Common.Components.FallbackImage)({ +const WidthSpecifiedFallbackImage = styled(Components.FallbackImage)({ maxWidth: "20rem", objectFit: "cover", }); export const PreviewImageField: React.FC = ({ originalDataset, previewDataset, name, label }) => { - const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); + const backendAdminClient = useBackendAdminClient(); const oldImgId = (originalDataset[name] as string) || ""; const newImgId = (previewDataset[name] as string) || ""; - const { data: originalImage } = Common.Hooks.BackendAdminAPI.usePublicFileQuery(backendAdminClient, oldImgId); - const { data: previewImage } = Common.Hooks.BackendAdminAPI.usePublicFileQuery(backendAdminClient, newImgId); + const { data: originalImage } = usePublicFileQuery(backendAdminClient, oldImgId); + const { data: previewImage } = usePublicFileQuery(backendAdminClient, newImgId); return originalImage?.id === previewImage?.id ? ( - + {previewImage?.file ? ( } /> @@ -136,13 +137,13 @@ export const PreviewImageField: React.FC = ({ originalD )} - + ) : ( - + {previewImage?.file ? ( } /> @@ -150,12 +151,12 @@ export const PreviewImageField: React.FC = ({ originalD )} - + 기존 이미지를 보려면 여기를 클릭해주세요. - + {originalImage?.file ? ( } /> @@ -163,7 +164,7 @@ export const PreviewImageField: React.FC = ({ originalD )} - + diff --git a/apps/pyconkr-admin/src/components/pages/modification_audit/dialogs.tsx b/apps/pyconkr-admin/src/components/pages/modification_audit/dialogs.tsx index 8251452..10da0cc 100644 --- a/apps/pyconkr-admin/src/components/pages/modification_audit/dialogs.tsx +++ b/apps/pyconkr-admin/src/components/pages/modification_audit/dialogs.tsx @@ -1,4 +1,6 @@ -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; +import { useApproveModificationAuditMutation, useBackendAdminClient, useRejectModificationAuditMutation } from "@frontend/common/src/hooks/useAdminAPI"; +import { BackendAPIClientError } from "@frontend/common/src/apis"; import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField, Typography } from "@mui/material"; import { enqueueSnackbar, OptionsObject } from "notistack"; import * as React from "react"; @@ -10,8 +12,8 @@ type SubmitConfirmDialogProps = { }; export const ApproveSubmitConfirmDialog: React.FC = ({ open, onClose, modificationAuditId }) => { - const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const approveModificationAuditMutation = Common.Hooks.BackendAdminAPI.useApproveModificationAuditMutation(backendAdminClient, modificationAuditId); + const backendAdminClient = useBackendAdminClient(); + const approveModificationAuditMutation = useApproveModificationAuditMutation(backendAdminClient, modificationAuditId); const addSnackbar = (c: string | React.ReactNode, variant: OptionsObject["variant"]) => enqueueSnackbar(c, { variant, anchorOrigin: { vertical: "bottom", horizontal: "center" } }); @@ -25,7 +27,7 @@ export const ApproveSubmitConfirmDialog: React.FC = ({ onError: (error) => { console.error("Approve modification audit failed:", error); let errorMessage = error instanceof Error ? error.message : "An unknown error occurred."; - if (error instanceof Common.BackendAPIs.BackendAPIClientError) errorMessage = error.message; + if (error instanceof BackendAPIClientError) errorMessage = error.message; addSnackbar(errorMessage, "error"); }, }); @@ -51,8 +53,8 @@ export const ApproveSubmitConfirmDialog: React.FC = ({ export const RejectSubmitConfirmDialog: React.FC = ({ open, onClose, modificationAuditId }) => { const inputRef = React.useRef(null); - const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const rejectModificationAuditMutation = Common.Hooks.BackendAdminAPI.useRejectModificationAuditMutation(backendAdminClient, modificationAuditId); + const backendAdminClient = useBackendAdminClient(); + const rejectModificationAuditMutation = useRejectModificationAuditMutation(backendAdminClient, modificationAuditId); const addSnackbar = (c: string | React.ReactNode, variant: OptionsObject["variant"]) => enqueueSnackbar(c, { variant, anchorOrigin: { vertical: "bottom", horizontal: "center" } }); @@ -68,7 +70,7 @@ export const RejectSubmitConfirmDialog: React.FC = ({ onError: (error) => { console.error("Reject modification audit failed:", error); let errorMessage = error instanceof Error ? error.message : "An unknown error occurred."; - if (error instanceof Common.BackendAPIs.BackendAPIClientError) errorMessage = error.message; + if (error instanceof BackendAPIClientError) errorMessage = error.message; addSnackbar(errorMessage, "error"); }, }); @@ -83,9 +85,9 @@ export const RejectSubmitConfirmDialog: React.FC = ({
반려 후에는 다시 승인할 수 없습니다!
- + - + - + @@ -81,17 +83,17 @@ type AdminCMSPageEditorStateType = { }; export const AdminCMSPageEditor: React.FC = ErrorBoundary.with( - { fallback: Common.Components.ErrorFallback }, + { fallback: Components.ErrorFallback }, Suspense.with({ fallback: }, () => { const { id } = useParams<{ id?: string }>(); - const { frontendDomain } = Common.Hooks.Common.useCommonContext(); - const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); - const { data: initialSections } = Common.Hooks.BackendAdminAPI.useListPageSectionsQuery(backendAdminClient, id || ""); + const { frontendDomain } = useCommonContext(); + const backendAdminClient = useBackendAdminClient(); + const { data: initialSections } = useListPageSectionsQuery(backendAdminClient, id || ""); const [editorState, setEditorState] = React.useState({ sections: initialSections, tab: 0, }); - const bulkUpdateSectionsMutation = Common.Hooks.BackendAdminAPI.useBulkUpdatePageSectionsMutation(backendAdminClient, id || ""); + const bulkUpdateSectionsMutation = useBulkUpdatePageSectionsMutation(backendAdminClient, id || ""); const setTab = (_: React.SyntheticEvent, selectedTab: number) => setEditorState((ps) => ({ ...ps, tab: selectedTab })); diff --git a/apps/pyconkr-admin/src/components/pages/presentation/editor.tsx b/apps/pyconkr-admin/src/components/pages/presentation/editor.tsx index 8af3f85..16daa62 100644 --- a/apps/pyconkr-admin/src/components/pages/presentation/editor.tsx +++ b/apps/pyconkr-admin/src/components/pages/presentation/editor.tsx @@ -1,4 +1,5 @@ -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; +import { useBackendAdminClient, useCreateMutation, useListQuery, useRemovePreparedMutation, useSchemaQuery, useUpdatePreparedMutation } from "@frontend/common/src/hooks/useAdminAPI"; import { Autocomplete, Box, Button, Card, CardContent, CircularProgress, Stack, styled, Tab, Tabs, TextField, Typography } from "@mui/material"; import { DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon"; @@ -143,10 +144,10 @@ const PresentationSpeakerForm: React.FC = ({ di - + - + @@ -263,29 +264,29 @@ type PresentationEditorStateType = { }; export const AdminPresentationEditor: React.FC = ErrorBoundary.with( - { fallback: Common.Components.ErrorFallback }, + { fallback: Components.ErrorFallback }, Suspense.with({ fallback: }, () => { const { id } = useParams<{ id?: string }>(); const addSnackbar = (c: string | React.ReactNode, variant: OptionsObject["variant"]) => enqueueSnackbar(c, { variant, anchorOrigin: { vertical: "bottom", horizontal: "center" } }); - const backendAdminAPIClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient(); + const backendAdminAPIClient = useBackendAdminClient(); const speakerQueryParams = [backendAdminAPIClient, "event", "presentationspeaker"] as const; const presentation = id || DUMMY_UUID; - const speakerCreateMutation = Common.Hooks.BackendAdminAPI.useCreateMutation(...speakerQueryParams); - const speakerUpdateMutation = Common.Hooks.BackendAdminAPI.useUpdatePreparedMutation(...speakerQueryParams); - const speakerDeleteMutation = Common.Hooks.BackendAdminAPI.useRemovePreparedMutation(...speakerQueryParams); - const { data: speakerJsonSchema } = Common.Hooks.BackendAdminAPI.useSchemaQuery(...speakerQueryParams); - const { data: speakerInitialData } = Common.Hooks.BackendAdminAPI.useListQuery(...speakerQueryParams, { presentation }); + const speakerCreateMutation = useCreateMutation(...speakerQueryParams); + const speakerUpdateMutation = useUpdatePreparedMutation(...speakerQueryParams); + const speakerDeleteMutation = useRemovePreparedMutation(...speakerQueryParams); + const { data: speakerJsonSchema } = useSchemaQuery(...speakerQueryParams); + const { data: speakerInitialData } = useListQuery(...speakerQueryParams, { presentation }); const speakers = speakerInitialData.map((s) => ({ ...s, trackId: s.id || Math.random().toString(36).substring(2, 15) })); const scheduleQueryParams = [backendAdminAPIClient, "event", "roomschedule"] as const; - const scheduleCreateMutation = Common.Hooks.BackendAdminAPI.useCreateMutation(...scheduleQueryParams); - const scheduleUpdateMutation = Common.Hooks.BackendAdminAPI.useUpdatePreparedMutation(...scheduleQueryParams); - const scheduleDeleteMutation = Common.Hooks.BackendAdminAPI.useRemovePreparedMutation(...scheduleQueryParams); - const { data: scheduleJsonSchema } = Common.Hooks.BackendAdminAPI.useSchemaQuery(...scheduleQueryParams); - const { data: scheduleInitialData } = Common.Hooks.BackendAdminAPI.useListQuery(...scheduleQueryParams, { presentation }); + const scheduleCreateMutation = useCreateMutation(...scheduleQueryParams); + const scheduleUpdateMutation = useUpdatePreparedMutation(...scheduleQueryParams); + const scheduleDeleteMutation = useRemovePreparedMutation(...scheduleQueryParams); + const { data: scheduleJsonSchema } = useSchemaQuery(...scheduleQueryParams); + const { data: scheduleInitialData } = useListQuery(...scheduleQueryParams, { presentation }); const schedules = scheduleInitialData.map((s) => ({ ...s, trackId: s.id || Math.random().toString(36).substring(2, 15) })); const createEmptySpeaker = (): OnMemoeryPresentationSpeaker => ({ @@ -359,7 +360,7 @@ export const AdminPresentationEditor: React.FC = ErrorBoundary.with( {id ? ( - + 스케줄 정보 {editorState.schedules.map((s) => ( @@ -373,8 +374,8 @@ export const AdminPresentationEditor: React.FC = ErrorBoundary.with( ))} - + ); diff --git a/apps/pyconkr/src/debug/page/mdi_test.tsx b/apps/pyconkr/src/debug/page/mdi_test.tsx index f68d833..4c55d52 100644 --- a/apps/pyconkr/src/debug/page/mdi_test.tsx +++ b/apps/pyconkr/src/debug/page/mdi_test.tsx @@ -1,4 +1,4 @@ -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; import { Box, Stack } from "@mui/material"; import React from "react"; @@ -25,10 +25,10 @@ export const MdiTestPage: React.FC = () => { }} > - + - + ); diff --git a/apps/pyconkr/src/main.tsx b/apps/pyconkr/src/main.tsx index 705368a..475971f 100644 --- a/apps/pyconkr/src/main.tsx +++ b/apps/pyconkr/src/main.tsx @@ -1,5 +1,6 @@ import { Global } from "@emotion/react"; -import * as Common from "@frontend/common"; +import { Components } from "@frontend/common"; +import type { ContextOptions } from "@frontend/common/src/contexts"; import * as Shop from "@frontend/shop"; import { CircularProgress, CssBaseline, ThemeProvider } from "@mui/material"; import { ErrorBoundary, Suspense } from "@suspensive/react"; @@ -42,7 +43,7 @@ const queryClient = new QueryClient({ }), }); -const CommonOptions: Common.Contexts.ContextOptions = { +const CommonOptions: ContextOptions = { language: "ko", debug: IS_DEBUG_ENV, baseUrl: ".", @@ -60,9 +61,9 @@ const ShopOptions: Shop.Contexts.ContextOptions = { }; const SuspenseFallback = ( - + - + ); const MainApp: React.FC = () => { @@ -83,9 +84,9 @@ const MainApp: React.FC = () => { - + - + @@ -95,7 +96,7 @@ const MainApp: React.FC = () => { - + diff --git a/apps/pyconkr/vite.config.mts b/apps/pyconkr/vite.config.mts index 9765567..857fbbd 100644 --- a/apps/pyconkr/vite.config.mts +++ b/apps/pyconkr/vite.config.mts @@ -13,6 +13,7 @@ export default defineConfig({ plugins: [react(), mdx(), mkcert({ hosts: ["local.dev.pycon.kr"] }), svgr()], resolve: { alias: { + "@frontend/common/src": path.resolve(__dirname, "../../packages/common/src"), "@frontend/common": path.resolve(__dirname, "../../packages/common/src/index.ts"), "@frontend/shop": path.resolve(__dirname, "../../packages/shop/src/index.ts"), "@apps/pyconkr": path.resolve(__dirname, "./src"), diff --git a/packages/common/src/apis/admin_api.ts b/packages/common/src/apis/admin_api.ts index b0c94d4..45251d8 100644 --- a/packages/common/src/apis/admin_api.ts +++ b/packages/common/src/apis/admin_api.ts @@ -1,99 +1,95 @@ import { BackendAPIClient } from "./client"; -import BackendAdminAPISchemas from "../schemas/backendAdminAPI"; - -namespace BackendAdminAPIs { - export const me = (client: BackendAPIClient) => async () => { - try { - return await client.get("v1/admin-api/user/userext/me/"); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (_) { - return null; - } +import * as BackendAdminAPISchemas from "../schemas/backendAdminAPI"; + +export const me = (client: BackendAPIClient) => async () => { + try { + return await client.get("v1/admin-api/user/userext/me/"); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_) { + return null; + } +}; + +export const signIn = (client: BackendAPIClient) => (data: BackendAdminAPISchemas.UserSignInSchema) => + client.post("v1/admin-api/user/userext/signin/", data); + +export const signOut = (client: BackendAPIClient) => () => client.delete("v1/admin-api/user/userext/signout/"); + +export const changePassword = (client: BackendAPIClient) => (data: BackendAdminAPISchemas.UserChangePasswordSchema) => + client.post("v1/admin-api/user/userext/password/", data); + +export const resetUserPassword = (client: BackendAPIClient, id: string) => () => + client.delete(`v1/admin-api/user/userext/${id}/password/`); + +export const list = + (client: BackendAPIClient, app: string, resource: string, params?: Record) => + () => + client.get(`v1/admin-api/${app}/${resource}/`, { params }); + +export const retrieve = + (client: BackendAPIClient, app: string, resource: string, id: string) => + () => { + if (!id) return Promise.resolve(null); + return client.get(`v1/admin-api/${app}/${resource}/${id}/`); }; - export const signIn = (client: BackendAPIClient) => (data: BackendAdminAPISchemas.UserSignInSchema) => - client.post("v1/admin-api/user/userext/signin/", data); - - export const signOut = (client: BackendAPIClient) => () => client.delete("v1/admin-api/user/userext/signout/"); - - export const changePassword = (client: BackendAPIClient) => (data: BackendAdminAPISchemas.UserChangePasswordSchema) => - client.post("v1/admin-api/user/userext/password/", data); - - export const resetUserPassword = (client: BackendAPIClient, id: string) => () => - client.delete(`v1/admin-api/user/userext/${id}/password/`); - - export const list = - (client: BackendAPIClient, app: string, resource: string, params?: Record) => - () => - client.get(`v1/admin-api/${app}/${resource}/`, { params }); - - export const retrieve = - (client: BackendAPIClient, app: string, resource: string, id: string) => - () => { - if (!id) return Promise.resolve(null); - return client.get(`v1/admin-api/${app}/${resource}/${id}/`); - }; - - export const create = - (client: BackendAPIClient, app: string, resource: string) => - (data: T) => - client.post, T>(`v1/admin-api/${app}/${resource}/`, data); - - export const update = - (client: BackendAPIClient, app: string, resource: string, id: string) => - (data: Omit) => - client.patch>(`v1/admin-api/${app}/${resource}/${id}/`, data); - - export const updatePrepared = - (client: BackendAPIClient, app: string, resource: string) => - (data: T) => - client.patch>(`v1/admin-api/${app}/${resource}/${data.id}/`, data); - - export const remove = (client: BackendAPIClient, app: string, resource: string, id: string) => () => - client.delete(`v1/admin-api/${app}/${resource}/${id}/`); - - export const removePrepared = (client: BackendAPIClient, app: string, resource: string) => (id: string) => - client.delete(`v1/admin-api/${app}/${resource}/${id}/`); - - export const schema = (client: BackendAPIClient, app: string, resource: string) => () => - client.get(`v1/admin-api/${app}/${resource}/json-schema/`); - - export const uploadPublicFile = (client: BackendAPIClient) => (file: File) => { - const formData = new FormData(); - formData.append("file", file); - return client.post(`v1/admin-api/file/publicfile/upload/`, formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); - }; - - export const listSections = (client: BackendAPIClient, pageId: string) => () => { - if (!pageId) return Promise.resolve([]); - return client.get(`v1/admin-api/cms/page/${pageId}/section/`); - }; - - export const bulkUpdateSections = - (client: BackendAPIClient, pageId: string) => (data: { sections: BackendAdminAPISchemas.PageSectionBulkUpdateSchema[] }) => - client.put( - `v1/admin-api/cms/page/${pageId}/section/bulk-update/`, - data - ); - - export const approveModificationAudit = (client: BackendAPIClient, id: string) => (reason?: string | null) => - client.patch( - `v1/admin-api/modification-audit/modification-audit/${id}/approve/`, - { reason: reason ?? null } - ); - - export const rejectModificationAudit = (client: BackendAPIClient, id: string) => (reason?: string | null) => - client.patch( - `v1/admin-api/modification-audit/modification-audit/${id}/reject/`, - { reason: reason ?? null } +export const create = + (client: BackendAPIClient, app: string, resource: string) => + (data: T) => + client.post, T>(`v1/admin-api/${app}/${resource}/`, data); + +export const update = + (client: BackendAPIClient, app: string, resource: string, id: string) => + (data: Omit) => + client.patch>(`v1/admin-api/${app}/${resource}/${id}/`, data); + +export const updatePrepared = + (client: BackendAPIClient, app: string, resource: string) => + (data: T) => + client.patch>(`v1/admin-api/${app}/${resource}/${data.id}/`, data); + +export const remove = (client: BackendAPIClient, app: string, resource: string, id: string) => () => + client.delete(`v1/admin-api/${app}/${resource}/${id}/`); + +export const removePrepared = (client: BackendAPIClient, app: string, resource: string) => (id: string) => + client.delete(`v1/admin-api/${app}/${resource}/${id}/`); + +export const schema = (client: BackendAPIClient, app: string, resource: string) => () => + client.get(`v1/admin-api/${app}/${resource}/json-schema/`); + +export const uploadPublicFile = (client: BackendAPIClient) => (file: File) => { + const formData = new FormData(); + formData.append("file", file); + return client.post(`v1/admin-api/file/publicfile/upload/`, formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); +}; + +export const listSections = (client: BackendAPIClient, pageId: string) => () => { + if (!pageId) return Promise.resolve([]); + return client.get(`v1/admin-api/cms/page/${pageId}/section/`); +}; + +export const bulkUpdateSections = + (client: BackendAPIClient, pageId: string) => (data: { sections: BackendAdminAPISchemas.PageSectionBulkUpdateSchema[] }) => + client.put( + `v1/admin-api/cms/page/${pageId}/section/bulk-update/`, + data ); - export const previewModificationAudit = - (client: BackendAPIClient, id: string) => - () => - client.get>(`v1/admin-api/modification-audit/modification-audit/${id}/preview/`); -} - -export default BackendAdminAPIs; +export const approveModificationAudit = (client: BackendAPIClient, id: string) => (reason?: string | null) => + client.patch( + `v1/admin-api/modification-audit/modification-audit/${id}/approve/`, + { reason: reason ?? null } + ); + +export const rejectModificationAudit = (client: BackendAPIClient, id: string) => (reason?: string | null) => + client.patch( + `v1/admin-api/modification-audit/modification-audit/${id}/reject/`, + { reason: reason ?? null } + ); + +export const previewModificationAudit = + (client: BackendAPIClient, id: string) => + () => + client.get>(`v1/admin-api/modification-audit/modification-audit/${id}/preview/`); diff --git a/packages/common/src/apis/client.ts b/packages/common/src/apis/client.ts index f8506bd..958b461 100644 --- a/packages/common/src/apis/client.ts +++ b/packages/common/src/apis/client.ts @@ -1,7 +1,7 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; import * as R from "remeda"; -import BackendAPISchemas from "../schemas/backendAPI"; +import * as BackendAPISchemas from "../schemas/backendAPI"; import { getCookie } from "../utils/cookie"; const DEFAULT_ERROR_MESSAGE = "알 수 없는 문제가 발생했습니다, 잠시 후 다시 시도해주세요."; diff --git a/packages/common/src/apis/index.ts b/packages/common/src/apis/index.ts index 0166366..664752c 100644 --- a/packages/common/src/apis/index.ts +++ b/packages/common/src/apis/index.ts @@ -1,17 +1,13 @@ import { BackendAPIClient, BackendAPIClientError as _BackendAPIClientError } from "./client"; -import BackendAPISchemas from "../schemas/backendAPI"; +import * as BackendAPISchemas from "../schemas/backendAPI"; -namespace BackendAPIs { - export const BackendAPIClientError = _BackendAPIClientError; - export const listSiteMaps = (client: BackendAPIClient) => () => client.get("v1/cms/sitemap/"); - export const retrievePage = (client: BackendAPIClient) => (id: string) => client.get(`v1/cms/page/${id}/`); - export const listSponsors = (client: BackendAPIClient) => () => client.get("v1/event/sponsor/"); - export const listSessions = (client: BackendAPIClient, params?: BackendAPISchemas.SessionQueryParameterSchema) => () => - client.get("v1/event/presentation/", { params }); - export const retrieveSession = (client: BackendAPIClient) => (id: string) => { - if (!id) return Promise.resolve(null); - return client.get(`v1/event/presentation/${id}/`); - }; -} - -export default BackendAPIs; +export const BackendAPIClientError = _BackendAPIClientError; +export const listSiteMaps = (client: BackendAPIClient) => () => client.get("v1/cms/sitemap/"); +export const retrievePage = (client: BackendAPIClient) => (id: string) => client.get(`v1/cms/page/${id}/`); +export const listSponsors = (client: BackendAPIClient) => () => client.get("v1/event/sponsor/"); +export const listSessions = (client: BackendAPIClient, params?: BackendAPISchemas.SessionQueryParameterSchema) => () => + client.get("v1/event/presentation/", { params }); +export const retrieveSession = (client: BackendAPIClient) => (id: string) => { + if (!id) return Promise.resolve(null); + return client.get(`v1/event/presentation/${id}/`); +}; diff --git a/packages/common/src/apis/participant_portal_api.ts b/packages/common/src/apis/participant_portal_api.ts index 355b0fd..b09c0f4 100644 --- a/packages/common/src/apis/participant_portal_api.ts +++ b/packages/common/src/apis/participant_portal_api.ts @@ -1,80 +1,76 @@ import { BackendAPIClient } from "./client"; -import ParticipantPortalAPISchemas from "../schemas/backendParticipantPortalAPI"; - -namespace BackendParticipantPortalAPIs { - export const me = (client: BackendAPIClient) => async () => { - try { - return await client.get("v1/participant-portal/user/me/"); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (_) { - return null; - } - }; - - export const updateMe = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.UserUpdateSchema) => - client.patch("v1/participant-portal/user/me/", data); - - export const previewMeModAudit = (client: BackendAPIClient) => async () => - client.get("v1/participant-portal/user/me/preview/"); - - export const signIn = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.UserSignInSchema) => - client.post("v1/participant-portal/user/signin/", data); - - export const signOut = (client: BackendAPIClient) => () => client.delete("v1/participant-portal/user/signout/"); - - export const changePassword = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.UserChangePasswordSchema) => - client.put("v1/participant-portal/user/password/", data); - - export const listPublicFiles = (client: BackendAPIClient) => () => - client.get("v1/participant-portal/public-file/"); - - export const uploadPublicFile = (client: BackendAPIClient) => (file: File) => { - const formData = new FormData(); - formData.append("file", file); - return client.post(`v1/participant-portal/public-file/upload/`, formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); - }; - - export const listPresentations = (client: BackendAPIClient) => () => - client.get("v1/participant-portal/presentation/"); - - export const retrievePresentation = (client: BackendAPIClient, id: string) => () => { - if (!id) return Promise.resolve(null); - return client.get(`v1/participant-portal/presentation/${id}/`); - }; - - export const previewPresentationModAudit = (client: BackendAPIClient, id: string) => () => { - if (!id) return Promise.resolve(null); - return client.get(`v1/participant-portal/presentation/${id}/preview/`); - }; - - export const patchPresentation = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.PresentationUpdateSchema) => - client.patch( - `v1/participant-portal/presentation/${data.id}/`, - data - ); - - export const listModificationAudits = (client: BackendAPIClient) => () => - client.get("v1/participant-portal/modification-audit/"); - - export const previewModificationAudit = (client: BackendAPIClient, id: string) => () => { - try { - return client.get(`v1/participant-portal/modification-audit/${id}/preview/`); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (_) { - return Promise.resolve(null); - } - }; - - export const retrieveModificationAudit = (client: BackendAPIClient, id: string) => () => - client.get(`v1/participant-portal/modification-audit/${id}`); - - export const cancelModificationAudit = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.ModificationAuditCancelRequestSchema) => - client.patch( - `v1/participant-portal/modification-audit/${data.id}/cancel/`, - data - ); -} - -export default BackendParticipantPortalAPIs; +import * as ParticipantPortalAPISchemas from "../schemas/backendParticipantPortalAPI"; + +export const me = (client: BackendAPIClient) => async () => { + try { + return await client.get("v1/participant-portal/user/me/"); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_) { + return null; + } +}; + +export const updateMe = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.UserUpdateSchema) => + client.patch("v1/participant-portal/user/me/", data); + +export const previewMeModAudit = (client: BackendAPIClient) => async () => + client.get("v1/participant-portal/user/me/preview/"); + +export const signIn = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.UserSignInSchema) => + client.post("v1/participant-portal/user/signin/", data); + +export const signOut = (client: BackendAPIClient) => () => client.delete("v1/participant-portal/user/signout/"); + +export const changePassword = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.UserChangePasswordSchema) => + client.put("v1/participant-portal/user/password/", data); + +export const listPublicFiles = (client: BackendAPIClient) => () => + client.get("v1/participant-portal/public-file/"); + +export const uploadPublicFile = (client: BackendAPIClient) => (file: File) => { + const formData = new FormData(); + formData.append("file", file); + return client.post(`v1/participant-portal/public-file/upload/`, formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); +}; + +export const listPresentations = (client: BackendAPIClient) => () => + client.get("v1/participant-portal/presentation/"); + +export const retrievePresentation = (client: BackendAPIClient, id: string) => () => { + if (!id) return Promise.resolve(null); + return client.get(`v1/participant-portal/presentation/${id}/`); +}; + +export const previewPresentationModAudit = (client: BackendAPIClient, id: string) => () => { + if (!id) return Promise.resolve(null); + return client.get(`v1/participant-portal/presentation/${id}/preview/`); +}; + +export const patchPresentation = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.PresentationUpdateSchema) => + client.patch( + `v1/participant-portal/presentation/${data.id}/`, + data + ); + +export const listModificationAudits = (client: BackendAPIClient) => () => + client.get("v1/participant-portal/modification-audit/"); + +export const previewModificationAudit = (client: BackendAPIClient, id: string) => () => { + try { + return client.get(`v1/participant-portal/modification-audit/${id}/preview/`); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_) { + return Promise.resolve(null); + } +}; + +export const retrieveModificationAudit = (client: BackendAPIClient, id: string) => () => + client.get(`v1/participant-portal/modification-audit/${id}`); + +export const cancelModificationAudit = (client: BackendAPIClient) => (data: ParticipantPortalAPISchemas.ModificationAuditCancelRequestSchema) => + client.patch( + `v1/participant-portal/modification-audit/${data.id}/cancel/`, + data + ); diff --git a/packages/common/src/apis/session.ts b/packages/common/src/apis/session.ts index 0bfdd2f..c398708 100644 --- a/packages/common/src/apis/session.ts +++ b/packages/common/src/apis/session.ts @@ -1,14 +1,10 @@ import { BackendAPIClient } from "./client"; -import BackendSessionAPISchemas from "../schemas/backendSessionAPI"; +import * as BackendSessionAPISchemas from "../schemas/backendSessionAPI"; -namespace SessionAPIs { - export const sessionList = (client: BackendAPIClient) => async () => { - return await client.get("v1/event/presentation/"); - }; +export const sessionList = (client: BackendAPIClient) => async () => { + return await client.get("v1/event/presentation/"); +}; - export const sessionFilteredList = (client: BackendAPIClient, categoryName: string) => async () => { - return await client.get(`v1/event/presentation/?category=${categoryName}`); - }; -} - -export default SessionAPIs; +export const sessionFilteredList = (client: BackendAPIClient, categoryName: string) => async () => { + return await client.get(`v1/event/presentation/?category=${categoryName}`); +}; diff --git a/packages/common/src/components/common_context.tsx b/packages/common/src/components/common_context.tsx index e798168..a3a2c59 100644 --- a/packages/common/src/components/common_context.tsx +++ b/packages/common/src/components/common_context.tsx @@ -1,12 +1,12 @@ import * as React from "react"; -import GlobalContext from "../contexts"; +import { context, ContextOptions } from "../contexts"; type CommonContextProps = { - options: GlobalContext.ContextOptions; + options: ContextOptions; children: React.ReactNode; }; export const CommonContextProvider: React.FC = (props) => ( - {props.children} + {props.children} ); diff --git a/packages/common/src/components/error_handler.tsx b/packages/common/src/components/error_handler.tsx index 345590b..643e41f 100644 --- a/packages/common/src/components/error_handler.tsx +++ b/packages/common/src/components/error_handler.tsx @@ -2,7 +2,7 @@ import { Button, Typography } from "@mui/material"; import { Suspense } from "@suspensive/react"; import * as React from "react"; -import CommonContext from "../hooks/"; +import * as CommonContext from "../hooks"; const DetailedErrorFallback: React.FC<{ error: Error; reset: () => void }> = ({ error, reset }) => { console.error(error); diff --git a/packages/common/src/components/mdx.tsx b/packages/common/src/components/mdx.tsx index 146d953..0afd1d1 100644 --- a/packages/common/src/components/mdx.tsx +++ b/packages/common/src/components/mdx.tsx @@ -9,7 +9,7 @@ import * as runtime from "react/jsx-runtime"; import remarkGfm from "remark-gfm"; import * as R from "remeda"; -import Hooks from "../hooks"; +import * as Hooks from "../hooks"; import { ErrorFallback } from "./error_handler"; import { LinkHandler } from "./link_handler"; import { rtrim } from "../utils/string"; diff --git a/packages/common/src/components/mdx_components/session_list.tsx b/packages/common/src/components/mdx_components/session_list.tsx index e905e3f..97e77c7 100644 --- a/packages/common/src/components/mdx_components/session_list.tsx +++ b/packages/common/src/components/mdx_components/session_list.tsx @@ -5,8 +5,8 @@ import { Link } from "react-router-dom"; import * as R from "remeda"; import PyCon2025Logo from "../../assets/pyconkr2025_logo.png"; -import Hooks from "../../hooks"; -import BackendAPISchemas from "../../schemas/backendAPI"; +import * as Hooks from "../../hooks"; +import * as BackendAPISchemas from "../../schemas/backendAPI"; import { ErrorFallback } from "../error_handler"; import { FallbackImage } from "../fallback_image"; import { StyledDivider } from "./styled_divider"; diff --git a/packages/common/src/components/mdx_components/session_timetable.tsx b/packages/common/src/components/mdx_components/session_timetable.tsx index 9f02cf5..a646c0a 100644 --- a/packages/common/src/components/mdx_components/session_timetable.tsx +++ b/packages/common/src/components/mdx_components/session_timetable.tsx @@ -5,8 +5,8 @@ import * as React from "react"; import { Link } from "react-router-dom"; import * as R from "remeda"; -import Hooks from "../../hooks"; -import BackendAPISchemas from "../../schemas/backendAPI"; +import * as Hooks from "../../hooks"; +import * as BackendAPISchemas from "../../schemas/backendAPI"; import { CenteredPage } from "../centered_page"; import { ErrorFallback } from "../error_handler"; import { StyledDivider } from "./styled_divider"; diff --git a/packages/common/src/components/mdx_editor.tsx b/packages/common/src/components/mdx_editor.tsx index f83a003..2fa500c 100644 --- a/packages/common/src/components/mdx_editor.tsx +++ b/packages/common/src/components/mdx_editor.tsx @@ -8,7 +8,7 @@ import * as React from "react"; import * as R from "remeda"; // import * as CryptoJS from "crypto-js"; -import Hooks from "../hooks"; +import * as Hooks from "../hooks"; type CustomComponentInfoType = { k: string; // key diff --git a/packages/common/src/contexts/index.ts b/packages/common/src/contexts/index.ts index 69ffc1d..421d589 100644 --- a/packages/common/src/contexts/index.ts +++ b/packages/common/src/contexts/index.ts @@ -1,27 +1,23 @@ import { MDXComponents } from "mdx/types"; import * as React from "react"; -namespace GlobalContext { - export type ContextOptions = { - language: "ko" | "en"; - frontendDomain?: string; - baseUrl: string; - debug?: boolean; - backendApiDomain: string; - backendApiTimeout: number; - backendApiCSRFCookieName?: string; - mdxComponents?: MDXComponents; - }; +export type ContextOptions = { + language: "ko" | "en"; + frontendDomain?: string; + baseUrl: string; + debug?: boolean; + backendApiDomain: string; + backendApiTimeout: number; + backendApiCSRFCookieName?: string; + mdxComponents?: MDXComponents; +}; - export const context = React.createContext({ - language: "ko", - frontendDomain: "", - baseUrl: "", - debug: false, - backendApiDomain: "", - backendApiTimeout: 10000, - backendApiCSRFCookieName: "", - }); -} - -export default GlobalContext; +export const context = React.createContext({ + language: "ko", + frontendDomain: "", + baseUrl: "", + debug: false, + backendApiDomain: "", + backendApiTimeout: 10000, + backendApiCSRFCookieName: "", +}); diff --git a/packages/common/src/hooks/index.ts b/packages/common/src/hooks/index.ts index 7dee57f..cc174e5 100644 --- a/packages/common/src/hooks/index.ts +++ b/packages/common/src/hooks/index.ts @@ -1,19 +1,7 @@ -import BackendAPIHooks from "./useAPI"; -import BackendAdminAPIHooks from "./useAdminAPI"; -import { useCommonContext as useCommonContextHook } from "./useCommonContext"; -import { useEmail as useEmailHook } from "./useEmail"; -import BackendParticipantPortalAPIHooks from "./useParticipantPortalAPI"; +import { useCommonContext } from "./useCommonContext"; +import { useEmail } from "./useEmail"; -export namespace CommonHooks { - export const useCommonContext = useCommonContextHook; - export const useEmail = useEmailHook; -} - -namespace Hooks { - export const Common = CommonHooks; - export const BackendAPI = BackendAPIHooks; - export const BackendAdminAPI = BackendAdminAPIHooks; - export const BackendParticipantPortalAPI = BackendParticipantPortalAPIHooks; -} - -export default Hooks; +export * as BackendAPI from "./useAPI"; +export * as BackendAdminAPI from "./useAdminAPI"; +export * as BackendParticipantPortalAPI from "./useParticipantPortalAPI"; +export const Common = { useCommonContext, useEmail }; diff --git a/packages/common/src/hooks/useAPI.ts b/packages/common/src/hooks/useAPI.ts index 10922c6..3cc90d9 100644 --- a/packages/common/src/hooks/useAPI.ts +++ b/packages/common/src/hooks/useAPI.ts @@ -1,10 +1,10 @@ import { useSuspenseQuery } from "@tanstack/react-query"; import * as React from "react"; -import BackendAPIs from "../apis"; +import * as BackendAPIs from "../apis"; import { BackendAPIClient } from "../apis/client"; -import BackendContext from "../contexts"; -import BackendAPISchemas from "../schemas/backendAPI"; +import { context as backendContext } from "../contexts"; +import * as BackendAPISchemas from "../schemas/backendAPI"; const QUERY_KEYS = { SITEMAP_LIST: ["query", "sitemap", "list"], @@ -13,47 +13,43 @@ const QUERY_KEYS = { SESSION_LIST: ["query", "session", "list"], }; -namespace BackendAPIHooks { - export const useBackendContext = () => { - const context = React.useContext(BackendContext.context); - if (!context) throw new Error("useBackendContext must be used within a CommonProvider"); - return context; - }; - - export const useBackendClient = () => { - const { language, backendApiDomain, backendApiTimeout } = useBackendContext(); - return new BackendAPIClient(backendApiDomain, backendApiTimeout, "", false, language); - }; - - export const useFlattenSiteMapQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.SITEMAP_LIST, client.language], - queryFn: BackendAPIs.listSiteMaps(client), - }); - - export const usePageQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PAGE, id, client.language], - queryFn: () => BackendAPIs.retrievePage(client)(id), - }); - - export const useSponsorQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.SPONSOR_LIST, client.language], - queryFn: BackendAPIs.listSponsors(client), - }); - - export const useSessionsQuery = (client: BackendAPIClient, params?: BackendAPISchemas.SessionQueryParameterSchema) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.SESSION_LIST, client.language, ...(params ? [JSON.stringify(params)] : [])], - queryFn: BackendAPIs.listSessions(client, params), - }); - - export const useSessionQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.SESSION_LIST, id, client.language], - queryFn: () => BackendAPIs.retrieveSession(client)(id), - }); -} - -export default BackendAPIHooks; +export const useBackendContext = () => { + const ctx = React.useContext(backendContext); + if (!ctx) throw new Error("useBackendContext must be used within a CommonProvider"); + return ctx; +}; + +export const useBackendClient = () => { + const { language, backendApiDomain, backendApiTimeout } = useBackendContext(); + return new BackendAPIClient(backendApiDomain, backendApiTimeout, "", false, language); +}; + +export const useFlattenSiteMapQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.SITEMAP_LIST, client.language], + queryFn: BackendAPIs.listSiteMaps(client), + }); + +export const usePageQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PAGE, id, client.language], + queryFn: () => BackendAPIs.retrievePage(client)(id), + }); + +export const useSponsorQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.SPONSOR_LIST, client.language], + queryFn: BackendAPIs.listSponsors(client), + }); + +export const useSessionsQuery = (client: BackendAPIClient, params?: BackendAPISchemas.SessionQueryParameterSchema) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.SESSION_LIST, client.language, ...(params ? [JSON.stringify(params)] : [])], + queryFn: BackendAPIs.listSessions(client, params), + }); + +export const useSessionQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.SESSION_LIST, id, client.language], + queryFn: () => BackendAPIs.retrieveSession(client)(id), + }); diff --git a/packages/common/src/hooks/useAdminAPI.ts b/packages/common/src/hooks/useAdminAPI.ts index 197ed2e..8ea3133 100644 --- a/packages/common/src/hooks/useAdminAPI.ts +++ b/packages/common/src/hooks/useAdminAPI.ts @@ -1,9 +1,9 @@ import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; -import BackendAPIHooks from "./useAPI"; -import BackendAdminAPIs from "../apis/admin_api"; +import { useBackendContext } from "./useAPI"; +import * as BackendAdminAPIs from "../apis/admin_api"; import { BackendAPIClient } from "../apis/client"; -import BackendAdminAPISchemas from "../schemas/backendAdminAPI"; +import * as BackendAdminAPISchemas from "../schemas/backendAdminAPI"; const QUERY_KEYS = { ADMIN_ME: ["query", "admin", "me"], @@ -25,131 +25,127 @@ const MUTATION_KEYS = { ADMIN_REJECT_MODIFICATION_AUDIT: ["mutation", "admin", "reject", "modification-audit"], }; -namespace BackendAdminAPIHooks { - export const useBackendAdminClient = () => { - const { backendApiDomain, backendApiTimeout, backendApiCSRFCookieName } = BackendAPIHooks.useBackendContext(); - return new BackendAPIClient(backendApiDomain, backendApiTimeout, backendApiCSRFCookieName, true); - }; - - export const useSignedInUserQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: QUERY_KEYS.ADMIN_ME, - queryFn: BackendAdminAPIs.me(client), - }); - - export const useSignInMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_SIGN_IN], - mutationFn: BackendAdminAPIs.signIn(client), - }); - - export const useSignOutMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_SIGN_OUT], - mutationFn: BackendAdminAPIs.signOut(client), - }); - - export const useChangePasswordMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_CHANGE_PASSWORD], - mutationFn: BackendAdminAPIs.changePassword(client), - }); - - export const useResetUserPasswordMutation = (client: BackendAPIClient, id: string) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_RESET_PASSWORD, id], - mutationFn: BackendAdminAPIs.resetUserPassword(client, id), - }); - - export const useSchemaQuery = (client: BackendAPIClient, app: string, resource: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.ADMIN_SCHEMA, app, resource], - queryFn: BackendAdminAPIs.schema(client, app, resource), - }); - - export const useListQuery = (client: BackendAPIClient, app: string, resource: string, params?: Record) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.ADMIN_LIST, app, resource, JSON.stringify(params)], - queryFn: BackendAdminAPIs.list(client, app, resource, params), - }); - - export const useRetrieveQuery = (client: BackendAPIClient, app: string, resource: string, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.ADMIN_RETRIEVE, app, resource, id], - queryFn: BackendAdminAPIs.retrieve(client, app, resource, id), - }); - - export const useCreateMutation = (client: BackendAPIClient, app: string, resource: string) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_CREATE, app, resource], - mutationFn: BackendAdminAPIs.create(client, app, resource), - }); - - export const useUpdateMutation = (client: BackendAPIClient, app: string, resource: string, id: string) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_UPDATE, app, resource, id], - mutationFn: BackendAdminAPIs.update(client, app, resource, id), - }); - - export const useUpdatePreparedMutation = (client: BackendAPIClient, app: string, resource: string) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_UPDATE, app, resource, "prepared"], - mutationFn: BackendAdminAPIs.updatePrepared(client, app, resource), - }); - - export const useRemoveMutation = (client: BackendAPIClient, app: string, resource: string, id: string) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_REMOVE, app, resource, id], - mutationFn: BackendAdminAPIs.remove(client, app, resource, id), - }); - - export const useRemovePreparedMutation = (client: BackendAPIClient, app: string, resource: string) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_REMOVE, app, resource, "prepared"], - mutationFn: BackendAdminAPIs.removePrepared(client, app, resource), - }); - - export const usePublicFileQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.ADMIN_RETRIEVE, "file", "publicfile", id], - queryFn: BackendAdminAPIs.retrieve(client, "file", "publicfile", id), - }); - - export const useUploadPublicFileMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_CREATE, "public-file", "upload"], - mutationFn: BackendAdminAPIs.uploadPublicFile(client), - }); - - export const useListPageSectionsQuery = (client: BackendAPIClient, pageId: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.ADMIN_LIST, "cms", "page", pageId, "section"], - queryFn: BackendAdminAPIs.listSections(client, pageId), - }); - - export const useBulkUpdatePageSectionsMutation = (client: BackendAPIClient, pageId: string) => - useMutation({ - mutationKey: [...MUTATION_KEYS.ADMIN_UPDATE, "cms", "page", pageId, "section"], - mutationFn: BackendAdminAPIs.bulkUpdateSections(client, pageId), - }); - - export const useModificationAuditPreviewQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.ADMIN_PREVIEW_MODIFICATION_AUDIT, id], - queryFn: BackendAdminAPIs.previewModificationAudit(client, id), - }); - - export const useApproveModificationAuditMutation = (client: BackendAPIClient, id: string) => - useMutation({ - mutationKey: MUTATION_KEYS.ADMIN_APPROVE_MODIFICATION_AUDIT, - mutationFn: BackendAdminAPIs.approveModificationAudit(client, id), - }); - - export const useRejectModificationAuditMutation = (client: BackendAPIClient, id: string) => - useMutation({ - mutationKey: MUTATION_KEYS.ADMIN_REJECT_MODIFICATION_AUDIT, - mutationFn: BackendAdminAPIs.rejectModificationAudit(client, id), - }); -} - -export default BackendAdminAPIHooks; +export const useBackendAdminClient = () => { + const { backendApiDomain, backendApiTimeout, backendApiCSRFCookieName } = useBackendContext(); + return new BackendAPIClient(backendApiDomain, backendApiTimeout, backendApiCSRFCookieName, true); +}; + +export const useSignedInUserQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: QUERY_KEYS.ADMIN_ME, + queryFn: BackendAdminAPIs.me(client), + }); + +export const useSignInMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_SIGN_IN], + mutationFn: BackendAdminAPIs.signIn(client), + }); + +export const useSignOutMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_SIGN_OUT], + mutationFn: BackendAdminAPIs.signOut(client), + }); + +export const useChangePasswordMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_CHANGE_PASSWORD], + mutationFn: BackendAdminAPIs.changePassword(client), + }); + +export const useResetUserPasswordMutation = (client: BackendAPIClient, id: string) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_RESET_PASSWORD, id], + mutationFn: BackendAdminAPIs.resetUserPassword(client, id), + }); + +export const useSchemaQuery = (client: BackendAPIClient, app: string, resource: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.ADMIN_SCHEMA, app, resource], + queryFn: BackendAdminAPIs.schema(client, app, resource), + }); + +export const useListQuery = (client: BackendAPIClient, app: string, resource: string, params?: Record) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.ADMIN_LIST, app, resource, JSON.stringify(params)], + queryFn: BackendAdminAPIs.list(client, app, resource, params), + }); + +export const useRetrieveQuery = (client: BackendAPIClient, app: string, resource: string, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.ADMIN_RETRIEVE, app, resource, id], + queryFn: BackendAdminAPIs.retrieve(client, app, resource, id), + }); + +export const useCreateMutation = (client: BackendAPIClient, app: string, resource: string) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_CREATE, app, resource], + mutationFn: BackendAdminAPIs.create(client, app, resource), + }); + +export const useUpdateMutation = (client: BackendAPIClient, app: string, resource: string, id: string) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_UPDATE, app, resource, id], + mutationFn: BackendAdminAPIs.update(client, app, resource, id), + }); + +export const useUpdatePreparedMutation = (client: BackendAPIClient, app: string, resource: string) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_UPDATE, app, resource, "prepared"], + mutationFn: BackendAdminAPIs.updatePrepared(client, app, resource), + }); + +export const useRemoveMutation = (client: BackendAPIClient, app: string, resource: string, id: string) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_REMOVE, app, resource, id], + mutationFn: BackendAdminAPIs.remove(client, app, resource, id), + }); + +export const useRemovePreparedMutation = (client: BackendAPIClient, app: string, resource: string) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_REMOVE, app, resource, "prepared"], + mutationFn: BackendAdminAPIs.removePrepared(client, app, resource), + }); + +export const usePublicFileQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.ADMIN_RETRIEVE, "file", "publicfile", id], + queryFn: BackendAdminAPIs.retrieve(client, "file", "publicfile", id), + }); + +export const useUploadPublicFileMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_CREATE, "public-file", "upload"], + mutationFn: BackendAdminAPIs.uploadPublicFile(client), + }); + +export const useListPageSectionsQuery = (client: BackendAPIClient, pageId: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.ADMIN_LIST, "cms", "page", pageId, "section"], + queryFn: BackendAdminAPIs.listSections(client, pageId), + }); + +export const useBulkUpdatePageSectionsMutation = (client: BackendAPIClient, pageId: string) => + useMutation({ + mutationKey: [...MUTATION_KEYS.ADMIN_UPDATE, "cms", "page", pageId, "section"], + mutationFn: BackendAdminAPIs.bulkUpdateSections(client, pageId), + }); + +export const useModificationAuditPreviewQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.ADMIN_PREVIEW_MODIFICATION_AUDIT, id], + queryFn: BackendAdminAPIs.previewModificationAudit(client, id), + }); + +export const useApproveModificationAuditMutation = (client: BackendAPIClient, id: string) => + useMutation({ + mutationKey: MUTATION_KEYS.ADMIN_APPROVE_MODIFICATION_AUDIT, + mutationFn: BackendAdminAPIs.approveModificationAudit(client, id), + }); + +export const useRejectModificationAuditMutation = (client: BackendAPIClient, id: string) => + useMutation({ + mutationKey: MUTATION_KEYS.ADMIN_REJECT_MODIFICATION_AUDIT, + mutationFn: BackendAdminAPIs.rejectModificationAudit(client, id), + }); diff --git a/packages/common/src/hooks/useCommonContext.ts b/packages/common/src/hooks/useCommonContext.ts index 36ae9cc..3cb5e56 100644 --- a/packages/common/src/hooks/useCommonContext.ts +++ b/packages/common/src/hooks/useCommonContext.ts @@ -1,11 +1,11 @@ import * as React from "react"; -import GlobalContext from "../contexts"; +import { context } from "../contexts"; export const useCommonContext = () => { - const context = React.useContext(GlobalContext.context); - if (!context) { + const ctx = React.useContext(context); + if (!ctx) { throw new Error("useCommonContext must be used within a CommonProvider"); } - return context; + return ctx; }; diff --git a/packages/common/src/hooks/useParticipantPortalAPI.ts b/packages/common/src/hooks/useParticipantPortalAPI.ts index 266f759..f5d4d33 100644 --- a/packages/common/src/hooks/useParticipantPortalAPI.ts +++ b/packages/common/src/hooks/useParticipantPortalAPI.ts @@ -1,8 +1,8 @@ import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; -import BackendAPIHooks from "./useAPI"; +import { useBackendContext } from "./useAPI"; import { BackendAPIClient } from "../apis/client"; -import ParticipantPortalAPI from "../apis/participant_portal_api"; +import * as ParticipantPortalAPI from "../apis/participant_portal_api"; const QUERY_KEYS = { PARTICIPANT_ME: ["query", "participant", "me"], @@ -23,107 +23,103 @@ const MUTATION_KEYS = { PARTICIPANT_CANCEL_MODIFICATION_AUDIT: ["mutation", "participant", "cancel", "modification-audit"], }; -namespace BackendParticipantPortalAPIHooks { - export const useParticipantPortalClient = () => { - const { backendApiDomain, backendApiTimeout, backendApiCSRFCookieName, language } = BackendAPIHooks.useBackendContext(); - return new BackendAPIClient(backendApiDomain, backendApiTimeout, backendApiCSRFCookieName, true, language); - }; - - export const useSignedInUserQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_ME, client.language], - queryFn: ParticipantPortalAPI.me(client), - }); - - export const usePreviewMeModAuditQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_ME, "preview", client.language], - queryFn: ParticipantPortalAPI.previewMeModAudit(client), - }); - - export const useUpdateMeMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.PARTICIPANT_UPDATE_ME], - mutationFn: ParticipantPortalAPI.updateMe(client), - }); - - export const useSignInMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.PARTICIPANT_SIGN_IN], - mutationFn: ParticipantPortalAPI.signIn(client), - }); - - export const useSignOutMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.PARTICIPANT_SIGN_OUT], - mutationFn: ParticipantPortalAPI.signOut(client), - }); - - export const useChangePasswordMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.PARTICIPANT_CHANGE_PASSWORD], - mutationFn: ParticipantPortalAPI.changePassword(client), - }); - - export const usePublicFilesQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_PUBLIC_FILES, client.language], - queryFn: ParticipantPortalAPI.listPublicFiles(client), - }); - - export const useUploadPublicFileMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.PARTICIPANT_UPLOAD_PUBLIC_FILE, "upload"], - mutationFn: ParticipantPortalAPI.uploadPublicFile(client), - }); - - export const useListPresentationsQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_LIST_PRESENTATION, client.language], - queryFn: ParticipantPortalAPI.listPresentations(client), - }); - - export const useRetrievePresentationQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_RETRIEVE_PRESENTATION, id, client.language], - queryFn: ParticipantPortalAPI.retrievePresentation(client, id), - }); - - export const useUpdatePresentationMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.PARTICIPANT_UPDATE_PRESENTATION], - mutationFn: ParticipantPortalAPI.patchPresentation(client), - }); - - export const usePreviewPresentationModAuditQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_RETRIEVE_PRESENTATION, id, "preview", client.language], - queryFn: ParticipantPortalAPI.previewPresentationModAudit(client, id), - }); - - export const useModificationAuditsQuery = (client: BackendAPIClient) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_LIST_MODIFICATION_AUDIT, client.language], - queryFn: ParticipantPortalAPI.listModificationAudits(client), - }); - - export const useModificationAuditPreviewQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_LIST_MODIFICATION_AUDIT, "preview", id, client.language], - queryFn: ParticipantPortalAPI.previewModificationAudit(client, id), - }); - - export const useRetrieveModificationAuditQuery = (client: BackendAPIClient, id: string) => - useSuspenseQuery({ - queryKey: [...QUERY_KEYS.PARTICIPANT_RETRIEVE_MODIFICATION_AUDIT, id, client.language], - queryFn: ParticipantPortalAPI.retrieveModificationAudit(client, id), - }); - - export const useCancelModificationAuditMutation = (client: BackendAPIClient) => - useMutation({ - mutationKey: [...MUTATION_KEYS.PARTICIPANT_CANCEL_MODIFICATION_AUDIT], - mutationFn: ParticipantPortalAPI.cancelModificationAudit(client), - }); -} - -export default BackendParticipantPortalAPIHooks; +export const useParticipantPortalClient = () => { + const { backendApiDomain, backendApiTimeout, backendApiCSRFCookieName, language } = useBackendContext(); + return new BackendAPIClient(backendApiDomain, backendApiTimeout, backendApiCSRFCookieName, true, language); +}; + +export const useSignedInUserQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_ME, client.language], + queryFn: ParticipantPortalAPI.me(client), + }); + +export const usePreviewMeModAuditQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_ME, "preview", client.language], + queryFn: ParticipantPortalAPI.previewMeModAudit(client), + }); + +export const useUpdateMeMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.PARTICIPANT_UPDATE_ME], + mutationFn: ParticipantPortalAPI.updateMe(client), + }); + +export const useSignInMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.PARTICIPANT_SIGN_IN], + mutationFn: ParticipantPortalAPI.signIn(client), + }); + +export const useSignOutMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.PARTICIPANT_SIGN_OUT], + mutationFn: ParticipantPortalAPI.signOut(client), + }); + +export const useChangePasswordMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.PARTICIPANT_CHANGE_PASSWORD], + mutationFn: ParticipantPortalAPI.changePassword(client), + }); + +export const usePublicFilesQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_PUBLIC_FILES, client.language], + queryFn: ParticipantPortalAPI.listPublicFiles(client), + }); + +export const useUploadPublicFileMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.PARTICIPANT_UPLOAD_PUBLIC_FILE, "upload"], + mutationFn: ParticipantPortalAPI.uploadPublicFile(client), + }); + +export const useListPresentationsQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_LIST_PRESENTATION, client.language], + queryFn: ParticipantPortalAPI.listPresentations(client), + }); + +export const useRetrievePresentationQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_RETRIEVE_PRESENTATION, id, client.language], + queryFn: ParticipantPortalAPI.retrievePresentation(client, id), + }); + +export const useUpdatePresentationMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.PARTICIPANT_UPDATE_PRESENTATION], + mutationFn: ParticipantPortalAPI.patchPresentation(client), + }); + +export const usePreviewPresentationModAuditQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_RETRIEVE_PRESENTATION, id, "preview", client.language], + queryFn: ParticipantPortalAPI.previewPresentationModAudit(client, id), + }); + +export const useModificationAuditsQuery = (client: BackendAPIClient) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_LIST_MODIFICATION_AUDIT, client.language], + queryFn: ParticipantPortalAPI.listModificationAudits(client), + }); + +export const useModificationAuditPreviewQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_LIST_MODIFICATION_AUDIT, "preview", id, client.language], + queryFn: ParticipantPortalAPI.previewModificationAudit(client, id), + }); + +export const useRetrieveModificationAuditQuery = (client: BackendAPIClient, id: string) => + useSuspenseQuery({ + queryKey: [...QUERY_KEYS.PARTICIPANT_RETRIEVE_MODIFICATION_AUDIT, id, client.language], + queryFn: ParticipantPortalAPI.retrieveModificationAudit(client, id), + }); + +export const useCancelModificationAuditMutation = (client: BackendAPIClient) => + useMutation({ + mutationKey: [...MUTATION_KEYS.PARTICIPANT_CANCEL_MODIFICATION_AUDIT], + mutationFn: ParticipantPortalAPI.cancelModificationAudit(client), + }); diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 3517381..15451f6 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -1,8 +1,8 @@ -export { default as BackendAdminAPIs } from "./apis/admin_api"; -export { default as BackendAPIs } from "./apis/index"; -export { default as BackendParticipantPortalAPIs } from "./apis/participant_portal_api"; +export * as BackendAdminAPIs from "./apis/admin_api"; +export * as BackendAPIs from "./apis/index"; +export * as BackendParticipantPortalAPIs from "./apis/participant_portal_api"; export { default as Components } from "./components/index"; -export { default as Contexts } from "./contexts/index"; -export { default as Hooks } from "./hooks/index"; -export { default as Schemas } from "./schemas/index"; -export { default as Utils } from "./utils/index"; +export * as Contexts from "./contexts/index"; +export * as Hooks from "./hooks/index"; +export * as Schemas from "./schemas/index"; +export * as Utils from "./utils/index"; diff --git a/packages/common/src/schemas/backendAPI.ts b/packages/common/src/schemas/backendAPI.ts index be05f0b..5b7ba58 100644 --- a/packages/common/src/schemas/backendAPI.ts +++ b/packages/common/src/schemas/backendAPI.ts @@ -1,116 +1,112 @@ import * as R from "remeda"; -namespace BackendAPISchemas { - export type EmptyObject = Record; +export type EmptyObject = Record; - export type DetailedErrorSchema = { - code: string; - detail: string; - attr: string | null; - }; +export type DetailedErrorSchema = { + code: string; + detail: string; + attr: string | null; +}; - export type ErrorResponseSchema = { - type: string; - errors: DetailedErrorSchema[]; - }; +export type ErrorResponseSchema = { + type: string; + errors: DetailedErrorSchema[]; +}; - export type FlattenedSiteMapSchema = { - id: string; - route_code: string; - name: string; - order: number; - parent_sitemap: string | null; - hide: boolean; - page: string | null; - external_link: string | null; - }; +export type FlattenedSiteMapSchema = { + id: string; + route_code: string; + name: string; + order: number; + parent_sitemap: string | null; + hide: boolean; + page: string | null; + external_link: string | null; +}; - export type NestedSiteMapSchema = { - id: string; - route_code: string; - name: string; - order: number; - hide: boolean; - parent_sitemap: string | null; - children: NestedSiteMapSchema[]; - page: string | null; - external_link: string | null; - }; +export type NestedSiteMapSchema = { + id: string; + route_code: string; + name: string; + order: number; + hide: boolean; + parent_sitemap: string | null; + children: NestedSiteMapSchema[]; + page: string | null; + external_link: string | null; +}; - export type SectionSchema = { - id: string; - css: string; +export type SectionSchema = { + id: string; + css: string; - order: number; - body: string; - }; + order: number; + body: string; +}; - export type PageSchema = { - id: string; - css: string; - title: string; - subtitle: string; +export type PageSchema = { + id: string; + css: string; + title: string; + subtitle: string; - show_top_title_banner: boolean; - show_bottom_sponsor_banner: boolean; + show_top_title_banner: boolean; + show_bottom_sponsor_banner: boolean; - sections: SectionSchema[]; - }; + sections: SectionSchema[]; +}; - export type SponsorTierSchema = { +export type SponsorTierSchema = { + id: string; + name: string; + order: number; + sponsors: { id: string; name: string; - order: number; - sponsors: { - id: string; - name: string; - logo: string; - description: string; - tags: string[]; - }[]; - }; + logo: string; + description: string; + tags: string[]; + }[]; +}; - export type SessionQueryParameterSchema = { - event?: string; - types?: string; - }; +export type SessionQueryParameterSchema = { + event?: string; + types?: string; +}; - export type SessionSchema = { +export type SessionSchema = { + id: string; + title: string; + summary: string | null; + description: string; + slideshow_url: string | null; + public_slideshow_file: string | null; + image: string | null; + categories: { id: string; - title: string; - summary: string | null; - description: string; - slideshow_url: string | null; - public_slideshow_file: string | null; + name: string; + }[]; + speakers: { + id: string; + nickname: string; + biography: string; image: string | null; - categories: { - id: string; - name: string; - }[]; - speakers: { - id: string; - nickname: string; - biography: string; - image: string | null; - }[]; - room_schedules: { - id: string; - room_name: string; - start_at: string; - end_at: string; - }[]; - }; - - export const isObjectErrorResponseSchema = (obj?: unknown): obj is BackendAPISchemas.ErrorResponseSchema => { - return ( - R.isPlainObject(obj) && - R.isString(obj.type) && - R.isArray(obj.errors) && - obj.errors.every((error) => { - return R.isPlainObject(error) && R.isString(error.code) && R.isString(error.detail) && (error.attr === null || R.isString(error.attr)); - }) - ); - }; -} + }[]; + room_schedules: { + id: string; + room_name: string; + start_at: string; + end_at: string; + }[]; +}; -export default BackendAPISchemas; +export const isObjectErrorResponseSchema = (obj?: unknown): obj is ErrorResponseSchema => { + return ( + R.isPlainObject(obj) && + R.isString(obj.type) && + R.isArray(obj.errors) && + obj.errors.every((error) => { + return R.isPlainObject(error) && R.isString(error.code) && R.isString(error.detail) && (error.attr === null || R.isString(error.attr)); + }) + ); +}; diff --git a/packages/common/src/schemas/backendAdminAPI.ts b/packages/common/src/schemas/backendAdminAPI.ts index f4b2d84..645aa53 100644 --- a/packages/common/src/schemas/backendAdminAPI.ts +++ b/packages/common/src/schemas/backendAdminAPI.ts @@ -1,138 +1,134 @@ import { RJSFSchema, UiSchema } from "@rjsf/utils"; -namespace BackendAdminAPISchemas { - export type DetailedErrorSchema = { - code: string; - detail: string; - attr: string | null; - }; - - export type ErrorResponseSchema = { - type: string; - errors: DetailedErrorSchema[]; - }; - - export type AdminSchemaDefinition = { - schema: RJSFSchema; - ui_schema: UiSchema; - translation_fields: string[]; - }; - - export type UserSchema = { - id: number; - username: string; - email: string; - first_name: string; - last_name: string; - is_staff: boolean; - is_active: boolean; - date_joined: string; // ISO 8601 format - }; - - export type UserSignInSchema = { - identity: string; // username or email - password: string; - }; - - export type UserChangePasswordSchema = { - old_password: string; - new_password: string; - new_password_confirm: string; - }; - - export type UserResetPasswordResponseSchema = { - password: string; - }; - - export type PublicFileSchema = { - id: string; // UUID - file: string; // URL to the public file - mimetype: string | null; // MIME type of the file - hash: string; // Hash of the file for integrity check - size: number; // Size of the file in bytes - }; - - export type PageSectionSchema = { - id?: string; - order: number; - css: string; - body_ko: string | null; - body_en: string | null; - }; - - export type FlattenedSiteMapSchema = { - id: string; - route_code: string; - name_ko: string; - name_en: string; - order: number; - parent_sitemap: string | null; - hide: boolean; - page: string | null; - external_link: string | null; - }; - - export type NestedSiteMapSchema = { - id: string; - route_code: string; - name_ko: string; - name_en: string; - order: number; - parent_sitemap: string | null; - hide: boolean; - children: NestedSiteMapSchema[]; - page: string | null; - external_link: string | null; - }; - - export type PageSectionBulkUpdateSchema = PageSectionSchema | Omit; - - export type PresentationSchema = { - id: string; // UUID - type: string; // UUID of the presentation type - categories: string[]; // Array of category UUIDs - title_ko: string; - title_en: string; - summary_ko: string; - summary_en: string; - description_ko: string; - description_en: string; - slideshow_url: string | null; - image: string | null; - }; - - export type ModificationAuditSchema = { - id: string; // UUID - status: "requested" | "approved" | "rejected" | "cancelled"; // Status of the modification request +export type DetailedErrorSchema = { + code: string; + detail: string; + attr: string | null; +}; + +export type ErrorResponseSchema = { + type: string; + errors: DetailedErrorSchema[]; +}; + +export type AdminSchemaDefinition = { + schema: RJSFSchema; + ui_schema: UiSchema; + translation_fields: string[]; +}; + +export type UserSchema = { + id: number; + username: string; + email: string; + first_name: string; + last_name: string; + is_staff: boolean; + is_active: boolean; + date_joined: string; // ISO 8601 format +}; + +export type UserSignInSchema = { + identity: string; // username or email + password: string; +}; + +export type UserChangePasswordSchema = { + old_password: string; + new_password: string; + new_password_confirm: string; +}; + +export type UserResetPasswordResponseSchema = { + password: string; +}; + +export type PublicFileSchema = { + id: string; // UUID + file: string; // URL to the public file + mimetype: string | null; // MIME type of the file + hash: string; // Hash of the file for integrity check + size: number; // Size of the file in bytes +}; + +export type PageSectionSchema = { + id?: string; + order: number; + css: string; + body_ko: string | null; + body_en: string | null; +}; + +export type FlattenedSiteMapSchema = { + id: string; + route_code: string; + name_ko: string; + name_en: string; + order: number; + parent_sitemap: string | null; + hide: boolean; + page: string | null; + external_link: string | null; +}; + +export type NestedSiteMapSchema = { + id: string; + route_code: string; + name_ko: string; + name_en: string; + order: number; + parent_sitemap: string | null; + hide: boolean; + children: NestedSiteMapSchema[]; + page: string | null; + external_link: string | null; +}; + +export type PageSectionBulkUpdateSchema = PageSectionSchema | Omit; + +export type PresentationSchema = { + id: string; // UUID + type: string; // UUID of the presentation type + categories: string[]; // Array of category UUIDs + title_ko: string; + title_en: string; + summary_ko: string; + summary_en: string; + description_ko: string; + description_en: string; + slideshow_url: string | null; + image: string | null; +}; + +export type ModificationAuditSchema = { + id: string; // UUID + status: "requested" | "approved" | "rejected" | "cancelled"; // Status of the modification request + created_at: string; // ISO 8601 timestamp + updated_at: string; // ISO 8601 timestamp + created_by: string; + updated_by: string | null; // User ID of the person who last updated the audit + modification_data: string; // JSON string containing the modification data + str_repr: string; // String representation of the modification audit, e.g., "Presentation Title - Status" + comments: { + id: string; // UUID of the comment + content: string; // Content of the comment created_at: string; // ISO 8601 timestamp - updated_at: string; // ISO 8601 timestamp - created_by: string; - updated_by: string | null; // User ID of the person who last updated the audit - modification_data: string; // JSON string containing the modification data - str_repr: string; // String representation of the modification audit, e.g., "Presentation Title - Status" - comments: { - id: string; // UUID of the comment - content: string; // Content of the comment - created_at: string; // ISO 8601 timestamp - created_by: { - id: number; // User ID of the commenter - nickname: string; // Nickname of the commenter - is_superuser: boolean; // Whether the commenter is a staff member - }; - updated_at: string; // ISO 8601 timestamp - }[]; - instance: { - app: string; - model: string; - id: string; // UUID of the instance being modified, e.g., presentation ID + created_by: { + id: number; // User ID of the commenter + nickname: string; // Nickname of the commenter + is_superuser: boolean; // Whether the commenter is a staff member }; + updated_at: string; // ISO 8601 timestamp + }[]; + instance: { + app: string; + model: string; + id: string; // UUID of the instance being modified, e.g., presentation ID }; +}; - export type ModificationAuditPreviewSchema = { - modification_audit: ModificationAuditSchema; - original: T; - modified: T; - }; -} - -export default BackendAdminAPISchemas; +export type ModificationAuditPreviewSchema = { + modification_audit: ModificationAuditSchema; + original: T; + modified: T; +}; diff --git a/packages/common/src/schemas/backendParticipantPortalAPI.ts b/packages/common/src/schemas/backendParticipantPortalAPI.ts index f10a1e0..b35339f 100644 --- a/packages/common/src/schemas/backendParticipantPortalAPI.ts +++ b/packages/common/src/schemas/backendParticipantPortalAPI.ts @@ -1,143 +1,139 @@ -namespace BackendParticipantPortalAPISchemas { - export type EmptyObject = Record; - - export type DetailedErrorSchema = { - code: string; - detail: string; - attr: string | null; - }; - - export type ErrorResponseSchema = { - type: string; - errors: DetailedErrorSchema[]; - }; - - export type UserSchema = { - id: number; - email: string; - username: string; - nickname: string | null; - nickname_ko: string | null; - nickname_en: string | null; - image: string | null; // PK of the user's profile image - profile_image: string | null; // URL to the user's profile image - - has_requested_modification_audit: boolean; - requested_modification_audit_id: string | null; - }; - - export type UserUpdateSchema = { - nickname_ko: string | null; - nickname_en: string | null; - image?: string | null; // PK of the user's profile image - }; - - export type UserSignInSchema = { - identity: string; // email - password: string; - }; - - export type UserChangePasswordSchema = { - old_password: string; - new_password: string; - new_password_confirm: string; - }; - - export type PublicFileSchema = { - id: string; // UUID - file: string; // URL to the public file - name: string; // Name of the public file - }; - - export type PresentationRetrieveSchema = { - id: string; // UUID - title: string; // Title of the presentation, translated to the current language - title_ko: string; // Title in Korean - title_en: string; // Title in English - summary: string; // Summary of the presentation, translated to the current language - summary_ko: string; // Summary in Korean - summary_en: string; // Summary in English - description: string; // Description of the presentation, translated to the current language - description_ko: string; // Description in Korean - description_en: string; // Description in English - slideshow_url: string | null; // URL to the presentation's slideshow, if available - image: string | null; // PK of the presentation's image - speakers: { - id: string; // UUID of the speaker - biography_ko: string; // Biography in Korean - biography_en: string; // Biography in English - image: string | null; // PK of the speaker's image - user: { - id: number; // User ID of the speaker - email: string; // Email of the speaker - nickname_ko: string | null; // Nickname in Korean - nickname_en: string | null; // Nickname in English - }; - }[]; - - has_requested_modification_audit: boolean; - requested_modification_audit_id: string | null; - }; - - export type PresentationUpdateSchema = { - id: string; - title_ko: string; - title_en: string; - summary_ko: string; - summary_en: string; - description_ko: string; - description_en: string; - image: string | null; - speakers: { - id: string; // UUID of the speaker - biography_ko: string; // Biography in Korean - biography_en: string; // Biography in English - image: string | null; // PK of the speaker's image - }[]; - }; - - export type ModificationAuditSchema = { - id: string; // UUID - str_repr: string; // String representation of the modification audit, e.g., "Presentation Title - Status" - status: "requested" | "approved" | "rejected" | "cancelled"; // Status of the modification request +export type EmptyObject = Record; + +export type DetailedErrorSchema = { + code: string; + detail: string; + attr: string | null; +}; + +export type ErrorResponseSchema = { + type: string; + errors: DetailedErrorSchema[]; +}; + +export type UserSchema = { + id: number; + email: string; + username: string; + nickname: string | null; + nickname_ko: string | null; + nickname_en: string | null; + image: string | null; // PK of the user's profile image + profile_image: string | null; // URL to the user's profile image + + has_requested_modification_audit: boolean; + requested_modification_audit_id: string | null; +}; + +export type UserUpdateSchema = { + nickname_ko: string | null; + nickname_en: string | null; + image?: string | null; // PK of the user's profile image +}; + +export type UserSignInSchema = { + identity: string; // email + password: string; +}; + +export type UserChangePasswordSchema = { + old_password: string; + new_password: string; + new_password_confirm: string; +}; + +export type PublicFileSchema = { + id: string; // UUID + file: string; // URL to the public file + name: string; // Name of the public file +}; + +export type PresentationRetrieveSchema = { + id: string; // UUID + title: string; // Title of the presentation, translated to the current language + title_ko: string; // Title in Korean + title_en: string; // Title in English + summary: string; // Summary of the presentation, translated to the current language + summary_ko: string; // Summary in Korean + summary_en: string; // Summary in English + description: string; // Description of the presentation, translated to the current language + description_ko: string; // Description in Korean + description_en: string; // Description in English + slideshow_url: string | null; // URL to the presentation's slideshow, if available + image: string | null; // PK of the presentation's image + speakers: { + id: string; // UUID of the speaker + biography_ko: string; // Biography in Korean + biography_en: string; // Biography in English + image: string | null; // PK of the speaker's image + user: { + id: number; // User ID of the speaker + email: string; // Email of the speaker + nickname_ko: string | null; // Nickname in Korean + nickname_en: string | null; // Nickname in English + }; + }[]; + + has_requested_modification_audit: boolean; + requested_modification_audit_id: string | null; +}; + +export type PresentationUpdateSchema = { + id: string; + title_ko: string; + title_en: string; + summary_ko: string; + summary_en: string; + description_ko: string; + description_en: string; + image: string | null; + speakers: { + id: string; // UUID of the speaker + biography_ko: string; // Biography in Korean + biography_en: string; // Biography in English + image: string | null; // PK of the speaker's image + }[]; +}; + +export type ModificationAuditSchema = { + id: string; // UUID + str_repr: string; // String representation of the modification audit, e.g., "Presentation Title - Status" + status: "requested" | "approved" | "rejected" | "cancelled"; // Status of the modification request + created_at: string; // ISO 8601 timestamp + updated_at: string; // ISO 8601 timestamp + + instance_type: T; // Type of the instance being modified (e.g., "presentation") + instance_id: string; // UUID of the instance being modified (e.g., presentation ID) + modification_data: string; // JSON string containing the modification data + + comments: { + id: string; // UUID of the comment + content: string; // Content of the comment created_at: string; // ISO 8601 timestamp + created_by: { + id: number; // User ID of the commenter + nickname: string; // Nickname of the commenter + is_superuser: boolean; // Whether the commenter is a staff member + }; updated_at: string; // ISO 8601 timestamp - - instance_type: T; // Type of the instance being modified (e.g., "presentation") - instance_id: string; // UUID of the instance being modified (e.g., presentation ID) - modification_data: string; // JSON string containing the modification data - - comments: { - id: string; // UUID of the comment - content: string; // Content of the comment - created_at: string; // ISO 8601 timestamp - created_by: { - id: number; // User ID of the commenter - nickname: string; // Nickname of the commenter - is_superuser: boolean; // Whether the commenter is a staff member - }; - updated_at: string; // ISO 8601 timestamp - }[]; - }; - - type ModificationAuditPresentationPreviewSchema = { - modification_audit: ModificationAuditSchema<"presentation">; - original: PresentationRetrieveSchema; - modified: PresentationRetrieveSchema; - }; - - type ModificationAuditUserPreviewSchema = { - modification_audit: ModificationAuditSchema<"userext">; - original: UserSchema; - modified: UserSchema; - }; - - export type ModificationAuditPreviewSchema = ModificationAuditPresentationPreviewSchema | ModificationAuditUserPreviewSchema; - - export type ModificationAuditCancelRequestSchema = { - id: string; // UUID of the modification audit - reason: string | null; // Reason for cancelling the modification request - }; -} - -export default BackendParticipantPortalAPISchemas; + }[]; +}; + +type ModificationAuditPresentationPreviewSchema = { + modification_audit: ModificationAuditSchema<"presentation">; + original: PresentationRetrieveSchema; + modified: PresentationRetrieveSchema; +}; + +type ModificationAuditUserPreviewSchema = { + modification_audit: ModificationAuditSchema<"userext">; + original: UserSchema; + modified: UserSchema; +}; + +export type ModificationAuditPreviewSchema = ModificationAuditPresentationPreviewSchema | ModificationAuditUserPreviewSchema; + +export type ModificationAuditCancelRequestSchema = { + id: string; // UUID of the modification audit + reason: string | null; // Reason for cancelling the modification request +}; diff --git a/packages/common/src/schemas/backendSessionAPI.ts b/packages/common/src/schemas/backendSessionAPI.ts index a9e2cc1..91aac87 100644 --- a/packages/common/src/schemas/backendSessionAPI.ts +++ b/packages/common/src/schemas/backendSessionAPI.ts @@ -1,33 +1,29 @@ -namespace BackendSessionAPISchemas { - export type SessionTypeSchema = { - id: string; - event: string; - name: string; - }; +export type SessionTypeSchema = { + id: string; + event: string; + name: string; +}; - export type SessionCategorySchema = { - id: string; - presentationType: string; - name: string; - }; +export type SessionCategorySchema = { + id: string; + presentationType: string; + name: string; +}; - export type SessionSpeakerSchema = { - id: string; - presentation: string; - user: string; - name: string; - biography: string; - image: string; // DB 반영 필요 - }; +export type SessionSpeakerSchema = { + id: string; + presentation: string; + user: string; + name: string; + biography: string; + image: string; // DB 반영 필요 +}; - export type SessionSchema = { - id: string; - name: string; // DB 반영 필요 - doNotRecord: boolean; // DB 반영 필요 - presentationType: SessionTypeSchema; - presentationCategories: SessionCategorySchema[]; - presentationSpeaker: SessionSpeakerSchema[]; - }; -} - -export default BackendSessionAPISchemas; +export type SessionSchema = { + id: string; + name: string; // DB 반영 필요 + doNotRecord: boolean; // DB 반영 필요 + presentationType: SessionTypeSchema; + presentationCategories: SessionCategorySchema[]; + presentationSpeaker: SessionSpeakerSchema[]; +}; diff --git a/packages/common/src/schemas/index.ts b/packages/common/src/schemas/index.ts index 96569e3..66cfe36 100644 --- a/packages/common/src/schemas/index.ts +++ b/packages/common/src/schemas/index.ts @@ -1,9 +1,3 @@ -import * as _BackendAPISchemas from "./backendAPI"; -import * as _BackendAdminAPISchemas from "./backendAdminAPI"; - -namespace CommonSchemas { - export const BackendAPI = _BackendAPISchemas; - export const BackendAdminAPI = _BackendAdminAPISchemas; -} - -export default CommonSchemas; +export * as BackendAPI from "./backendAPI"; +export * as BackendAdminAPI from "./backendAdminAPI"; +export * as ParticipantPortalAPI from "./backendParticipantPortalAPI"; diff --git a/packages/common/src/utils/index.ts b/packages/common/src/utils/index.ts index 2c44362..1ccc649 100644 --- a/packages/common/src/utils/index.ts +++ b/packages/common/src/utils/index.ts @@ -1,26 +1,5 @@ -import { buildFlatSiteMap as _buildFlatSiteMap, buildNestedSiteMap as _buildNestedSiteMap, parseCss as _parseCss } from "./api"; -import { getCookie as _getCookie } from "./cookie"; -import { getFormValue as _getFormValue, isFormValid as _isFormValid } from "./form"; -import { - filterPropertiesByLanguageInJsonSchema as _filterPropertiesByLanguageInJsonSchema, - filterReadOnlyPropertiesInJsonSchema as _filterReadOnlyPropertiesInJsonSchema, - filterWritablePropertiesInJsonSchema as _filterWritablePropertiesInJsonSchema, -} from "./json_schema"; -import { isFilledString as _isFilledString, isValidHttpUrl as _isValidHttpUrl, rtrim as _rtrim } from "./string"; - -namespace Utils { - export const buildFlatSiteMap = _buildFlatSiteMap; - export const buildNestedSiteMap = _buildNestedSiteMap; - export const parseCss = _parseCss; - export const getCookie = _getCookie; - export const isFormValid = _isFormValid; - export const getFormValue = _getFormValue; - export const isFilledString = _isFilledString; - export const isValidHttpUrl = _isValidHttpUrl; - export const rtrim = _rtrim; - export const filterWritablePropertiesInJsonSchema = _filterWritablePropertiesInJsonSchema; - export const filterReadOnlyPropertiesInJsonSchema = _filterReadOnlyPropertiesInJsonSchema; - export const filterPropertiesByLanguageInJsonSchema = _filterPropertiesByLanguageInJsonSchema; -} - -export default Utils; +export * from "./api"; +export * from "./cookie"; +export * from "./form"; +export * from "./json_schema"; +export * from "./string";