Skip to content

Commit 6313486

Browse files
committed
add button languages for noti preview
1 parent 1ac6880 commit 6313486

6 files changed

Lines changed: 113 additions & 45 deletions

File tree

ui/dashboard/src/@locales/en/form.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@
554554
"mention": "Mention",
555555
"languages": "Languages",
556556
"languages-info": "Add a translation for each language. Viewers see the notification in their console language, falling back to English.",
557+
"languages-info-view": "This notification is available in the following languages.",
557558
"add-language": "Add language",
558559
"remove-language": "Remove language",
559560
"content": "Content",

ui/dashboard/src/@locales/ja/form.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@
553553
"notification-title-placeholder": "通知のタイトル",
554554
"languages": "言語",
555555
"languages-info": "各言語の翻訳を追加します。閲覧者にはコンソールの言語で表示され、なければ英語で表示されます。",
556+
"languages-info-view": "この通知は以下の言語でご利用いただけます。",
556557
"add-language": "言語を追加",
557558
"remove-language": "言語を削除",
558559
"content": "内容",

ui/dashboard/src/pages/notification-feed/elements/notification-detail.tsx

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
import { ReactNode } from 'react';
1+
import { ReactNode, useEffect, useMemo, useState } from 'react';
22
import { useToast } from 'hooks';
3-
import { useTranslation } from 'i18n';
3+
import { getLanguage, useTranslation } from 'i18n';
44
import { Pencil, Send } from 'lucide-react';
55
import { formatLongDateTime, useFormatDateTime } from 'utils/date-time';
66
import { cn } from 'utils/style';
77
import Button from 'components/button';
88
import SlideModal from 'components/modal/slide';
99
import Spinner from 'components/spinner';
1010
import { usePublishDraft } from '../collection-loader/use-fetch-notifications';
11-
import { NotificationDetail, NotificationStatus } from '../types';
11+
import { LANGUAGE_META } from '../language-meta';
12+
import LanguageTabs from '../publisher/language-tabs';
13+
import {
14+
NotificationDetail,
15+
NotificationLocalizationInput,
16+
NotificationStatus
17+
} from '../types';
1218
import { MarkdownContent } from './markdown-content';
1319
import TagChip from './tag-chip';
1420

@@ -78,6 +84,34 @@ const NotificationDetailModal = ({
7884
const { notify, errorNotify } = useToast();
7985
const publishMutation = usePublishDraft();
8086

87+
const localizations: NotificationLocalizationInput[] = useMemo(() => {
88+
if (notification?.localizations?.length) return notification.localizations;
89+
if (!notification) return [];
90+
return [
91+
{
92+
language: getLanguage(),
93+
title: notification.title,
94+
content: notification.content,
95+
tags: notification.tags
96+
}
97+
];
98+
}, [notification]);
99+
100+
const [activeLanguage, setActiveLanguage] = useState<string>(() =>
101+
getLanguage()
102+
);
103+
104+
useEffect(() => {
105+
if (!localizations.length) return;
106+
setActiveLanguage(current => {
107+
if (localizations.some(l => l.language === current)) return current;
108+
const preferred = getLanguage();
109+
return localizations.some(l => l.language === preferred)
110+
? preferred
111+
: localizations[0].language;
112+
});
113+
}, [localizations]);
114+
81115
if (!isOpen) return null;
82116

83117
if (isError) {
@@ -107,6 +141,8 @@ const NotificationDetailModal = ({
107141

108142
const isDraft = notification.status === NotificationStatus.DRAFT;
109143
const timestamp = isDraft ? notification.updatedAt : notification.publishedAt;
144+
const activeLocalization =
145+
localizations.find(l => l.language === activeLanguage) ?? localizations[0];
110146

111147
const onPublish = () => {
112148
publishMutation.mutate(notification.id, {
@@ -119,9 +155,31 @@ const NotificationDetailModal = ({
119155
};
120156

121157
return (
122-
<SlideModal title={notification.title} isOpen={isOpen} onClose={onClose}>
158+
<SlideModal
159+
title={activeLocalization.title}
160+
isOpen={isOpen}
161+
onClose={onClose}
162+
>
123163
<div className="w-full h-full flex flex-col">
124164
<div className="flex flex-1 flex-col gap-6 overflow-auto p-6">
165+
{localizations.length > 1 && (
166+
<LanguageTabs
167+
fields={localizations.map(l => ({
168+
id: l.language,
169+
language: l.language
170+
}))}
171+
activeLanguage={activeLanguage}
172+
availableToAdd={[]}
173+
canRemove={false}
174+
readOnly
175+
languageMeta={LANGUAGE_META}
176+
tooltipContent={t('form:languages-info-view')}
177+
onSelect={setActiveLanguage}
178+
onAdd={() => {}}
179+
onRemove={() => {}}
180+
/>
181+
)}
182+
125183
<div className="flex items-center gap-2">
126184
<TagChip
127185
tag={{
@@ -136,16 +194,16 @@ const NotificationDetailModal = ({
136194
</span>
137195
</div>
138196

139-
{notification.tags.length > 0 && (
197+
{activeLocalization.tags.length > 0 && (
140198
<div className="flex flex-wrap items-center gap-2">
141-
{notification.tags.map(tag => (
199+
{activeLocalization.tags.map(tag => (
142200
<TagChip key={tag.name} tag={tag} />
143201
))}
144202
</div>
145203
)}
146204

147205
<Section title={t('form:content')}>
148-
<MarkdownContent source={notification.content} />
206+
<MarkdownContent source={activeLocalization.content} />
149207
</Section>
150208

151209
<Section
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { FunctionComponent } from 'react';
2+
import { Language } from 'i18n';
3+
import { IconEnglishFlag, IconJapanFlag } from '@icons';
4+
5+
export interface LanguageMeta {
6+
label: string;
7+
englishName: string;
8+
icon: FunctionComponent;
9+
}
10+
11+
export const LANGUAGE_META: Record<string, LanguageMeta> = {
12+
[Language.ENGLISH]: {
13+
label: 'English',
14+
englishName: 'English',
15+
icon: IconEnglishFlag
16+
},
17+
[Language.JAPANESE]: {
18+
label: '日本語',
19+
englishName: 'Japanese',
20+
icon: IconJapanFlag
21+
}
22+
};
23+
24+
export const FORM_LANGUAGES: Language[] = [Language.ENGLISH, Language.JAPANESE];

ui/dashboard/src/pages/notification-feed/publisher/language-tabs.tsx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { FunctionComponent } from 'react';
21
import { useTranslation } from 'i18n';
32
import { X } from 'lucide-react';
43
import { cn } from 'utils/style';
@@ -7,18 +6,13 @@ import Button from 'components/button';
76
import Dropdown from 'components/dropdown';
87
import Icon from 'components/icon';
98
import { Tooltip } from 'components/tooltip';
9+
import { LanguageMeta } from '../language-meta';
1010

1111
export interface LanguageTabField {
1212
id: string;
1313
language: string;
1414
}
1515

16-
interface LanguageMeta {
17-
label: string;
18-
englishName: string;
19-
icon: FunctionComponent;
20-
}
21-
2216
interface LanguageTabsProps {
2317
fields: LanguageTabField[];
2418
activeLanguage: string;
@@ -28,6 +22,8 @@ interface LanguageTabsProps {
2822
onSelect: (language: string) => void;
2923
onAdd: (language: string) => void;
3024
onRemove: (index: number, language: string) => void;
25+
readOnly?: boolean;
26+
tooltipContent?: string;
3127
}
3228

3329
const LanguageTabs = ({
@@ -38,7 +34,9 @@ const LanguageTabs = ({
3834
languageMeta,
3935
onSelect,
4036
onAdd,
41-
onRemove
37+
onRemove,
38+
readOnly = false,
39+
tooltipContent
4240
}: LanguageTabsProps) => {
4341
const { t } = useTranslation(['form']);
4442

@@ -52,7 +50,7 @@ const LanguageTabs = ({
5250
{t('form:languages')}
5351
</label>
5452
<Tooltip
55-
content={t('form:languages-info')}
53+
content={tooltipContent ?? t('form:languages-info')}
5654
trigger={
5755
<span className="flex text-gray-400">
5856
<Icon icon={IconInfo} size="xxs" />
@@ -83,7 +81,7 @@ const LanguageTabs = ({
8381
)}
8482
{label(field.language)}
8583
</Button>
86-
{canRemove && (
84+
{!readOnly && canRemove && (
8785
<Button
8886
type="button"
8987
variant="text"
@@ -98,17 +96,19 @@ const LanguageTabs = ({
9896
))}
9997
</div>
10098

101-
<Dropdown
102-
className="w-[200px] py-[11px]"
103-
disabled={availableToAdd.length <= 0}
104-
placeholder={t('form:add-language')}
105-
options={availableToAdd.map(lang => ({
106-
value: lang,
107-
label: `${label(lang)} (${languageMeta[lang]?.englishName ?? lang})`,
108-
icon: icon(lang)
109-
}))}
110-
onChange={value => onAdd(String(value))}
111-
/>
99+
{!readOnly && (
100+
<Dropdown
101+
className="w-[200px] py-[11px]"
102+
disabled={availableToAdd.length <= 0}
103+
placeholder={t('form:add-language')}
104+
options={availableToAdd.map(lang => ({
105+
value: lang,
106+
label: `${label(lang)} (${languageMeta[lang]?.englishName ?? lang})`,
107+
icon: icon(lang)
108+
}))}
109+
onChange={value => onAdd(String(value))}
110+
/>
111+
)}
112112
</div>
113113
</div>
114114
);

ui/dashboard/src/pages/notification-feed/publisher/publish-form.tsx

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { yupResolver } from '@hookform/resolvers/yup';
44
import { useToast } from 'hooks';
55
import useFormSchema from 'hooks/use-form-schema';
66
import { getLanguage, Language, useTranslation } from 'i18n';
7-
import { IconEnglishFlag, IconJapanFlag } from '@icons';
87
import Button from 'components/button';
98
import Form from 'components/form';
109
import Input from 'components/input';
@@ -13,6 +12,7 @@ import {
1312
useSaveDraft,
1413
useUpdateNotification
1514
} from '../collection-loader/use-fetch-notifications';
15+
import { FORM_LANGUAGES, LANGUAGE_META } from '../language-meta';
1616
import {
1717
NotificationDetail,
1818
NotificationLocalizationInput,
@@ -24,22 +24,6 @@ import LanguageTabs from './language-tabs';
2424
import MarkdownEditor from './markdown-editor';
2525
import TagSelect from './tag-select';
2626

27-
const LANGUAGE_META = {
28-
[Language.ENGLISH]: {
29-
label: 'English',
30-
englishName: 'English',
31-
icon: IconEnglishFlag
32-
},
33-
[Language.JAPANESE]: {
34-
label: '日本語',
35-
englishName: 'Japanese',
36-
icon: IconJapanFlag
37-
}
38-
};
39-
40-
// Languages the form can author, in the order they appear in the add menu.
41-
const FORM_LANGUAGES: Language[] = [Language.ENGLISH, Language.JAPANESE];
42-
4327
const emptyLocalization = (
4428
language: string
4529
): NotificationLocalizationInput => ({

0 commit comments

Comments
 (0)