Skip to content
Snippets Groups Projects
FeedbackModal.tsx 7.19 KiB
Newer Older
  • Learn to ignore specific revisions
  • Yoan Vallet's avatar
    Yoan Vallet committed
    import React, { useState } from 'react'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    import { withClient, Client } from 'cozy-client'
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    import { translate } from 'cozy-ui/react/I18n'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    import { detect } from 'detect-browser'
    
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    import Modal from 'components/CommonKit/Modal/Modal'
    
    import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    import StyledButton from 'components/CommonKit/Button/StyledButton'
    
    import StyledIconBorderedButton from 'components/CommonKit/IconButton/StyledIconBorderedButton'
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    
    import BugOnIcon from 'assets/icons/visu/feedback/bug-on.svg'
    import BugOffIcon from 'assets/icons/visu/feedback/bug-off.svg'
    import IdeaOnIcon from 'assets/icons/visu/feedback/idea-on.svg'
    
    import IdeaOffIcon from 'assets/icons/visu/feedback/idea-off.svg'
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    import OtherOnIcon from 'assets/icons/visu/feedback/other-on.svg'
    import OtherOffIcon from 'assets/icons/visu/feedback/other-off.svg'
    
    import warningIcon from 'assets/icons/ico/warning-yellow.svg'
    
    import successIcon from 'assets/icons/visu/data-ok.svg'
    
    const FEEDBACK_EMAIL = 'ecolyo@grandlyon.com'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    const browser = detect()
    
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    interface FeedbackModalProps {
      opened: boolean
      handleCloseClick: () => void
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      t: Function
      client: Client
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    }
    
    const FeedbackModal: React.FC<FeedbackModalProps> = ({
      opened,
      handleCloseClick,
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      t,
      client,
    
    Yoan Vallet's avatar
    Yoan Vallet committed
    }: FeedbackModalProps) => {
      const [type, setType] = useState<string>('bug')
      const [description, setDescription] = useState<string>('')
      const [email, setEmail] = useState<string>('')
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      const [sending, setSending] = useState<boolean>(false)
      const [sent, setSent] = useState<boolean>(false)
    
      const [error, setError] = useState<string>('')
    
    Yoan Vallet's avatar
    Yoan Vallet committed
      const resetInputs = () => {
    
        setType('bug')
        setDescription('')
        setEmail('')
    
    Yoan Vallet's avatar
    Yoan Vallet committed
        setSent(false)
    
        setError('')
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      const closeModal = () => {
    
    Yoan Vallet's avatar
    Yoan Vallet committed
        resetInputs()
    
    Yoan VALLET's avatar
    Yoan VALLET committed
        handleCloseClick()
      }
    
      const sendEmail = async () => {
        setSending(true)
    
        if (description === '') {
          setError(t('feedback.error_empty_description'))
        } else {
          const envInfo =
            `Ecolyo` +
            `\nv${client.appMetadata.version}` +
            `\n\nLocation: ${window.location}` +
            '\n\nBrowser:' +
            `\nOn ${browser && browser.os}` +
            `\nFrom ${browser && browser.name}` +
            `\n${browser && browser.version}` +
            '\n\nNavigator:' +
            `\nOn ${navigator.platform}` +
            `\nFrom ${navigator.vendor}` +
            `\n${navigator.userAgent}`
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
    
          const mailContent =
            'Type: ' +
    
            t('feedback.type_' + type) +
    
            '\n\nDescription:\n' +
            description +
            '\n\nEmail: ' +
            email +
            '\n_______________\n' +
            envInfo
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
    
          const mailData = {
            mode: 'from',
            to: [{ name: 'Support', email: FEEDBACK_EMAIL }],
    
            subject: '[Ecolyo] - Feedbacks - ' + t('feedback.type_' + type),
    
            parts: [{ type: 'text/plain', body: mailContent }],
          }
          try {
            const jobCollection = client.collection('io.cozy.jobs')
            await jobCollection.create('sendmail', mailData)
          } catch (e) {
            // eslint-disable-next-line no-console
            console.error(e)
            setError(t('feedback.error_sending'))
          }
    
    Yoan VALLET's avatar
    Yoan VALLET committed
        }
        setSending(false)
    
        setSent(true)
      }
    
      const validResult = () => {
        setSent(false)
        setError('')
        if (error === '') {
    
    Yoan Vallet's avatar
    Yoan Vallet committed
          resetInputs()
    
          closeModal()
        }
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      }
    
      const getOnIcon = (_type: string) => {
        switch (_type) {
          case 'bug':
            return BugOnIcon
          case 'idea':
            return IdeaOnIcon
          case 'other':
            return OtherOnIcon
          default:
            return BugOnIcon
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      }
      const getOffIcon = (_type: string) => {
        switch (_type) {
          case 'bug':
            return BugOffIcon
          case 'idea':
            return IdeaOffIcon
          case 'other':
            return OtherOffIcon
          default:
            return BugOffIcon
        }
      }
    
      const selectorItem = (itemType: string) => {
    
        const selected = type === itemType
        return (
          <div className="fb-selector-item">
            <StyledIconBorderedButton
              icon={selected ? getOnIcon(itemType) : getOffIcon(itemType)}
              selected={selected}
              size={36}
              onClick={() => setType(itemType)}
            >
              <div
                className={
                  selected
    
                    ? 'fb-selector-item-selectedlabel text-10-bold'
    
                    : 'fb-selector-item-label text-10-normal'
                }
              >
                {t('feedback.type_' + itemType)}
              </div>
            </StyledIconBorderedButton>
          </div>
        )
    
    Yoan VALLET's avatar
    Yoan VALLET committed
        <Modal open={opened} yellowBorder={true} handleCloseClick={closeModal}>
    
          {sent ? (
            <div className="fb-root">
              <div className="fb-content">
                {error === '' ? (
                  <div className="fb-content-success">
                    <div className="fb-icon">
                      <StyledIcon icon={successIcon} size={48} />
                    </div>
                    <div>{t('feedback.success_sending')}</div>
                  </div>
                ) : (
                  <div className="fb-content-error">
                    <div className="fb-icon">
    
                      <StyledIcon icon={warningIcon} size={48} />
    
                    </div>
    
                    <div>{t('feedback.warning')}</div>
    
                    <div>{error}</div>
                  </div>
                )}
                <StyledButton
                  className="fb-button"
                  color="primary"
                  onClick={validResult}
                >
                  {t('feedback.ok')}
                </StyledButton>
    
              </div>
    
            </div>
          ) : (
            <div className="fb-root">
              <div className="fb-header text-18-bold">{t('feedback.title')}</div>
              <div className="fb-content">
                <div className="fb-label text-16-bold">{t('feedback.type')}</div>
                <div className="fb-selector">
                  {selectorItem('bug')}
                  {selectorItem('idea')}
                  {selectorItem('other')}
                </div>
                <div className="fb-label text-16-bold">
                  {t('feedback.description')}
                </div>
                <textarea
                  id="idFeedbackDescription"
                  className="fb-form fb-textarea"
                  aria-describedby="Feedbacks description"
                  placeholder={t('feedback.description_placeholder')}
                  name="description"
                  onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
                    setDescription(e.target.value)
                  }
                  value={description}
                ></textarea>
                <div className="fb-label text-15-normal">{t('feedback.email')}</div>
                <input
                  id="idFeedbackEmail"
                  type="text"
                  className="fb-form fb-input"
                  aria-describedby="Feedbacks email"
                  placeholder={t('feedback.email_placeholder')}
                  name="email"
                  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                    setEmail(e.target.value)
                  }
                  value={email}
                />
                <StyledButton
                  className="fb-button"
                  color="primary"
                  onClick={sendEmail}
                  disabled={sending}
                >
                  {t('feedback.send')}
                </StyledButton>
    
              </div>
    
    Yoan Vallet's avatar
    Yoan Vallet committed
            </div>
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    export default translate()(withClient(FeedbackModal))