From 40d4190e6fbf43a6eb4888ae22ace2231edbfa15 Mon Sep 17 00:00:00 2001 From: wangsijie Date: Tue, 12 Apr 2022 17:09:40 +0800 Subject: [PATCH] feat(console): add experience form fields --- .../components/BrandingForm.tsx | 70 ++++++++++++++ .../SignInExperience/components/TermsForm.tsx | 34 +++++++ .../components/index.module.scss | 7 ++ .../pages/SignInExperience/index.module.scss | 2 + .../src/pages/SignInExperience/index.tsx | 94 +++++++++++++++---- packages/phrases/src/locales/en.ts | 9 +- packages/phrases/src/locales/zh-cn.ts | 9 +- 7 files changed, 201 insertions(+), 24 deletions(-) create mode 100644 packages/console/src/pages/SignInExperience/components/BrandingForm.tsx create mode 100644 packages/console/src/pages/SignInExperience/components/TermsForm.tsx create mode 100644 packages/console/src/pages/SignInExperience/components/index.module.scss diff --git a/packages/console/src/pages/SignInExperience/components/BrandingForm.tsx b/packages/console/src/pages/SignInExperience/components/BrandingForm.tsx new file mode 100644 index 000000000..57b15a381 --- /dev/null +++ b/packages/console/src/pages/SignInExperience/components/BrandingForm.tsx @@ -0,0 +1,70 @@ +import { BrandingStyle, SignInExperience } from '@logto/schemas'; +import React from 'react'; +import { Control, Controller, UseFormRegister, UseFormWatch } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; + +import FormField from '@/components/FormField'; +import RadioGroup, { Radio } from '@/components/RadioGroup'; +import TextInput from '@/components/TextInput'; + +import * as styles from './index.module.scss'; + +type Props = { + register: UseFormRegister; + control: Control; + watch: UseFormWatch; +}; + +const BrandingForm = ({ register, control, watch }: Props) => { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + + const isDarkModeEnabled = watch('branding.isDarkModeEnabled'); + const style = watch('branding.style'); + const isSloganRequired = style === BrandingStyle.Logo_Slogan; + + return ( + <> +
{t('sign_in_exp.branding.title')}
+ + {/* TODO: LOG-1733 color-picker */} + + + + {/* TODO: LOG-2152 switch */} + +
{t('sign_in_exp.branding.dark_mode_description')}
+
+ + {/* TODO: LOG-1733 color-picker */} + + + + {/* TODO: LOG-2153 plain radio */} + ( + + + {t('sign_in_exp.branding.styles.logo_slogan')} + + {t('sign_in_exp.branding.styles.logo')} + + )} + /> + + + + + + + + + ); +}; + +export default BrandingForm; diff --git a/packages/console/src/pages/SignInExperience/components/TermsForm.tsx b/packages/console/src/pages/SignInExperience/components/TermsForm.tsx new file mode 100644 index 000000000..4eda77c15 --- /dev/null +++ b/packages/console/src/pages/SignInExperience/components/TermsForm.tsx @@ -0,0 +1,34 @@ +import { SignInExperience } from '@logto/schemas'; +import React from 'react'; +import { UseFormRegister, UseFormWatch } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; + +import FormField from '@/components/FormField'; +import TextInput from '@/components/TextInput'; + +import * as styles from './index.module.scss'; + +type Props = { + register: UseFormRegister; + watch: UseFormWatch; +}; + +const TermsForm = ({ register, watch }: Props) => { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const enabled = watch('termsOfUse.enabled'); + + return ( + <> +
{t('sign_in_exp.terms_of_use.title')}
+ + +
{t('sign_in_exp.terms_of_use.description')}
+
+ + + + + ); +}; + +export default TermsForm; diff --git a/packages/console/src/pages/SignInExperience/components/index.module.scss b/packages/console/src/pages/SignInExperience/components/index.module.scss new file mode 100644 index 000000000..6935a1dbc --- /dev/null +++ b/packages/console/src/pages/SignInExperience/components/index.module.scss @@ -0,0 +1,7 @@ +@use '@/scss/underscore' as _; + +.title { + color: var(--color-neutral-variant-60); + font: var(--font-subhead-cap); + margin-top: _.unit(8); +} diff --git a/packages/console/src/pages/SignInExperience/index.module.scss b/packages/console/src/pages/SignInExperience/index.module.scss index 2e2bbd2c6..8fd883b8f 100644 --- a/packages/console/src/pages/SignInExperience/index.module.scss +++ b/packages/console/src/pages/SignInExperience/index.module.scss @@ -7,6 +7,8 @@ .setup { flex: 1; margin-right: _.unit(3); + height: 100%; + overflow-y: auto; .tabs { padding-top: _.unit(2); diff --git a/packages/console/src/pages/SignInExperience/index.tsx b/packages/console/src/pages/SignInExperience/index.tsx index 8f9f9831e..897b735d6 100644 --- a/packages/console/src/pages/SignInExperience/index.tsx +++ b/packages/console/src/pages/SignInExperience/index.tsx @@ -1,36 +1,94 @@ -import classNames from 'classnames'; -import React from 'react'; +import { SignInExperience as SignInExperienceType } from '@logto/schemas'; +import React, { useEffect } from 'react'; +import { useForm } from 'react-hook-form'; +import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router-dom'; +import useSWR from 'swr'; import Button from '@/components/Button'; import Card from '@/components/Card'; import CardTitle from '@/components/CardTitle'; import TabNav, { TabNavLink } from '@/components/TabNav'; +import useApi, { RequestError } from '@/hooks/use-api'; import * as detailsStyles from '@/scss/details.module.scss'; +import BrandingForm from './components/BrandingForm'; +import TermsForm from './components/TermsForm'; import * as styles from './index.module.scss'; const SignInExperience = () => { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const { tab } = useParams(); + const { data, error, mutate } = useSWR('/api/sign-in-exp'); + const { + reset, + control, + handleSubmit, + register, + watch, + formState: { isSubmitting }, + } = useForm(); + const api = useApi(); + + useEffect(() => { + if (data) { + reset(data); + } + }, [data, reset]); + + const onSubmit = handleSubmit(async (formData) => { + if (!data || isSubmitting) { + return; + } + + const updatedData = await api + .patch(`/api/applications/${data.id}`, { + json: { + ...formData, + }, + }) + .json(); + void mutate(updatedData); + toast.success(t('application_details.save_success')); + }); return (
- - - - - {t('sign_in_exp.tabs.experience')} - - - {t('sign_in_exp.tabs.methods')} - - {t('sign_in_exp.tabs.others')} - -
TODO
-
-
-
+
+ + + + + {t('sign_in_exp.tabs.experience')} + + + {t('sign_in_exp.tabs.methods')} + + + {t('sign_in_exp.tabs.others')} + + + {!data && !error &&
loading
} + {error &&
{`error occurred: ${error.body.message}`}
} + {data && ( +
+ {tab === 'experience' && ( + + )} + {tab === 'experience' && } +
+
+ + )} +
+
TODO
); diff --git a/packages/phrases/src/locales/en.ts b/packages/phrases/src/locales/en.ts index bfa931236..e0ea7f992 100644 --- a/packages/phrases/src/locales/en.ts +++ b/packages/phrases/src/locales/en.ts @@ -328,12 +328,15 @@ const translation = { branding: { title: 'BRANDING', primary_color: 'Primary color', - dark_mode: 'Enable dark mode', + dark_primary_color: 'Primary color (Dark)', + dark_mode: 'Enable Dark Mode', dark_mode_description: 'Enabling this setting will auto generate the dark mode color. You app won’t have dark mode if it’s turned off.', ui_style: 'Define your UI style', - app_logo: 'App Logo', - text: 'Text', + styles: { + logo_slogan: 'Logo + slogan', + logo: 'Logo', + }, logo_image_url: 'Logo image URL', slogan: 'Slogan', slogan_placeholder: 'Unleash your creativity', diff --git a/packages/phrases/src/locales/zh-cn.ts b/packages/phrases/src/locales/zh-cn.ts index b021bbd6c..2e7271122 100644 --- a/packages/phrases/src/locales/zh-cn.ts +++ b/packages/phrases/src/locales/zh-cn.ts @@ -324,12 +324,15 @@ const translation = { branding: { title: 'BRANDING', primary_color: 'Primary color', - dark_mode: 'Enable dark mode', + dark_primary_color: 'Primary color (Dark)', + dark_mode: 'Enable Dark Mode', dark_mode_description: 'Enabling this setting will auto generate the dark mode color. You app won’t have dark mode if it’s turned off.', ui_style: 'Define your UI style', - app_logo: 'App Logo', - text: 'Text', + styles: { + logo_slogan: 'Logo + slogan', + logo: 'Logo', + }, logo_image_url: 'Logo image URL', slogan: 'Slogan', slogan_placeholder: 'Unleash your creativity',