feat: onboarding pages darkmode (#867)

This commit is contained in:
Ahmed Bouhuolia
2025-12-03 16:04:46 +02:00
committed by GitHub
parent 71b1206f8a
commit 32d74b0413
15 changed files with 386 additions and 289 deletions

View File

@@ -1,6 +1,9 @@
// @ts-nocheck
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { x } from '@xstyled/emotion';
import { css } from '@emotion/css';
import { useIsDarkMode } from '@/hooks/useDarkMode';
import WorkflowIcon from './WorkflowIcon';
import { FormattedMessage as T } from '@/components';
@@ -8,13 +11,12 @@ import { FormattedMessage as T } from '@/components';
import withOrganizationActions from '@/containers/Organization/withOrganizationActions';
import { compose } from '@/utils';
import '@/style/pages/Setup/Congrats.scss';
/**
* Setup congrats page.
*/
function SetupCongratsPage({ setOrganizationSetupCompleted }) {
const [isReloading, setIsReloading] = React.useState(false);
const isDarkMode = useIsDarkMode();
const handleBtnClick = () => {
setIsReloading(true);
@@ -22,30 +24,55 @@ function SetupCongratsPage({ setOrganizationSetupCompleted }) {
};
return (
<div class="setup-congrats">
<div class="setup-congrats__workflow-pic">
<x.div
w={'500px'}
mx="auto"
textAlign="center"
pt={'80px'}
>
<x.div>
<WorkflowIcon width="280" height="330" />
</div>
</x.div>
<div class="setup-congrats__text">
<h1>
<T id={'setup.congrats.title'} />
</h1>
<p class="paragraph">
<T id={'setup.congrats.description'} />
</p>
<Button
intent={Intent.PRIMARY}
type="submit"
loading={isReloading}
onClick={handleBtnClick}
<x.div mt={30}>
<x.h2
color={isDarkMode ? 'rgba(255, 255, 255, 0.85)' : '#2d2b43'}
mb={'12px'}
>
<T id={'setup.congrats.go_to_dashboard'} />
</Button>
</div>
</div>
<T id={'setup.congrats.title'} />
</x.h2>
<x.p
fontSize={'16px'}
opacity={0.85}
mb={'14px'}
color={isDarkMode ? 'rgba(255, 255, 255, 0.7)' : undefined}
>
<T id={'setup.congrats.description'} />
</x.p>
<x.div
className={css`
.bp4-button {
height: 38px;
padding-left: 25px;
padding-right: 25px;
font-size: 15px;
margin-top: 12px;
}
`}
>
<Button
intent={Intent.PRIMARY}
type="submit"
loading={isReloading}
onClick={handleBtnClick}
>
<T id={'setup.congrats.go_to_dashboard'} />
</Button>
</x.div>
</x.div>
</x.div>
);
}

View File

@@ -2,6 +2,9 @@
import React from 'react';
import { ProgressBar, Intent } from '@blueprintjs/core';
import * as R from 'ramda';
import { x } from '@xstyled/emotion';
import { css } from '@emotion/css';
import { useIsDarkMode } from '@/hooks/useDarkMode';
import { useJob, useCurrentOrganization } from '@/hooks/query';
import { FormattedMessage as T } from '@/components';
@@ -10,8 +13,6 @@ import withOrganizationActions from '@/containers/Organization/withOrganizationA
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
import withOrganization from '../Organization/withOrganization';
import '@/style/pages/Setup/Initializing.scss';
/**
* Setup initializing step form.
*/
@@ -47,7 +48,7 @@ function SetupInitializingForm({
}, [setOrganizationSetupCompleted, isJobDone, isSuccess]);
return (
<div class="setup-initializing-form">
<x.div w="95%" mx="auto" pt="16%">
{isFailed ? (
<SetupInitializingFailed />
) : isRunning || isWaiting || isJobFetching ? (
@@ -57,7 +58,7 @@ function SetupInitializingForm({
) : (
<SetupInitializingFailed />
)}
</div>
</x.div>
);
}
@@ -73,17 +74,29 @@ export default R.compose(
* State initializing failed state.
*/
function SetupInitializingFailed() {
const isDarkMode = useIsDarkMode();
return (
<div class="setup-initializing__content">
<div className={'setup-initializing-form__title'}>
<h1>
<x.div>
<x.div textAlign="center" mt={35}>
<x.h1
fontSize={'22px'}
fontWeight={500}
color={isDarkMode ? 'rgba(255, 255, 255, 0.75)' : '#454c59'}
mt={0}
mb={'14px'}
>
<T id={'setup.initializing.something_went_wrong'} />
</h1>
<p class="paragraph">
</x.h1>
<x.p
w="70%"
mx="auto"
color={isDarkMode ? 'rgba(255, 255, 255, 0.7)' : '#2e4266'}
>
<T id={'setup.initializing.please_refresh_the_page'} />
</p>
</div>
</div>
</x.p>
</x.div>
</x.div>
);
}
@@ -91,19 +104,49 @@ function SetupInitializingFailed() {
* Setup initializing running state.
*/
function SetupInitializingRunning() {
return (
<div class="setup-initializing__content">
<ProgressBar intent={Intent.PRIMARY} value={null} />
const isDarkMode = useIsDarkMode();
<div className={'setup-initializing-form__title'}>
<h1>
const progressBarStyles = css`
.bp4-progress-bar {
border-radius: 40px;
display: block;
height: 6px;
overflow: hidden;
position: relative;
width: 80%;
margin: 0 auto;
.bp4-progress-meter {
background-color: #809cb3;
}
}
`;
return (
<x.div>
<x.div className={progressBarStyles}>
<ProgressBar intent={Intent.NONE} value={null} />
</x.div>
<x.div textAlign="center" mt={35}>
<x.h1
fontSize={'22px'}
fontWeight={500}
color={isDarkMode ? 'rgba(255, 255, 255, 0.85)' : '#454c59'}
mt={0}
mb={'14px'}
>
<T id={'setup.initializing.title'} />
</h1>
<p className={'paragraph'}>
</x.h1>
<x.p
w="70%"
mx="auto"
color={isDarkMode ? 'rgba(255, 255, 255, 0.7)' : '#2e4266'}
>
<T id={'setup.initializing.description'} />
</p>
</div>
</div>
</x.p>
</x.div>
</x.div>
);
}
@@ -111,18 +154,30 @@ function SetupInitializingRunning() {
* Setup initializing completed state.
*/
function SetupInitializingCompleted() {
const isDarkMode = useIsDarkMode();
return (
<div class="setup-initializing__content">
<div className={'setup-initializing-form__title'}>
<h1>
<x.div>
<x.div textAlign="center" mt={35}>
<x.h1
fontSize={'22px'}
fontWeight={600}
color={isDarkMode ? 'rgba(255, 255, 255, 0.85)' : '#454c59'}
mt={0}
mb={'14px'}
>
<T id={'setup.initializing.waiting_to_redirect'} />
</h1>
<p class="paragraph">
</x.h1>
<x.p
w="70%"
mx="auto"
color={isDarkMode ? 'rgba(255, 255, 255, 0.7)' : '#2e4266'}
>
<T
id={'setup.initializing.refresh_the_page_if_redirect_not_worked'}
/>
</p>
</div>
</div>
</x.p>
</x.div>
</x.div>
);
}

View File

@@ -5,15 +5,18 @@ import { Button, Intent, FormGroup, Classes } from '@blueprintjs/core';
import classNames from 'classnames';
import { TimezonePicker } from '@blueprintjs/timezone';
import { getAllCountries } from '@bigcapital/utils';
import { x } from '@xstyled/emotion';
import {
FFormGroup,
FInputGroup,
FSelect,
FTimezoneSelect,
FormattedMessage as T,
} from '@/components';
import { Col, Row } from '@/components';
import { inputIntent } from '@/utils';
import { useIsDarkMode } from '@/hooks/useDarkMode';
import { getFiscalYear } from '@/constants/fiscalYearOptions';
import { getLanguages } from '@/constants/languagesOptions';
@@ -28,19 +31,24 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
const FiscalYear = getFiscalYear();
const Languages = getLanguages();
const currencies = getAllCurrenciesOptions();
const isDarkMode = useIsDarkMode();
return (
<Form>
<h3>
<x.h3
color={isDarkMode ? 'rgba(255, 255, 255, 0.5)' : '#868f9f'}
mb="2rem"
fontWeight={600}
>
<T id={'organization_details'} />
</h3>
</x.h3>
{/* ---------- Organization name ---------- */}
<FFormGroup
name={'name'}
label={<T id={'legal_organization_name'} />}
fastField={true}
fastField
>
<FInputGroup name={'name'} fastField={true} />
<FInputGroup name={'name'} large fastField />
</FFormGroup>
{/* ---------- Location ---------- */}
@@ -56,7 +64,8 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
textAccessor={'name'}
placeholder={<T id={'select_business_location'} />}
popoverProps={{ minimal: true }}
fastField={true}
buttonProps={{ large: true }}
fastField
/>
</FFormGroup>
@@ -75,18 +84,15 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
valueAccessor={'key'}
textAccessor={'name'}
placeholder={<T id={'select_base_currency'} />}
fastField={true}
buttonProps={{ large: true }}
fastField
/>
</FFormGroup>
</Col>
{/* ---------- Language ---------- */}
<Col xs={6}>
<FFormGroup
name={'language'}
label={<T id={'language'} />}
fastField={true}
>
<FFormGroup name={'language'} label={<T id={'language'} />} fastField>
<FSelect
name={'language'}
items={Languages}
@@ -94,7 +100,8 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
textAccessor={'name'}
placeholder={<T id={'select_language'} />}
popoverProps={{ minimal: true }}
fastField={true}
buttonProps={{ large: true }}
fastField
/>
</FFormGroup>
</Col>
@@ -104,7 +111,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
<FFormGroup
name={'fiscalYear'}
label={<T id={'fiscal_year'} />}
fastField={true}
fastField
>
<FSelect
name={'fiscalYear'}
@@ -113,50 +120,48 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
textAccessor={'name'}
placeholder={<T id={'select_fiscal_year'} />}
popoverProps={{ minimal: true }}
fastField={true}
buttonProps={{ large: true }}
fastField
/>
</FFormGroup>
{/* ---------- Time zone ---------- */}
<FastField name={'timezone'}>
{({
form: { setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={<T id={'time_zone'} />}
className={classNames(
'form-group--time-zone',
'form-group--select-list',
Classes.FILL,
)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'timezone'} />}
>
<TimezonePicker
value={value}
onChange={(item) => {
setFieldValue('timezone', item);
}}
valueDisplayFormat="composite"
showLocalTimezone={true}
placeholder={<T id={'select_time_zone'} />}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</FastField>
<FFormGroup name={'timezone'} label={<T id={'time_zone'} />}>
<FTimezoneSelect
name={'timezone'}
valueDisplayFormat="composite"
showLocalTimezone={true}
placeholder={<T id={'select_time_zone'} />}
popoverProps={{ minimal: true }}
buttonProps={{
alignText: 'left',
fill: true,
large: true,
}}
/>
</FFormGroup>
<p className={'register-org-note'}>
<x.p
fontSize={14}
lineHeight="2.7rem"
mb={6}
borderBottom={`1px solid ${isDarkMode ? 'rgba(255, 255, 255, 0.1)' : '#f5f5f5'}`}
className={Classes.TEXT_MUTED}
>
<T id={'setup.organization.note_you_can_change_your_preferences'} />
</p>
</x.p>
<div className={'register-org-button'}>
<Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit">
<x.div>
<Button
intent={Intent.PRIMARY}
loading={isSubmitting}
fill
large
type="submit"
>
<T id={'save_continue'} />
</Button>
</div>
</x.div>
</Form>
);
}

View File

@@ -2,16 +2,15 @@
import React from 'react';
import { Formik } from 'formik';
import { FormattedMessage as T } from '@/components';
import '@/style/pages/Setup/Organization.scss';
import { x } from '@xstyled/emotion';
import SetupOrganizationForm from './SetupOrganizationForm';
import { useOrganizationSetup } from '@/hooks/query';
import withSettingsActions from '@/containers/Settings/withSettingsActions';
import { setCookie, compose, transfromToSnakeCase } from '@/utils';
import { getSetupOrganizationValidation } from './SetupOrganization.schema';
import { setCookie, compose, transfromToSnakeCase } from '@/utils';
// Initial values.
const defaultValues = {
@@ -53,17 +52,22 @@ function SetupOrganizationPage({ wizard }) {
};
return (
<div className={'setup-organization'}>
<x.div
maxWidth={'600px'}
w="100%"
mx="auto"
pt={'45px'}
pb={'20px'}
px={'25px'}
>
<Formik
validationSchema={validationSchema}
initialValues={initialValues}
component={SetupOrganizationForm}
onSubmit={handleSubmit}
/>
</div>
</x.div>
);
}
export default compose(
withSettingsActions,
)(SetupOrganizationPage);
export default compose(withSettingsActions)(SetupOrganizationPage);

View File

@@ -1,5 +1,6 @@
// @ts-nocheck
import React from 'react';
import { x } from '@xstyled/emotion';
import SetupWizardContent from './SetupWizardContent';
@@ -27,9 +28,9 @@ function SetupRightSection({
isSubscriptionActive,
}) {
return (
<section className={'setup-page__right-section'}>
<x.section w="100%" overflow="auto">
<SetupWizardContent stepId={setupStepId} stepIndex={setupStepIndex} />
</section>
</x.section>
);
}

View File

@@ -1,3 +0,0 @@
.items {
padding: 40px 40px 20px;
}

View File

@@ -1,18 +1,23 @@
// @ts-nocheck
import React from 'react';
import { x } from '@xstyled/emotion';
import { css } from '@emotion/css';
import SetupSubscription from './SetupSubscription/SetupSubscription';
import SetupOrganizationPage from './SetupOrganizationPage';
import SetupInitializingForm from './SetupInitializingForm';
import SetupCongratsPage from './SetupCongratsPage';
import { Stepper } from '@/components/Stepper';
import styles from './SetupWizardContent.module.scss';
interface SetupWizardContentProps {
stepIndex: number;
stepId: string;
}
const itemsClassName = css`
padding: 40px 40px 20px;
`;
/**
* Setup wizard content.
*/
@@ -21,12 +26,11 @@ export default function SetupWizardContent({
stepId,
}: SetupWizardContentProps) {
return (
<div class="setup-page__content">
<x.div w="100%" overflow="auto">
<Stepper
active={stepIndex}
classNames={{
content: styles.content,
items: styles.items,
items: itemsClassName,
}}
>
<Stepper.Step label={'Subscription'}>
@@ -45,6 +49,6 @@ export default function SetupWizardContent({
<SetupCongratsPage id="congrats" />
</Stepper.Step>
</Stepper>
</div>
</x.div>
);
}