Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1073 support different locales and timezones #1091

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vuu-ui/cypress/pages/ShellWithNewTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class ShellWithNewTheme {
creator: string,
date: Date
) => {
const formattedDate = formatDate({ date: "dd.mm.yyyy" })(date);
const formattedDate = formatDate({ date: "ddmmyyyy" })(date);
const layoutTileName = `${layoutName} ${creator}, ${formattedDate}`;

return cy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class LocalPersistenceManager implements PersistenceManager {
const newMetadata: LayoutMetadata = {
...metadata,
id,
created: formatDate({ date: "dd.mm.yyyy" })(new Date()),
created: formatDate({ date: "ddmmyyyy" })(new Date()),
};

this.saveLayoutsWithMetadata(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const persistenceManager = new LocalPersistenceManager();

const existingId = "existing_id";

const newDate = formatDate({ date: "dd.mm.yyyy" })(new Date());
const newDate = formatDate({ date: "ddmmyyyy" })(new Date());

const existingMetadata: LayoutMetadata = {
id: existingId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import {
FormField,
FormFieldLabel,
Switch,
ToggleButton,
ToggleButtonGroup,
} from "@salt-ds/core";
Expand All @@ -23,55 +24,13 @@ export const DateTimeFormattingSettings: React.FC<
const { pattern = fallbackDateTimePattern } = formatting;
const toggleValue = useMemo(() => getToggleValue(pattern), [pattern]);

const [fallbackState, setFallbackState] = useState<Required<DateTimePattern>>(
{
time: pattern.time ?? defaultPatternsByType.time,
date: pattern.date ?? defaultPatternsByType.date,
}
);

const onPatternChange = useCallback(
(pattern: DateTimePattern) => onChange({ ...formatting, pattern }),
[onChange, formatting]
);

const onDropdownChange = useCallback<
<T extends keyof DateTimePattern>(
key: T
) => SingleSelectionHandler<Required<DateTimePattern>[T]>
>(
(key) => (_, p) => {
const updatedPattern = { ...(pattern ?? {}), [key]: p };
setFallbackState((s) => ({
time: updatedPattern.time ?? s.time,
date: updatedPattern.date ?? s.date,
}));
onPatternChange(updatedPattern);
},
[onPatternChange, pattern]
);

const onToggleChange = useCallback(
(evnt: SyntheticEvent<HTMLButtonElement, Event>) => {
const value = evnt.currentTarget.value as ToggleValue;
switch (value) {
case "time":
return onPatternChange({
[value]: pattern[value] ?? fallbackState[value],
});
case "date":
return onPatternChange({
[value]: pattern[value] ?? fallbackState[value],
});
case "both":
return onPatternChange({
time: pattern.time ?? fallbackState.time,
date: pattern.date ?? fallbackState.date,
});
}
},
[onPatternChange, pattern, fallbackState]
);
const { onDropdownChange, onSwitchChange, onToggleChange } =
useDateTimeFormattingSettings({ pattern, onPatternChange });

return (
<>
Expand Down Expand Up @@ -103,6 +62,11 @@ export const DateTimeFormattingSettings: React.FC<
/>
</FormField>
))}

<FormField labelPlacement="left">
<FormFieldLabel>{"Show time-zone"}</FormFieldLabel>
<Switch checked={!!pattern.showTimeZone} onChange={onSwitchChange} />
</FormField>
</>
);
};
Expand All @@ -116,3 +80,71 @@ type ToggleValue = (typeof toggleValues)[number];
function getToggleValue(pattern: DateTimePattern): ToggleValue {
return !pattern.time ? "date" : !pattern.date ? "time" : "both";
}

type RequiredDateTimePattern = Required<Pick<DateTimePattern, "date" | "time">>;

function useDateTimeFormattingSettings(props: {
pattern: DateTimePattern;
onPatternChange: (p: DateTimePattern) => void;
}) {
const { pattern, onPatternChange } = props;
const [fallbackState, setFallbackState] = useState<RequiredDateTimePattern>({
time: pattern.time ?? defaultPatternsByType.time,
date: pattern.date ?? defaultPatternsByType.date,
});

const onDropdownChange = useCallback<
<T extends keyof RequiredDateTimePattern>(
key: T
) => SingleSelectionHandler<RequiredDateTimePattern[T]>
>(
(key) => (_, p) => {
const updatedPattern = { ...(pattern ?? {}), [key]: p };
setFallbackState((s) => ({
time: updatedPattern.time ?? s.time,
date: updatedPattern.date ?? s.date,
}));
onPatternChange(updatedPattern);
},
[onPatternChange, pattern]
);

const onToggleChange = useCallback(
(evnt: SyntheticEvent<HTMLButtonElement, Event>) => {
const value = evnt.currentTarget.value as ToggleValue;
switch (value) {
case "time":
return onPatternChange({
...pattern,
time: pattern.time ?? fallbackState.time,
date: undefined,
});
case "date":
return onPatternChange({
...pattern,
time: undefined,
date: pattern.date ?? fallbackState.date,
});
case "both":
return onPatternChange({
...pattern,
time: pattern.time ?? fallbackState.time,
date: pattern.date ?? fallbackState.date,
});
}
},
[onPatternChange, pattern, fallbackState]
);

const onSwitchChange = useCallback<
React.ChangeEventHandler<HTMLInputElement>
>(
(e) => {
const { checked: showTimeZone } = e.target;
onPatternChange({ ...pattern, showTimeZone });
},
[onPatternChange, pattern]
);

return { onDropdownChange, onSwitchChange, onToggleChange };
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useMemo } from "react";
import { Dropdown, SingleSelectionHandler } from "@finos/vuu-ui-controls";
import {
Button,
FormField,
Expand All @@ -6,7 +8,15 @@ import {
ToggleButton,
ToggleButtonGroup,
} from "@salt-ds/core";
import { TableSettingsProps } from "@finos/vuu-table-types";
import {
localeOptions,
timeZoneOptions,
getDefaultLocaleAndTimeZone,
} from "@finos/vuu-utils";
import {
DateTimeTableAttributes,
TableSettingsProps,
} from "@finos/vuu-table-types";
import { ColumnList } from "../column-list";
import { useTableSettings } from "./useTableSettings";

Expand All @@ -33,6 +43,7 @@ export const TableSettingsPanel = ({
onChangeColumnLabels,
onChangeTableAttribute,
onColumnChange,
onChangeDateTimeAttribute,
onMoveListItem,
tableConfig,
} = useTableSettings({
Expand Down Expand Up @@ -101,6 +112,12 @@ export const TableSettingsPanel = ({
<Input className="vuuInput" />
</FormField>

<DateTimeAttributesSettings
dateTimeAttrs={tableConfig.dateTime ?? {}}
onLocaleChange={onChangeDateTimeAttribute("locale")}
onTimeZoneChange={onChangeDateTimeAttribute("timeZone")}
/>

<ColumnList
columnItems={columnItems}
onChange={onColumnChange}
Expand All @@ -117,3 +134,47 @@ export const TableSettingsPanel = ({
</div>
);
};

const DateTimeAttributesSettings: React.FC<{
dateTimeAttrs: DateTimeTableAttributes;
onLocaleChange: SingleSelectionHandler<string>;
onTimeZoneChange: SingleSelectionHandler<string>;
}> = ({ dateTimeAttrs, onLocaleChange, onTimeZoneChange }) => {
const { locale: defaultLocale, timeZone: defaultTimeZone } =
getDefaultLocaleAndTimeZone();
const { locale = defaultLocale, timeZone = defaultTimeZone } = dateTimeAttrs;

const localesSource = useMemo(
() => [...new Set([...localeOptions, locale, defaultLocale])].sort(),
[locale, defaultLocale]
);

const timeZonesSource = useMemo(
() => [...new Set([...timeZoneOptions, timeZone, defaultTimeZone])].sort(),
[timeZone, defaultTimeZone]
);

return (
<>
<FormField>
<FormFieldLabel>Date/time locale</FormFieldLabel>
<Dropdown
onSelectionChange={onLocaleChange}
selected={locale}
source={localesSource}
width="100%"
/>
</FormField>

<FormField>
<FormFieldLabel>Time-zone</FormFieldLabel>
<Dropdown
onSelectionChange={onTimeZoneChange}
selected={timeZone}
source={timeZonesSource}
width="100%"
/>
</FormField>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { SchemaColumn } from "@finos/vuu-data-types";
import { updateTableConfig } from "@finos/vuu-table";
import {
ColumnDescriptor,
DateTimeTableAttributes,
TableConfig,
TableSettingsProps,
} from "@finos/vuu-table-types";
Expand All @@ -20,6 +21,7 @@ import {
useState,
} from "react";
import { ColumnChangeHandler } from "../column-list";
import { SingleSelectionHandler } from "@finos/vuu-ui-controls";

const sortOrderFromAvailableColumns = (
availableColumns: SchemaColumn[],
Expand Down Expand Up @@ -194,6 +196,23 @@ export const useTableSettings = ({
[]
);

const handleChangeDateTimeAttribute = useCallback<
<T extends keyof DateTimeTableAttributes>(
key: T
) => SingleSelectionHandler<DateTimeTableAttributes[T]>
>(
(key) => (_, value) => {
setColumnState((s) => ({
...s,
tableConfig: {
...s.tableConfig,
dateTime: { ...s.tableConfig.dateTime, [key]: value },
},
}));
},
[]
);

useLayoutEffectSkipFirst(() => {
onConfigChange?.(tableConfig);
}, [onConfigChange, tableConfig]);
Expand All @@ -211,6 +230,7 @@ export const useTableSettings = ({
onChangeColumnLabels: handleChangeColumnLabels,
onChangeTableAttribute: handleChangeTableAttribute,
onColumnChange: handleColumnChange,
onChangeDateTimeAttribute: handleChangeDateTimeAttribute,
onMoveListItem: handleMoveListItem,
tableConfig,
};
Expand Down
6 changes: 6 additions & 0 deletions vuu-ui/packages/vuu-table-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,19 @@ export interface TableCellRendererProps
onCommit?: DataItemCommitHandler;
}

export declare type DateTimeTableAttributes = {
timeZone?: string;
locale?: string;
};

export interface TableAttributes {
columnDefaultWidth?: number;
columnFormatHeader?: "capitalize" | "uppercase";
columnSeparators?: boolean;
// showHighlightedRow?: boolean;
rowSeparators?: boolean;
zebraStripes?: boolean;
dateTime?: DateTimeTableAttributes;
}

/**
Expand Down
13 changes: 10 additions & 3 deletions vuu-ui/packages/vuu-table/src/useTableModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,11 @@ const columnDescriptorToRuntimeColumDescriptor =
column: ColumnDescriptor & { key?: number },
index: number
): RuntimeColumnDescriptor => {
const { columnDefaultWidth = DEFAULT_COLUMN_WIDTH, columnFormatHeader } =
tableAttributes;
const {
columnDefaultWidth = DEFAULT_COLUMN_WIDTH,
columnFormatHeader,
dateTime: dateTimeTableAttributes,
} = tableAttributes;
const serverDataType = getDataType(column, tableSchema);
const {
align = getDefaultAlignment(serverDataType),
Expand All @@ -315,7 +318,11 @@ const columnDescriptorToRuntimeColumDescriptor =
name,
originalIdx: index,
serverDataType,
valueFormatter: getValueFormatter(column, serverDataType),
valueFormatter: getValueFormatter(
column,
serverDataType,
dateTimeTableAttributes
),
width: width,
};

Expand Down
Loading