TryGhost/Ghost

View on GitHub
apps/admin-x-settings/src/components/settings/general/TimeZone.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
import React, {useEffect, useState} from 'react';
import TopLevelGroup from '../../TopLevelGroup';
import timezoneData from '@tryghost/timezone-data';
import useSettingGroup from '../../../hooks/useSettingGroup';
import {Select, SettingGroupContent, withErrorBoundary} from '@tryghost/admin-x-design-system';
import {getLocalTime} from '../../../utils/helpers';
import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';

interface TimezoneDataDropdownOption {
    name: string;
    label: string;
}

interface HintProps {
    timezone: string;
}

const Hint: React.FC<HintProps> = ({timezone}) => {
    const [currentTime, setCurrentTime] = useState(getLocalTime(timezone));

    useEffect(() => {
        const timer = setInterval(() => {
            setCurrentTime(getLocalTime(timezone));
        }, 1000);

        return () => {
            clearInterval(timer);
        };
    }, [timezone]);
    return (
        <>
            The local time here is currently {currentTime}
        </>
    );
};

const TimeZone: React.FC<{ keywords: string[] }> = ({keywords}) => {
    const {
        localSettings,
        isEditing,
        saveState,
        handleSave,
        handleCancel,
        updateSetting,
        handleEditingChange
    } = useSettingGroup();

    const [publicationTimezone] = getSettingValues(localSettings, ['timezone']) as string[];

    const timezoneOptions: Array<{value: string; label: string}> = timezoneData.map((tzOption: TimezoneDataDropdownOption) => {
        return {
            value: tzOption.name,
            label: tzOption.label
        };
    });

    const publicationTimezoneData = timezoneOptions.find(option => option.value === publicationTimezone);

    const handleTimezoneChange = (value?: string) => {
        updateSetting('timezone', value || null);
    };

    const viewContent = (
        <SettingGroupContent values={[
            {
                key: 'site-timezone',
                value: <div className='flex flex-col'>
                    {publicationTimezoneData?.label || publicationTimezone}
                    <span className='text-xs'><Hint timezone={publicationTimezone} /></span>
                </div>
            }
        ]} />
    );
    const inputFields = (
        <SettingGroupContent columns={1}>
            <Select
                hint={<Hint timezone={publicationTimezone} />}
                options={timezoneOptions}
                selectedOption={timezoneOptions.find(option => option.value === publicationTimezone)}
                testId='timezone-select'
                title="Site timezone"
                isSearchable
                onSelect={option => handleTimezoneChange(option?.value)}
            />
        </SettingGroupContent>
    );

    return (
        <TopLevelGroup
            description='Set the time and date of your publication, used for all published posts'
            isEditing={isEditing}
            keywords={keywords}
            navid='timezone'
            saveState={saveState}
            testId='timezone'
            title='Site timezone'
            onCancel={handleCancel}
            onEditingChange={handleEditingChange}
            onSave={handleSave}
        >
            {isEditing ? inputFields : viewContent}
        </TopLevelGroup>
    );
};

export default withErrorBoundary(TimeZone, 'Site timezone');