Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -9,8 +9,8 @@ import { addSnackbar } from "../../utils/snackbar";
export const BackendAdminSignInGuard: React.FC<{ children: React.ReactNode }> = ErrorBoundary.with(
{ fallback: <>로그인 정보를 불러오는 중 문제가 발생했습니다.</> },
Suspense.with({ fallback: <CircularProgress /> }, ({ 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");
Expand Down
88 changes: 50 additions & 38 deletions apps/pyconkr-admin/src/components/layouts/admin_editor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
import * as Common from "@frontend/common";
import { Components } from "@frontend/common";
import { retrieve } from "@frontend/common/src/apis/admin_api";
import {
useBackendAdminClient,
useChoicesQuery,
useCreateMutation,
useRemoveMutation,
useSchemaQuery,
useUpdateMutation,
} from "@frontend/common/src/hooks/useAdminAPI";
import {
filterPropertiesByLanguageInJsonSchema,
filterReadOnlyPropertiesInJsonSchema,
filterWritablePropertiesInJsonSchema,
} from "@frontend/common/src/utils";
import { Add, Close, Delete, Edit } from "@mui/icons-material";
import {
Box,
Expand Down Expand Up @@ -132,7 +146,7 @@ const fieldPropsToSelectedProps = (props: FieldProps): OutlinedSelectProps & { d
};

const M2MSelect: Field = ErrorBoundary.with(
{ fallback: Common.Components.ErrorFallback },
{ fallback: Components.ErrorFallback },
Suspense.with({ fallback: <CircularProgress /> }, (props) => {
const selectable = (props.schema.items as JSONSchema7).oneOf as DescriptedEnum[];
const selectableListObj: DescriptedEnumObject = selectable.reduce((a, i) => ({ ...a, [i.const]: i }), {} as DescriptedEnumObject);
Expand Down Expand Up @@ -167,29 +181,26 @@ const MDRendererContainer = styled(Box)(({ theme }) => ({
},
}));

const MDEditorField: Field = ErrorBoundary.with(
{ fallback: Common.Components.ErrorFallback },
({ disabled, formData, name, onChange: rawOnChange }) => {
const [valueState, setValueState] = React.useState<string | undefined>(formData?.toString() || "");
const onChange = (value?: string) => {
setValueState(value);
rawOnChange(value, undefined, name);
};
return (
<MUIStyledFieldset>
<Typography variant="subtitle2" component="legend" children={name} />
<Stack direction="row" spacing={2} sx={{ width: "100%", height: "100%", minHeight: "100%", maxHeight: "100%", flexGrow: 1, py: 2 }}>
<Box sx={{ width: "50%", maxWidth: "50%" }}>
<Common.Components.MarkdownEditor disabled={disabled} name={name} value={valueState} onChange={onChange} extraCommands={[]} />
</Box>
<MDRendererContainer>
<Common.Components.MDXRenderer text={valueState || ""} format="md" />
</MDRendererContainer>
</Stack>
</MUIStyledFieldset>
);
}
);
const MDEditorField: Field = ErrorBoundary.with({ fallback: Components.ErrorFallback }, ({ disabled, formData, name, onChange: rawOnChange }) => {
const [valueState, setValueState] = React.useState<string | undefined>(formData?.toString() || "");
const onChange = (value?: string) => {
setValueState(value);
rawOnChange(value, undefined, name);
};
return (
<MUIStyledFieldset>
<Typography variant="subtitle2" component="legend" children={name} />
<Stack direction="row" spacing={2} sx={{ width: "100%", height: "100%", minHeight: "100%", maxHeight: "100%", flexGrow: 1, py: 2 }}>
<Box sx={{ width: "50%", maxWidth: "50%" }}>
<Components.MarkdownEditor disabled={disabled} name={name} value={valueState} onChange={onChange} extraCommands={[]} />
</Box>
<MDRendererContainer>
<Components.MDXRenderer text={valueState || ""} format="md" />
</MDRendererContainer>
</Stack>
</MUIStyledFieldset>
);
});

type ReadOnlyValueFieldStateType = {
loading: boolean;
Expand Down Expand Up @@ -234,7 +245,7 @@ const ReadOnlyValueField: React.FC<{
)}
{fieldState.blob.type.startsWith("application/json") && fieldState.blobText && (
<Box sx={{ maxWidth: "600px", overflow: "auto" }}>
<Common.Components.LottieDebugPanel data={JSON.parse(fieldState.blobText)} />
<Components.LottieDebugPanel data={JSON.parse(fieldState.blobText)} />
</Box>
)}
<a href={value as string}>링크</a>
Expand All @@ -251,7 +262,7 @@ type InnerAdminEditorStateType = {
};

const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> = ErrorBoundary.with(
{ fallback: Common.Components.ErrorFallback },
{ fallback: Components.ErrorFallback },
Suspense.with(
{ fallback: <CircularProgress /> },
({
Expand All @@ -275,9 +286,10 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> = Err
tab: 0,
formData: undefined,
});
const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient();
const { data: schemaInfo } = Common.Hooks.BackendAdminAPI.useSchemaQuery(backendAdminClient, app, resource);
const { data: choicesData } = Common.Hooks.BackendAdminAPI.useChoicesQuery(backendAdminClient, app, resource);

const backendAdminClient = useBackendAdminClient();
const { data: schemaInfo } = useSchemaQuery(backendAdminClient, app, resource);
const { data: choicesData } = useChoicesQuery(backendAdminClient, app, resource);

// Merge choices into schema for FK/M2M fields
React.useMemo(() => {
Expand All @@ -299,9 +311,9 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> = Err
const selectedLanguage = editorState.tab === 0 ? "ko" : "en";
const notSelectedLanguage = editorState.tab === 0 ? "en" : "ko";

const createMutation = Common.Hooks.BackendAdminAPI.useCreateMutation<Record<string, string>>(backendAdminClient, app, resource);
const modifyMutation = Common.Hooks.BackendAdminAPI.useUpdateMutation<Record<string, string>>(backendAdminClient, app, resource, id || "");
const deleteMutation = Common.Hooks.BackendAdminAPI.useRemoveMutation(backendAdminClient, app, resource, id || "undefined");
const createMutation = useCreateMutation<Record<string, string>>(backendAdminClient, app, resource);
const modifyMutation = useUpdateMutation<Record<string, string>>(backendAdminClient, app, resource, id || "");
const deleteMutation = useRemoveMutation(backendAdminClient, app, resource, id || "undefined");
const submitMutation = id ? modifyMutation : createMutation;

React.useEffect(() => {
Expand All @@ -311,7 +323,7 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> = Err
return;
}

const initialData = await Common.BackendAdminAPIs.retrieve<Record<string, string>>(backendAdminClient, app, resource, id)();
const initialData = await retrieve<Record<string, string>>(backendAdminClient, app, resource, id)();
setFormData({ ...initialData, ...context });
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down Expand Up @@ -359,13 +371,13 @@ const InnerAdminEditor: React.FC<AppResourceIdType & AdminEditorPropsType> = 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
);
Expand Down
17 changes: 10 additions & 7 deletions apps/pyconkr-admin/src/components/layouts/admin_list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as Common from "@frontend/common";
import { Components } from "@frontend/common";
import { useBackendAdminClient, useChoicesQuery, useListQuery, useOpenApiSchemaQuery } from "@frontend/common/src/hooks/useAdminAPI";
import { extractQueryParameters } from "@frontend/common/src/utils";
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";
Expand All @@ -24,22 +26,23 @@ type ListRowType = {
};

const InnerAdminList: React.FC<AdminListProps> = ErrorBoundary.with(
{ fallback: Common.Components.ErrorFallback },
{ fallback: Components.ErrorFallback },
Suspense.with({ fallback: <CircularProgress /> }, ({ app, resource, hideCreatedAt, hideUpdatedAt, hideCreateNew }) => {
const navigate = useNavigate();

const [searchParams, setSearchParams] = useSearchParams();
const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient();
const backendAdminClient = useBackendAdminClient();

const filterParams: Record<string, string> = Object.fromEntries(searchParams.entries());
const listQuery = Common.Hooks.BackendAdminAPI.useListQuery<ListRowType>(backendAdminClient, app, resource, filterParams);
const listQuery = useListQuery<ListRowType>(backendAdminClient, app, resource, filterParams);

const openApiSchemaQuery = Common.Hooks.BackendAdminAPI.useOpenApiSchemaQuery(backendAdminClient);
const openApiSchemaQuery = useOpenApiSchemaQuery(backendAdminClient);
const queryParameters = React.useMemo(
() => Common.Utils.extractQueryParameters(openApiSchemaQuery.data, app, resource),
() => extractQueryParameters(openApiSchemaQuery.data, app, resource),
[openApiSchemaQuery.data, app, resource]
);

const choicesQuery = Common.Hooks.BackendAdminAPI.useChoicesQuery(backendAdminClient, app, resource);
const choicesQuery = useChoicesQuery(backendAdminClient, app, resource);

const handleFilterApply = (newParams: Record<string, string>) => setSearchParams(newParams, { replace: true });

Expand Down
9 changes: 5 additions & 4 deletions apps/pyconkr-admin/src/components/pages/account/account.tsx
Original file line number Diff line number Diff line change
@@ -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: <CircularProgress /> }, () => {
const backendAdminAPIClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient();
const { data } = Common.Hooks.BackendAdminAPI.useSignedInUserQuery(backendAdminAPIClient);
const backendAdminAPIClient = useBackendAdminClient();
const { data } = useSignedInUserQuery(backendAdminAPIClient);

return data ? <Navigate to="/account/manage" replace /> : <Navigate to="/account/sign-in" replace />;
})
Expand Down
16 changes: 9 additions & 7 deletions apps/pyconkr-admin/src/components/pages/account/manage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as Common from "@frontend/common";
import { me } from "@frontend/common/src/apis/admin_api";
import { useBackendAdminClient, useChangePasswordMutation, useSignOutMutation } from "@frontend/common/src/hooks/useAdminAPI";
import { getFormValue, isFormValid } from "@frontend/common/src/utils";
import { Logout } from "@mui/icons-material";
import { Button, Stack, Tab, Tabs, TextField, Typography } from "@mui/material";
import * as React from "react";
Expand All @@ -16,9 +18,9 @@ export const AccountManagementPage: React.FC = () => {
const changePasswordFormRef = React.useRef<HTMLFormElement>(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 }));

Expand All @@ -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<ChangePasswordFormType>({ form });
const formData = getFormValue<ChangePasswordFormType>({ form });
if (formData.new_password !== formData.new_password_confirm) {
addSnackbar("새 비밀번호와 확인 비밀번호가 일치하지 않습니다.", "error");
return;
Expand All @@ -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("/");
Expand Down
12 changes: 7 additions & 5 deletions apps/pyconkr-admin/src/components/pages/account/sign_in.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -16,14 +18,14 @@ export const SignInPage: React.FC = () => {
const [pageState, setPageState] = React.useState<PageStateType>({ 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<HTMLFormElement>) => {
event.preventDefault();
if (!formRef.current) return;

const formData = Common.Utils.getFormValue<{
const formData = getFormValue<{
identity: string;
password: string;
}>({ form: formRef.current });
Expand All @@ -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("/");
Expand Down
6 changes: 3 additions & 3 deletions apps/pyconkr-admin/src/components/pages/file/upload.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -25,8 +25,8 @@ const InnerPublicFileUploadPage: React.FC = () => {
});
const fileInputRef = React.useRef<HTMLInputElement>(null);
const fileDragBoxRef = React.useRef<HTMLDivElement>(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(
() =>
Expand Down
Loading