2022-07-11 17:28:51 +08:00
|
|
|
import { AdminConsoleKey } from '@logto/phrases';
|
2022-06-27 20:10:27 +08:00
|
|
|
import { Application } from '@logto/schemas';
|
2022-07-15 18:01:42 +08:00
|
|
|
import { useRef, KeyboardEvent } from 'react';
|
2022-06-27 20:10:27 +08:00
|
|
|
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
2022-06-29 10:26:04 +08:00
|
|
|
import { toast } from 'react-hot-toast';
|
2022-06-27 20:10:27 +08:00
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import useSWR from 'swr';
|
|
|
|
|
|
|
|
import Button from '@/components/Button';
|
|
|
|
import FormField from '@/components/FormField';
|
|
|
|
import MultiTextInput from '@/components/MultiTextInput';
|
|
|
|
import { convertRhfErrorMessage, createValidatorForRhf } from '@/components/MultiTextInput/utils';
|
|
|
|
import TextInput from '@/components/TextInput';
|
|
|
|
import useApi, { RequestError } from '@/hooks/use-api';
|
|
|
|
import { GuideForm } from '@/types/guide';
|
|
|
|
import { uriValidator } from '@/utilities/validator';
|
|
|
|
|
|
|
|
import * as styles from './index.module.scss';
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
appId: string;
|
|
|
|
name: 'redirectUris' | 'postLogoutRedirectUris';
|
2022-07-11 17:28:51 +08:00
|
|
|
title: AdminConsoleKey;
|
2022-06-27 20:10:27 +08:00
|
|
|
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);
|
2022-06-29 10:26:04 +08:00
|
|
|
toast.success(t('general.saved'));
|
2022-06-27 20:10:27 +08:00
|
|
|
|
|
|
|
// 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>
|
2022-07-08 22:02:01 +08:00
|
|
|
<FormField isRequired={name === 'redirectUris'} className={styles.field} title={title}>
|
2022-06-27 20:10:27 +08:00
|
|
|
<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 && (
|
|
|
|
<TextInput
|
|
|
|
className={styles.field}
|
|
|
|
value={value[0]}
|
|
|
|
errorMessage={errorObject?.required ?? errorObject?.inputs?.[0]}
|
|
|
|
onChange={({ currentTarget: { value } }) => {
|
|
|
|
onChange([value]);
|
|
|
|
}}
|
|
|
|
onKeyPress={(event) => {
|
|
|
|
onKeyPress(event, value);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{!isSingle && (
|
|
|
|
<MultiTextInput
|
|
|
|
title={title}
|
|
|
|
value={value}
|
|
|
|
error={errorObject}
|
|
|
|
onChange={onChange}
|
|
|
|
onKeyPress={(event) => {
|
|
|
|
onKeyPress(event, value);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<Button
|
|
|
|
className={styles.saveButton}
|
|
|
|
disabled={!isDirty}
|
|
|
|
isLoading={isSubmitting}
|
2022-07-11 17:28:51 +08:00
|
|
|
title="general.save"
|
2022-06-27 20:10:27 +08:00
|
|
|
type="primary"
|
|
|
|
onClick={handleSubmit(async () => onSubmit(value))}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</FormField>
|
|
|
|
</form>
|
|
|
|
</FormProvider>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default UriInputField;
|