mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(console): add custom domain form (#3962)
This commit is contained in:
parent
0c1744e77d
commit
6fcc2a875c
4 changed files with 128 additions and 2 deletions
|
@ -0,0 +1,15 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.addDomain {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
.textInput {
|
||||
flex: 1;
|
||||
margin-right: _.unit(3);
|
||||
}
|
||||
|
||||
.addButton {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
import { type Domain } from '@logto/schemas';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Button from '@/components/Button';
|
||||
import TextInput from '@/components/TextInput';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import { onKeyDownHandler } from '@/utils/a11y';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const subdomainRegex = /^[\dA-Za-z][\dA-Za-z-]*[\dA-Za-z](\.[\dA-Za-z][\dA-Za-z-]*[\dA-Za-z]){2,}$/;
|
||||
|
||||
type FormData = {
|
||||
domain: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
onCustomDomainAdded: (domain: Domain) => void;
|
||||
};
|
||||
|
||||
function AddDomainForm({ onCustomDomainAdded }: Props) {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const {
|
||||
register,
|
||||
watch,
|
||||
formState: { errors, isSubmitting },
|
||||
handleSubmit,
|
||||
} = useForm<FormData>({
|
||||
defaultValues: {
|
||||
domain: '',
|
||||
},
|
||||
});
|
||||
|
||||
const domainInput = watch('domain');
|
||||
|
||||
const api = useApi();
|
||||
|
||||
const onSubmit = handleSubmit(async (formData) => {
|
||||
const createdDomain = await api.post('api/domains', { json: formData }).json<Domain>();
|
||||
onCustomDomainAdded(createdDomain);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.addDomain}>
|
||||
<TextInput
|
||||
className={styles.textInput}
|
||||
placeholder={t('domain.custom.custom_domain_placeholder')}
|
||||
error={errors.domain?.message}
|
||||
onKeyDown={onKeyDownHandler({ Enter: onSubmit })}
|
||||
{...register('domain', {
|
||||
required: true,
|
||||
pattern: {
|
||||
value: subdomainRegex,
|
||||
message: t('domain.custom.invalid_domain_format'),
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<Button
|
||||
className={styles.addButton}
|
||||
type="primary"
|
||||
title="domain.custom.add_domain"
|
||||
isLoading={isSubmitting}
|
||||
disabled={domainInput.length === 0}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddDomainForm;
|
|
@ -0,0 +1,7 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.container {
|
||||
> div:not(:first-child) {
|
||||
margin-top: _.unit(4);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,45 @@
|
|||
import { type Domain } from '@logto/schemas';
|
||||
import { conditional } from '@silverhand/essentials';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import FormCard from '@/components/FormCard';
|
||||
import FormField from '@/components/FormField';
|
||||
import { type RequestError } from '@/hooks/use-api';
|
||||
|
||||
import AddDomainForm from './components/AddDomainForm';
|
||||
import DefaultDomain from './components/DefaultDomain';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
function TenantDomainSettings() {
|
||||
// Todo: @xiaoyijun setup the auto refresh interval for the domains when implementing the active domain process.
|
||||
const { data, error, mutate } = useSWR<Domain[], RequestError>('api/domains');
|
||||
const isLoading = !data && !error;
|
||||
/**
|
||||
* Note: we can only create a custom domain, and we don't have a default id for it, so the first element of the array is the custom domain.
|
||||
*/
|
||||
const customDomain = conditional(!isLoading && data)?.[0];
|
||||
|
||||
if (isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* TODO: @xiaoyijun add the custom domain form card */}
|
||||
<div className={styles.container}>
|
||||
<FormCard
|
||||
title="domain.custom.custom_domain"
|
||||
description="domain.custom.custom_domain_description"
|
||||
>
|
||||
<FormField title="domain.custom.custom_domain_field">
|
||||
{!customDomain && (
|
||||
<AddDomainForm
|
||||
onCustomDomainAdded={(domain) => {
|
||||
void mutate([domain]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* TODO @xiaoyijun add custom domain content if a custom domain is created */}
|
||||
</FormField>
|
||||
</FormCard>
|
||||
<FormCard
|
||||
title="domain.default.default_domain"
|
||||
description="domain.default.default_domain_description"
|
||||
|
|
Loading…
Reference in a new issue