Shun Miyazawa 3 лет назад
Родитель
Сommit
4e750ad092

+ 1 - 1
packages/app/src/components/ShareLink/ShareLink.tsx

@@ -9,7 +9,7 @@ import { apiv3Delete } from '~/client/util/apiv3-client';
 import { useCurrentPageId } from '~/stores/context';
 import { useCurrentPageId } from '~/stores/context';
 import { useSWRxSharelink } from '~/stores/share-link';
 import { useSWRxSharelink } from '~/stores/share-link';
 
 
-import ShareLinkForm from './ShareLinkForm';
+import { ShareLinkForm } from './ShareLinkForm';
 import ShareLinkList from './ShareLinkList';
 import ShareLinkList from './ShareLinkList';
 
 
 const ShareLink = (): JSX.Element => {
 const ShareLink = (): JSX.Element => {

+ 202 - 0
packages/app/src/components/ShareLink/ShareLinkForm.tsx

@@ -0,0 +1,202 @@
+import React, { FC, useState } from 'react';
+
+import { isInteger } from 'core-js/fn/number';
+import { format, parse } from 'date-fns';
+import { useTranslation } from 'next-i18next';
+
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Post } from '~/client/util/apiv3-client';
+import { useCurrentPageId } from '~/stores/context';
+
+type Props = {
+  onCloseForm: () => void,
+}
+
+export const ShareLinkForm: FC<Props> = (props: Props) => {
+  const { t } = useTranslation();
+  const { onCloseForm } = props;
+
+  const [expirationType, setExpirationType] = useState('unlimited');
+  const [numberOfDays, setNumberOfDays] = useState(7);
+  const [description, setDescription] = useState('');
+  const [customExpirationDate, setCustomExpirationDate] = useState(format(new Date(), 'yyyy-MM-dd'));
+  const [customExpirationTime, setCustomExpirationTime] = useState(format(new Date(), 'HH:mm'));
+
+  const { data: currentPageId } = useCurrentPageId();
+
+  const handleChangeExpirationType = (expirationType) => {
+    setExpirationType(expirationType);
+  };
+
+  const handleChangeNumberOfDays = (numberOfDays) => {
+    setNumberOfDays(numberOfDays);
+  };
+
+  const handleChangeDescription = (description) => {
+    setDescription(description);
+  };
+
+  const handleChangeCustomExpirationDate = (customExpirationDate) => {
+    setCustomExpirationDate(customExpirationDate);
+  };
+
+  const handleChangeCustomExpirationTime = (customExpirationTime) => {
+    setCustomExpirationTime(customExpirationTime);
+  };
+
+  const generateExpired = () => {
+    let expiredAt;
+
+    if (expirationType === 'unlimited') {
+      return null;
+    }
+
+    if (expirationType === 'numberOfDays') {
+      if (!isInteger(Number(numberOfDays))) {
+        throw new Error(t('share_links.Invalid_Number_of_Date'));
+      }
+      const date = new Date();
+      date.setDate(date.getDate() + Number(numberOfDays));
+      expiredAt = date;
+    }
+
+    if (expirationType === 'custom') {
+      expiredAt = parse(`${customExpirationDate}T${customExpirationTime}`, "yyyy-MM-dd'T'HH:mm", new Date());
+    }
+
+    return expiredAt;
+  };
+
+  const closeForm = () => {
+    if (onCloseForm == null) {
+      return;
+    }
+    onCloseForm();
+  };
+
+
+  const handleIssueShareLink = async() => {
+    let expiredAt;
+
+    try {
+      expiredAt = generateExpired();
+    }
+    catch (err) {
+      return toastError(err);
+    }
+
+    try {
+      await apiv3Post('/share-links/', { relatedPage: currentPageId, expiredAt, description });
+      closeForm();
+      toastSuccess(t('toaster.issue_share_link'));
+    }
+    catch (err) {
+      toastError(err);
+    }
+  };
+
+  return (
+    <div className="share-link-form p-3">
+      <h3 className="grw-modal-head pb-2"> { t('share_links.share_settings') }</h3>
+      <div className=" p-3">
+
+        {/* ExpirationTypeOptions */}
+        <div className="form-group row">
+          <label htmlFor="inputDesc" className="col-md-5 col-form-label">{t('share_links.expire')}</label>
+          <div className="col-md-7">
+
+            <div className="custom-control custom-radio form-group ">
+              <input
+                type="radio"
+                className="custom-control-input"
+                id="customRadio1"
+                name="expirationType"
+                value="customRadio1"
+                checked={expirationType === 'unlimited'}
+                onChange={() => { handleChangeExpirationType('unlimited') }}
+              />
+              <label className="custom-control-label" htmlFor="customRadio1">{t('share_links.Unlimited')}</label>
+            </div>
+
+            <div className="custom-control custom-radio  form-group">
+              <input
+                type="radio"
+                className="custom-control-input"
+                id="customRadio2"
+                value="customRadio2"
+                checked={expirationType === 'numberOfDays'}
+                onChange={() => { handleChangeExpirationType('numberOfDays') }}
+                name="expirationType"
+              />
+              <label className="custom-control-label" htmlFor="customRadio2">
+                <div className="row align-items-center m-0">
+                  <input
+                    type="number"
+                    min="1"
+                    className="col-4"
+                    name="expirationType"
+                    value={numberOfDays}
+                    onFocus={() => { handleChangeExpirationType('numberOfDays') }}
+                    onChange={e => handleChangeNumberOfDays(Number(e.target.value))}
+                  />
+                  <span className="col-auto">{t('share_links.Days')}</span>
+                </div>
+              </label>
+            </div>
+
+            <div className="custom-control custom-radio form-group text-nowrap mb-0">
+              <input
+                type="radio"
+                className="custom-control-input"
+                id="customRadio3"
+                name="expirationType"
+                value="customRadio3"
+                checked={expirationType === 'custom'}
+                onChange={() => { handleChangeExpirationType('custom') }}
+              />
+              <label className="custom-control-label" htmlFor="customRadio3">
+                {t('share_links.Custom')}
+              </label>
+              <div className="d-inline-flex flex-wrap">
+                <input
+                  type="date"
+                  className="ml-3 mb-2"
+                  name="customExpirationDate"
+                  value={customExpirationDate}
+                  onFocus={() => { handleChangeExpirationType('custom') }}
+                  onChange={e => handleChangeCustomExpirationDate(e.target.value)}
+                />
+                <input
+                  type="time"
+                  className="ml-3 mb-2"
+                  name="customExpiration"
+                  value={customExpirationTime}
+                  onFocus={() => { handleChangeExpirationType('custom') }}
+                  onChange={e => handleChangeCustomExpirationTime(e.target.value)}
+                />
+              </div>
+            </div>
+          </div>
+        </div>
+
+        {/* DescriptionForm */}
+        <div className="form-group row">
+          <label htmlFor="inputDesc" className="col-md-5 col-form-label">{t('share_links.description')}</label>
+          <div className="col-md-4">
+            <input
+              type="text"
+              className="form-control"
+              id="inputDesc"
+              placeholder={t('share_links.enter_desc')}
+              value={description}
+              onChange={e => handleChangeDescription(e.target.value)}
+            />
+          </div>
+        </div>
+        <button type="button" className="btn btn-primary d-block mx-auto px-5" onClick={handleIssueShareLink}>
+          {t('share_links.Issue')}
+        </button>
+      </div>
+    </div>
+  );
+};

+ 1 - 1
packages/app/src/components/ShareLink/ShareLinkForm.jsx → packages/app/src/components/ShareLink/_ShareLinkForm.jsx

@@ -2,8 +2,8 @@ import React from 'react';
 
 
 import { isInteger } from 'core-js/fn/number';
 import { isInteger } from 'core-js/fn/number';
 import { format, parse } from 'date-fns';
 import { format, parse } from 'date-fns';
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
+import PropTypes from 'prop-types';
 
 
 import PageContainer from '~/client/services/PageContainer';
 import PageContainer from '~/client/services/PageContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';