Răsfoiți Sursa

refs 116536: manage guest questionnaire answer status using updatedDate

Futa Arai 3 ani în urmă
părinte
comite
d58608e5e3

+ 79 - 0
packages/app/src/client/services/guest-questionnaire-answer-status.ts

@@ -0,0 +1,79 @@
+// A service to manage questionnaire answer statuses for guest user.
+// Saves statuses in localStorage.
+
+import { StatusType } from '~/interfaces/questionnaire/questionnaire-answer-status';
+
+interface GuestQuestionnaireAnswerStatus {
+  status: StatusType
+  updatedDate: string
+}
+
+interface GuestQuestionnaireAnswerStatusStorage {
+  [key: string]: GuestQuestionnaireAnswerStatus
+}
+
+const storageKey = 'guestQuestionnaireAnswerStatuses';
+const daysUntilExpiration = 30;
+
+/**
+ * Get all answer statuses stored in localStorage as GuestQuestionnaireAnswerStatusStorage,
+ * and update outdated information.
+ */
+const getStorage = (): GuestQuestionnaireAnswerStatusStorage | null => {
+  if (typeof window !== 'undefined') {
+    const currentStorage = localStorage.getItem(storageKey);
+    if (currentStorage) {
+      const storageJson: GuestQuestionnaireAnswerStatusStorage = JSON.parse(currentStorage);
+
+      // delete status if outdated
+      // change skipped to not_answered if different date than when skipped
+      Object.keys(storageJson).forEach((key) => {
+        const answerStatus = storageJson[key];
+        const updatedDate = new Date(answerStatus.updatedDate);
+        const expirationDate = new Date(updatedDate.setDate(updatedDate.getDate() + daysUntilExpiration));
+        if (expirationDate < new Date()) {
+          delete storageJson[key];
+        }
+        else if (answerStatus.status === StatusType.skipped
+          && new Date().toDateString() !== answerStatus.updatedDate) {
+          storageJson[key] = {
+            status: StatusType.not_answered,
+            updatedDate: new Date().toDateString(),
+          };
+        }
+      });
+
+      return storageJson;
+    }
+  }
+  return null;
+};
+
+/**
+ * Set answer status for questionnaire order in GuestQuestionnaireAnswerStatusStorage,
+ * and save it in localStorage.
+ */
+const setStatus = (questionnaireOrderId: string, status: StatusType): void => {
+  if (typeof window !== 'undefined') {
+    const guestQuestionnaireAnswerStatus: GuestQuestionnaireAnswerStatus = {
+      status,
+      updatedDate: new Date().toDateString(),
+    };
+
+    const storage = getStorage();
+
+    if (storage) {
+      storage[questionnaireOrderId] = guestQuestionnaireAnswerStatus;
+      localStorage.setItem(storageKey, JSON.stringify(storage));
+    }
+    else {
+      const initialStorage: GuestQuestionnaireAnswerStatusStorage = { [questionnaireOrderId]: guestQuestionnaireAnswerStatus };
+      localStorage.setItem(storageKey, JSON.stringify(initialStorage));
+    }
+  }
+};
+
+export const GuestQuestionnaireAnswerStatusService = {
+  setStatus,
+  getStorage,
+};

+ 4 - 3
packages/app/src/components/Questionnaire/QuestionnaireModal.tsx

@@ -3,6 +3,7 @@ import { useCallback } from 'react';
 import { useTranslation } from 'next-i18next';
 import { Modal, ModalBody } from 'reactstrap';
 
+import { GuestQuestionnaireAnswerStatusService } from '~/client/services/guest-questionnaire-answer-status';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 import { IAnswer } from '~/interfaces/questionnaire/answer';
@@ -38,7 +39,7 @@ const QuestionnaireModal = ({ questionnaireOrder }: QuestionnaireModalProps): JS
         answers,
       });
       if (!currentUser) {
-        localStorage.setItem(questionnaireOrder._id, StatusType.answered);
+        GuestQuestionnaireAnswerStatusService.setStatus(questionnaireOrder._id, StatusType.answered);
       }
       toastSuccess(
         <>
@@ -77,7 +78,7 @@ const QuestionnaireModal = ({ questionnaireOrder }: QuestionnaireModalProps): JS
         questionnaireOrderId: questionnaireOrder._id,
       });
       if (!currentUser) {
-        localStorage.setItem(questionnaireOrder._id, StatusType.denied);
+        GuestQuestionnaireAnswerStatusService.setStatus(questionnaireOrder._id, StatusType.denied);
       }
       toastSuccess(t('questionnaire.denied'));
     }
@@ -97,7 +98,7 @@ const QuestionnaireModal = ({ questionnaireOrder }: QuestionnaireModalProps): JS
         questionnaireOrderId: questionnaireOrder._id,
       });
       if (!currentUser) {
-        localStorage.setItem(questionnaireOrder._id, StatusType.skipped);
+        GuestQuestionnaireAnswerStatusService.setStatus(questionnaireOrder._id, StatusType.skipped);
       }
     }
     catch (e) {

+ 6 - 3
packages/app/src/components/Questionnaire/QuestionnaireModalManager.tsx

@@ -1,3 +1,4 @@
+import { GuestQuestionnaireAnswerStatusService } from '~/client/services/guest-questionnaire-answer-status';
 import { StatusType } from '~/interfaces/questionnaire/questionnaire-answer-status';
 import { IQuestionnaireOrderHasId } from '~/interfaces/questionnaire/questionnaire-order';
 import { useCurrentUser } from '~/stores/context';
@@ -13,12 +14,14 @@ const QuestionnaireModalManager = ():JSX.Element => {
   const { data: currentUser } = useCurrentUser();
 
   const questionnaireOrdersToShow = (questionnaireOrders: IQuestionnaireOrderHasId[] | undefined) => {
-    if (currentUser) {
+    const guestQuestionnaireAnswerStorage = GuestQuestionnaireAnswerStatusService.getStorage();
+    if (currentUser || !guestQuestionnaireAnswerStorage) {
       return questionnaireOrders;
     }
+
     return questionnaireOrders?.filter((questionnaireOrder) => {
-      const localAnswerStatus = localStorage.getItem(questionnaireOrder._id);
-      return !localAnswerStatus || localAnswerStatus === StatusType.not_answered;
+      const localAnswerStatus = guestQuestionnaireAnswerStorage[questionnaireOrder._id];
+      return !localAnswerStatus || localAnswerStatus.status === StatusType.not_answered;
     });
   };
 

+ 3 - 2
packages/app/src/components/Questionnaire/QuestionnaireToast.tsx

@@ -2,6 +2,7 @@ import { useCallback, useState } from 'react';
 
 import { useTranslation } from 'next-i18next';
 
+import { GuestQuestionnaireAnswerStatusService } from '~/client/services/guest-questionnaire-answer-status';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastSuccess } from '~/client/util/toastr';
 import { StatusType } from '~/interfaces/questionnaire/questionnaire-answer-status';
@@ -38,7 +39,7 @@ const QuestionnaireToast = ({ questionnaireOrder }: QuestionnaireToastProps): JS
         questionnaireOrderId: questionnaireOrder._id,
       });
       if (!currentUser) {
-        localStorage.setItem(questionnaireOrder._id, StatusType.denied);
+        GuestQuestionnaireAnswerStatusService.setStatus(questionnaireOrder._id, StatusType.denied);
       }
       toastSuccess(t('questionnaire.denied'));
     }
@@ -56,7 +57,7 @@ const QuestionnaireToast = ({ questionnaireOrder }: QuestionnaireToastProps): JS
         questionnaireOrderId: questionnaireOrder._id,
       });
       if (!currentUser) {
-        localStorage.setItem(questionnaireOrder._id, StatusType.skipped);
+        GuestQuestionnaireAnswerStatusService.setStatus(questionnaireOrder._id, StatusType.skipped);
       }
     }
     catch (e) {