0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-20 21:32:31 -05:00
logto/packages/console/src/mdx-components/UriInputField/index.tsx

144 lines
4.6 KiB
TypeScript
Raw Normal View History

2022-10-21 13:14:17 +08:00
import type { AdminConsoleKey } from '@logto/phrases';
import type { Application } from '@logto/schemas';
import type { KeyboardEvent } from 'react';
import { useRef } from 'react';
import { Controller, FormProvider, useForm } from 'react-hook-form';
import { toast } from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
import useSWR from 'swr';
import Button from '@/components/Button';
import FormField from '@/components/FormField';
import { convertRhfErrorMessage, createValidatorForRhf } from '@/components/MultiTextInput/utils';
import MultiTextInputField from '@/components/MultiTextInputField';
import TextInput from '@/components/TextInput';
2022-10-21 13:14:17 +08:00
import type { RequestError } from '@/hooks/use-api';
import useApi from '@/hooks/use-api';
import type { GuideForm } from '@/types/guide';
2023-02-15 10:26:22 +08:00
import { uriValidator } from '@/utils/validator';
import * as styles from './index.module.scss';
type Props = {
appId: string;
name: 'redirectUris' | 'postLogoutRedirectUris';
title: AdminConsoleKey;
isSingle?: boolean;
};
const UriInputField = ({ appId, name, title, isSingle = false }: Props) => {
const methods = useForm<Partial<GuideForm>>();
const {
control,
getValues,
handleSubmit,
reset,
formState: { isSubmitting },
} = methods;
const { data, mutate } = useSWR<Application, RequestError>(`api/applications/${appId}`);
const ref = useRef<HTMLDivElement>(null);
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const api = useApi();
const onSubmit = async (value: string[]) => {
const updatedApp = await api
.patch(`api/applications/${appId}`, {
json: {
oidcClientMetadata: {
[name]: value.filter(Boolean),
},
},
})
.json<Application>();
void mutate(updatedApp);
toast.success(t('general.saved'));
// Reset form to set 'isDirty' to false
reset(getValues());
};
const onKeyPress = (event: KeyboardEvent<HTMLInputElement>, value: string[]) => {
if (event.key === 'Enter') {
event.preventDefault();
void handleSubmit(async () => onSubmit(value))();
}
};
return (
<FormProvider {...methods}>
<form>
<Controller
name={name}
control={control}
defaultValue={data?.oidcClientMetadata[name]}
rules={{
validate: createValidatorForRhf({
required: t(
isSingle ? 'errors.required_field_missing' : 'errors.required_field_missing_plural',
{ field: title }
),
pattern: {
verify: (value) => !value || uriValidator(value),
message: t('errors.invalid_uri_format'),
},
}),
}}
render={({ field: { onChange, value = [] }, fieldState: { error, isDirty } }) => {
const errorObject = convertRhfErrorMessage(error?.message);
return (
<div ref={ref} className={styles.wrapper}>
{isSingle && (
<FormField
isRequired={name === 'redirectUris'}
className={styles.field}
title={title}
>
<TextInput
className={styles.field}
value={value[0]}
errorMessage={errorObject?.required ?? errorObject?.inputs?.[0]}
onChange={({ currentTarget: { value } }) => {
onChange([value]);
}}
onKeyPress={(event) => {
onKeyPress(event, value);
}}
/>
</FormField>
)}
{!isSingle && (
<MultiTextInputField
isRequired={name === 'redirectUris'}
formFieldClassName={styles.field}
title={title}
value={value}
error={errorObject}
className={styles.multiTextInput}
onChange={onChange}
onKeyPress={(event) => {
onKeyPress(event, value);
}}
/>
)}
<Button
className={styles.saveButton}
disabled={!isDirty}
isLoading={isSubmitting}
title="general.save"
type="primary"
onClick={handleSubmit(async () => onSubmit(value))}
/>
</div>
);
}}
/>
</form>
</FormProvider>
);
};
export default UriInputField;