Procházet zdrojové kódy

WIP: refactor TemplateModal

Yuki Takei před 2 roky
rodič
revize
a6868f2391

+ 45 - 23
apps/app/src/components/TemplateModal/TemplateModal.tsx

@@ -2,7 +2,11 @@ import React, {
   useCallback, useEffect, useState,
 } from 'react';
 
+import assert from 'assert';
+
+import { Lang } from '@growi/core';
 import type { ITemplate } from '@growi/core/dist/interfaces/template';
+import type { TemplateSummary } from '@growi/pluginkit/dist/interfaces/v4';
 import { useTranslation } from 'next-i18next';
 import {
   Modal,
@@ -12,8 +16,9 @@ import {
 } from 'reactstrap';
 
 import { useTemplateModal } from '~/stores/modal';
+import { usePersonalSettings } from '~/stores/personal-settings';
 import { usePreviewOptions } from '~/stores/renderer';
-import { useTemplates } from '~/stores/template';
+import { useSWRxTemplates } from '~/stores/template';
 import loggerFactory from '~/utils/logger';
 
 import Preview from '../PageEditor/Preview';
@@ -24,25 +29,35 @@ const logger = loggerFactory('growi:components:TemplateModal');
 
 
 type TemplateRadioButtonProps = {
-  template: ITemplate,
-  onChange: (selectedTemplate: ITemplate) => void,
+  templateSummary: TemplateSummary,
+  onChange: (selectedTemplate: TemplateSummary) => void,
+  usersDefaultLang?: Lang,
   isSelected?: boolean,
 }
 
-const TemplateRadioButton = ({ template, onChange, isSelected }: TemplateRadioButtonProps): JSX.Element => {
-  const radioButtonId = `rb-${template.id}`;
+const TemplateRadioButton = ({
+  templateSummary, onChange, usersDefaultLang, isSelected,
+}: TemplateRadioButtonProps): JSX.Element => {
+  const templateId = templateSummary.default.id;
+  const radioButtonId = `rb-${templateId}`;
+
+  const template = usersDefaultLang != null && usersDefaultLang in templateSummary
+    ? templateSummary[usersDefaultLang]
+    : templateSummary.default;
+
+  assert(template.isValid);
 
   return (
-    <div key={template.id} className="custom-control custom-radio mb-2">
+    <div key={templateId} className="custom-control custom-radio mb-2">
       <input
         id={radioButtonId}
         type="radio"
         className="custom-control-input"
         checked={isSelected}
-        onChange={() => onChange(template)}
+        onChange={() => onChange(templateSummary)}
       />
       <label className="custom-control-label" htmlFor={radioButtonId}>
-        {template.name}
+        {template.title}
       </label>
     </div>
   );
@@ -54,15 +69,17 @@ export const TemplateModal = (): JSX.Element => {
 
   const { data: templateModalStatus, close } = useTemplateModal();
 
+  const { data: personalSettingsInfo } = usePersonalSettings();
   const { data: rendererOptions } = usePreviewOptions();
-  const { data: templates } = useTemplates();
+  const { data: templateSummaries } = useSWRxTemplates();
 
-  const [selectedTemplate, setSelectedTemplate] = useState<ITemplate>();
+  const [selectedTemplateId, setSelectedTemplateId] = useState<string>();
+  // const [selectedTemplateLocale, setSelectedTemplateLocale] = useState<string>();
 
   const { format } = useFormatter();
 
   const submitHandler = useCallback((template?: ITemplate) => {
-    if (templateModalStatus == null || selectedTemplate == null) {
+    if (templateModalStatus == null || selectedTemplateId == null) {
       return;
     }
 
@@ -71,17 +88,17 @@ export const TemplateModal = (): JSX.Element => {
       return;
     }
 
-    templateModalStatus.onSubmit(format(selectedTemplate));
+    // templateModalStatus.onSubmit(format(selectedTemplate));
     close();
-  }, [close, format, selectedTemplate, templateModalStatus]);
+  }, [close, selectedTemplateId, templateModalStatus]);
 
   useEffect(() => {
     if (!templateModalStatus?.isOpened) {
-      setSelectedTemplate(undefined);
+      setSelectedTemplateId(undefined);
     }
   }, [templateModalStatus?.isOpened]);
 
-  if (templates == null || templateModalStatus == null) {
+  if (templateSummaries == null || templateModalStatus == null) {
     return <></>;
   }
 
@@ -94,12 +111,13 @@ export const TemplateModal = (): JSX.Element => {
       <ModalBody className="container">
         <div className="row">
           <div className="col-12">
-            { templates.map(template => (
+            { Object.entries(templateSummaries).map(([templateId, templateSummary]) => (
               <TemplateRadioButton
-                key={template.id}
-                template={template}
-                onChange={selected => setSelectedTemplate(selected)}
-                isSelected={template.id === selectedTemplate?.id}
+                key={templateId}
+                templateSummary={templateSummary}
+                usersDefaultLang={personalSettingsInfo?.lang}
+                onChange={() => setSelectedTemplateId(templateId)}
+                isSelected={templateId === selectedTemplateId}
               />
             )) }
           </div>
@@ -110,8 +128,8 @@ export const TemplateModal = (): JSX.Element => {
         <h3>{t('Preview')}</h3>
         <div className='card'>
           <div className="card-body" style={{ height: '400px', overflowY: 'auto' }}>
-            { rendererOptions != null && selectedTemplate != null && (
-              <Preview rendererOptions={rendererOptions} markdown={format(selectedTemplate)}/>
+            { rendererOptions != null && selectedTemplateId != null && (
+              <Preview rendererOptions={rendererOptions} markdown={'' /* format(selectedTemplate) */}/>
             ) }
           </div>
         </div>
@@ -121,7 +139,11 @@ export const TemplateModal = (): JSX.Element => {
         <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={close}>
           {t('Cancel')}
         </button>
-        <button type="submit" className="btn btn-sm btn-primary mx-1" onClick={() => submitHandler(selectedTemplate)} disabled={selectedTemplate == null}>
+        <button
+          type="submit"
+          className="btn btn-sm btn-primary mx-1"
+          // onClick={() => submitHandler(selectedTemplate)}
+          disabled={selectedTemplateId == null}>
           {t('commons:Insert')}
         </button>
       </ModalFooter>

+ 95 - 91
apps/app/src/stores/template.tsx

@@ -1,141 +1,145 @@
-import type { ITemplate } from '@growi/core';
+import type { TemplateSummaries } from '@growi/pluginkit/dist/interfaces/v4';
 import useSWR, { type SWRResponse } from 'swr';
 
-import { getGrowiFacade } from '~/features/growi-plugin/client/utils/growi-facade-utils';
+import { apiv3Get } from '~/client/util/apiv3-client';
 
-const presetTemplates: ITemplate[] = [
-  // preset 1
-  {
-    id: '__preset1__',
-    name: '日報',
-    markdown: `# {{yyyy}}/{{MM}}/{{dd}} 日報
+// const presetTemplates: ITemplate[] = [
+//   // preset 1
+//   {
+//     id: '__preset1__',
+//     name: '日報',
+//     markdown: `# {{yyyy}}/{{MM}}/{{dd}} 日報
 
-## 今日の目標
-- 目標1
-    - 〇〇の完了
-- 目標2
-    - 〇〇を〇件達成
+// ## 今日の目標
+// - 目標1
+//     - 〇〇の完了
+// - 目標2
+//     - 〇〇を〇件達成
 
 
-## 内容
-- 10:00 ~ 10:20 今日のタスク確認
-- 10:20 ~ 11:00 全体会議
+// ## 内容
+// - 10:00 ~ 10:20 今日のタスク確認
+// - 10:20 ~ 11:00 全体会議
 
 
-## 進捗
-- 目標1
-    - 完了
-- 目標2
-    - 〇〇件達成
+// ## 進捗
+// - 目標1
+//     - 完了
+// - 目標2
+//     - 〇〇件達成
 
 
-## メモ
-- 改善できることの振り返り
+// ## メモ
+// - 改善できることの振り返り
 
 
-## 翌営業日の目標
-- 目標1
-    - 〇〇の完了
-- 目標2
-    - 〇〇を〇件達成
-`,
-  },
+// ## 翌営業日の目標
+// - 目標1
+//     - 〇〇の完了
+// - 目標2
+//     - 〇〇を〇件達成
+// `,
+//   },
 
-  // preset 2
-  {
-    id: '__preset2__',
-    name: '議事録',
-    markdown: `# {{{title}}}{{^title}}<会議名>{{/title}}
+//   // preset 2
+//   {
+//     id: '__preset2__',
+//     name: '議事録',
+//     markdown: `# {{{title}}}{{^title}}<会議名>{{/title}}
 
-## 日時
-{{yyyy}}/{{MM}}/{{dd}} {{HH}}:{{mm}}〜hh:mm
+// ## 日時
+// {{yyyy}}/{{MM}}/{{dd}} {{HH}}:{{mm}}〜hh:mm
 
 
-## 参加者
--
+// ## 参加者
+// -
 
-## 議題
-1.
-2.
+// ## 議題
+// 1.
+// 2.
 
 
-## 1.
-### 内容
+// ## 1.
+// ### 内容
 
 
-### 決定事項
+// ### 決定事項
 
 
-### Next Action
+// ### Next Action
 
 
-## 2.
-### 内容
+// ## 2.
+// ### 内容
 
 
-### 決定事項
+// ### 決定事項
 
 
-### Next Action
+// ### Next Action
 
 
-## 次回会議
-- 会議内容
-- 会議時間
-    - {{yyyy}}/{{MM}}/dd
-`,
-  },
+// ## 次回会議
+// - 会議内容
+// - 会議時間
+//     - {{yyyy}}/{{MM}}/dd
+// `,
+//   },
 
-  // preset 3
-  {
-    id: '__preset3__',
-    name: '企画書',
-    markdown: `# {{{title}}}{{^title}}<企画タイトル>{{/title}}
+//   // preset 3
+//   {
+//     id: '__preset3__',
+//     name: '企画書',
+//     markdown: `# {{{title}}}{{^title}}<企画タイトル>{{/title}}
 
-## 目的
+// ## 目的
 
 
-## 現状の課題
+// ## 現状の課題
 
 
-## 概要
-#### 企画の内容
+// ## 概要
+// #### 企画の内容
 
-#### スケジュール
+// #### スケジュール
 
 
-## 効果
-#### メリット
+// ## 効果
+// #### メリット
 
-#### 数値目標
+// #### 数値目標
 
 
-## 参考資料
+// ## 参考資料
 
-`,
-  },
+// `,
+//   },
 
-  // preset 4
-  {
-    id: '__preset4__',
-    name: '関連ページの一覧表示',
-    markdown: `# 関連ページ
+//   // preset 4
+//   {
+//     id: '__preset4__',
+//     name: '関連ページの一覧表示',
+//     markdown: `# 関連ページ
 
-## 子ページ一覧
-$lsx(depth=1)
-`,
-  },
-];
+// ## 子ページ一覧
+// $lsx(depth=1)
+// `,
+//   },
+// ];
 
-export const useTemplates = (): SWRResponse<ITemplate[], Error> => {
+export const useSWRxTemplates = (): SWRResponse<TemplateSummaries, Error> => {
+  // return useSWR(
+  //   'templates',
+  //   () => [
+  //     ...presetTemplates,
+  //     ...Object.values<ITemplate>(getGrowiFacade().customTemplates ?? {}),
+  //   ],
+  //   {
+  //     fallbackData: presetTemplates,
+  //   },
+  // );
   return useSWR(
-    'templates',
-    () => [
-      ...presetTemplates,
-      ...Object.values<ITemplate>(getGrowiFacade().customTemplates ?? {}),
-    ],
-    {
-      fallbackData: presetTemplates,
-    },
+    ['/templates'],
+    ([endpoint]) => apiv3Get<TemplateSummaries>(endpoint).then(res => res.data),
   );
 };