QuestionnaireToast.tsx 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { useCallback, useState, type JSX } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import { apiv3Put } from '~/client/util/apiv3-client';
  4. import { toastSuccess } from '~/client/util/toastr';
  5. import { useQuestionnaireModal } from '~/features/questionnaire/client/stores/model';
  6. import { useCurrentUser } from '~/stores-universal/context';
  7. import loggerFactory from '~/utils/logger';
  8. import { StatusType } from '../../interfaces/questionnaire-answer-status';
  9. import type { IQuestionnaireOrderHasId } from '../../interfaces/questionnaire-order';
  10. import { GuestQuestionnaireAnswerStatusService } from '../services/guest-questionnaire-answer-status';
  11. const logger = loggerFactory('growi:QuestionnaireToast');
  12. type QuestionnaireToastProps = {
  13. questionnaireOrder: IQuestionnaireOrderHasId,
  14. }
  15. const QuestionnaireToast = ({ questionnaireOrder }: QuestionnaireToastProps): JSX.Element => {
  16. const { open: openQuestionnaireModal } = useQuestionnaireModal();
  17. const { data: currentUser } = useCurrentUser();
  18. const lang = currentUser?.lang;
  19. const [isOpen, setIsOpen] = useState(true);
  20. const { t } = useTranslation();
  21. const answerBtnClickHandler = useCallback(() => {
  22. openQuestionnaireModal(questionnaireOrder._id, () => setIsOpen(false));
  23. }, [openQuestionnaireModal, questionnaireOrder._id]);
  24. const denyBtnClickHandler = useCallback(async() => {
  25. // Immediately close
  26. setIsOpen(false);
  27. try {
  28. await apiv3Put('/questionnaire/deny', {
  29. questionnaireOrderId: questionnaireOrder._id,
  30. });
  31. if (currentUser == null) {
  32. GuestQuestionnaireAnswerStatusService.setStatus(questionnaireOrder._id, StatusType.denied);
  33. }
  34. toastSuccess(t('questionnaire.denied'));
  35. }
  36. catch (e) {
  37. logger.error(e);
  38. }
  39. }, [questionnaireOrder._id, t, currentUser]);
  40. // No showing toasts since not important
  41. const closeBtnClickHandler = useCallback(async() => {
  42. setIsOpen(false);
  43. try {
  44. await apiv3Put('/questionnaire/skip', {
  45. questionnaireOrderId: questionnaireOrder._id,
  46. });
  47. if (currentUser == null) {
  48. GuestQuestionnaireAnswerStatusService.setStatus(questionnaireOrder._id, StatusType.skipped);
  49. }
  50. }
  51. catch (e) {
  52. logger.error(e);
  53. }
  54. }, [questionnaireOrder._id, currentUser]);
  55. const questionnaireOrderShortTitle = lang === 'en_US' ? questionnaireOrder.shortTitle.en_US : questionnaireOrder.shortTitle.ja_JP;
  56. return (
  57. <div className={`toast ${isOpen ? 'show' : 'hide'}`}>
  58. <div className="toast-header bg-primary">
  59. <strong className="me-auto text-light">{questionnaireOrderShortTitle}</strong>
  60. <button type="button" className="ms-2 mb-1 btn-close" onClick={closeBtnClickHandler} aria-label="Close"></button>
  61. </div>
  62. <div className="toast-body bg-light text-dark d-flex justify-content-end">
  63. <button type="button" className="btn btn-secondary me-3" onClick={answerBtnClickHandler}>{t('questionnaire.answer')}</button>
  64. <button type="button" className="btn btn-secondary" onClick={denyBtnClickHandler}>{t('questionnaire.deny')}</button>
  65. </div>
  66. </div>
  67. );
  68. };
  69. export default QuestionnaireToast;