From abde7f409c05899e79cd0b3dac42c91b855e6565 Mon Sep 17 00:00:00 2001
From: Yoan VALLET <ext.sopra.yvallet@grandlyon.com>
Date: Wed, 3 Jun 2020 22:30:44 +0200
Subject: [PATCH] feat: handle LOGIN_FAILED case

---
 .../Konnector/KonnectorForm.tsx               | 34 +++++-----
 ...nnectorLoading.tsx => KonnectorLaunch.tsx} | 15 +++--
 .../Konnector/KonnectorLoginForm.tsx          | 43 ++++++++----
 .../KonnectorViewer/KonnectorViewerCard.tsx   | 66 +++++++++++++++----
 .../ContentComponents/OAuth/OAuthForm.tsx     |  1 +
 src/doctypes/io-cozy-triggers.ts              | 12 ++++
 6 files changed, 119 insertions(+), 52 deletions(-)
 rename src/components/ContentComponents/Konnector/{KonnectorLoading.tsx => KonnectorLaunch.tsx} (85%)

diff --git a/src/components/ContentComponents/Konnector/KonnectorForm.tsx b/src/components/ContentComponents/Konnector/KonnectorForm.tsx
index c85fece9a..e02336b88 100644
--- a/src/components/ContentComponents/Konnector/KonnectorForm.tsx
+++ b/src/components/ContentComponents/Konnector/KonnectorForm.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react'
+import React from 'react'
 import { translate } from 'cozy-ui/react/I18n'
 
 import IFluidConfig from 'services/IFluidConfig'
@@ -6,46 +6,42 @@ import { Konnector, Trigger } from 'doctypes'
 
 import KonnectorLoginForm from 'components/ContentComponents/Konnector/KonnectorLoginForm'
 import KonnectorOAuthForm from 'components/ContentComponents/Konnector/KonnectorOAuthForm'
-import KonnectorLoading from 'components/ContentComponents/Konnector/KonnectorLoading'
 
 interface KonnectorFormProps {
   fluidConfig: IFluidConfig
   konnector: Konnector
-  handleConnexion: Function
+  account: Account | null
+  trigger: Trigger | null
+  handleSuccessForm: Function
 }
 
 const KonnectorForm: React.FC<KonnectorFormProps> = ({
   fluidConfig,
   konnector,
-  handleConnexion,
+  account,
+  trigger,
+  handleSuccessForm,
 }: KonnectorFormProps) => {
   const oAuth: boolean = fluidConfig.konnectorConfig.oauth
-  const [account, setAccount] = useState<Account | null>(null)
-  const [trigger, setTrigger] = useState<Trigger | null>(null)
 
-  const handleForm = (_account: Account, _trigger: Trigger) => {
-    setAccount(_account)
-    setTrigger(_trigger)
-  }
-
-  const handleKonnectorLoading = () => {
-    handleConnexion(account)
+  const handleSuccess = (_account: Account, _trigger: Trigger) => {
+    handleSuccessForm(_account, _trigger)
   }
 
   return (
     <>
-      {account && trigger ? (
-        <KonnectorLoading
+      {!oAuth ? (
+        <KonnectorLoginForm
+          fluidConfig={fluidConfig}
+          onSuccess={handleSuccess}
+          account={account}
           trigger={trigger}
-          handleKonnectorLoading={handleKonnectorLoading}
         />
-      ) : !oAuth ? (
-        <KonnectorLoginForm fluidConfig={fluidConfig} onSuccess={handleForm} />
       ) : (
         <KonnectorOAuthForm
           konnector={konnector}
           siteLink={fluidConfig.siteLink}
-          onSuccess={handleForm}
+          onSuccess={handleSuccess}
         />
       )}
     </>
diff --git a/src/components/ContentComponents/Konnector/KonnectorLoading.tsx b/src/components/ContentComponents/Konnector/KonnectorLaunch.tsx
similarity index 85%
rename from src/components/ContentComponents/Konnector/KonnectorLoading.tsx
rename to src/components/ContentComponents/Konnector/KonnectorLaunch.tsx
index a0a3ea348..9cf2abb7f 100644
--- a/src/components/ContentComponents/Konnector/KonnectorLoading.tsx
+++ b/src/components/ContentComponents/Konnector/KonnectorLaunch.tsx
@@ -23,21 +23,21 @@ const loadingOptions = {
   },
 }
 
-interface KonnectorLoadingProps {
+interface KonnectorLaunchProps {
   trigger: Trigger
-  handleKonnectorLoading: Function
+  handleKonnectorLaunch: Function
   client: Client
   t: Function
 }
 
-const KonnectorLoading: React.FC<KonnectorLoadingProps> = ({
+const KonnectorLaunch: React.FC<KonnectorLaunchProps> = ({
   trigger,
-  handleKonnectorLoading,
+  handleKonnectorLaunch,
   client,
   t,
-}: KonnectorLoadingProps) => {
+}: KonnectorLaunchProps) => {
   const callbackResponse = () => {
-    handleKonnectorLoading()
+    handleKonnectorLaunch()
   }
 
   useEffect(() => {
@@ -63,6 +63,7 @@ const KonnectorLoading: React.FC<KonnectorLoadingProps> = ({
     }
   }, [])
 
+  // TODO - SUCCESS SCREEN
   return (
     <div className="kload-content">
       <Lottie options={loadingOptions} height={50} width={50} />
@@ -76,4 +77,4 @@ const KonnectorLoading: React.FC<KonnectorLoadingProps> = ({
   )
 }
 
-export default translate()(withClient(KonnectorLoading))
+export default translate()(withClient(KonnectorLaunch))
diff --git a/src/components/ContentComponents/Konnector/KonnectorLoginForm.tsx b/src/components/ContentComponents/Konnector/KonnectorLoginForm.tsx
index 6726c6af3..a4023ac83 100644
--- a/src/components/ContentComponents/Konnector/KonnectorLoginForm.tsx
+++ b/src/components/ContentComponents/Konnector/KonnectorLoginForm.tsx
@@ -8,10 +8,13 @@ import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton'
 import StyledButton from 'components/CommonKit/Button/StyledButton'
 import TrailingIcon from 'assets/icons/ico/trailing-icon.svg'
 import { ConnectionService } from 'services/connectionService'
+import { Account, Trigger } from 'doctypes'
 
 interface KonnectorLoginFormProps {
   fluidConfig: IFluidConfig
   onSuccess: Function
+  account: Account
+  trigger: Trigger
   client: Client
   t: Function
 }
@@ -19,6 +22,8 @@ interface KonnectorLoginFormProps {
 const KonnectorLoginForm: React.FC<KonnectorLoginFormProps> = ({
   fluidConfig,
   onSuccess,
+  account,
+  trigger,
   client,
   t,
 }: KonnectorLoginFormProps) => {
@@ -42,6 +47,27 @@ const KonnectorLoginForm: React.FC<KonnectorLoginFormProps> = ({
     }
   }
 
+  const connect = async () => {
+    const connectionService = new ConnectionService(
+      client,
+      fluidConfig.konnectorConfig.slug,
+      login,
+      password
+    )
+    const { account, trigger } = await connectionService.connectNewUser()
+    if (!trigger) {
+      setError(t('KONNECTORCONFIG.ERROR_ACCOUNT_CREATION'))
+      setLoading(false)
+      return null
+    }
+    onSuccess(account, trigger)
+  }
+
+  const update = async () => {
+    // TODO - update account
+    onSuccess(account, trigger)
+  }
+
   const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
     e.preventDefault()
     try {
@@ -52,24 +78,17 @@ const KonnectorLoginForm: React.FC<KonnectorLoginFormProps> = ({
         setLoading(false)
         return null
       }
-      const connectionService = new ConnectionService(
-        client,
-        fluidConfig.konnectorConfig.slug,
-        login,
-        password
-      )
-      const { account, trigger } = await connectionService.connectNewUser()
-      if (!trigger) {
-        setError(t('KONNECTORCONFIG.ERROR_ACCOUNT_CREATION'))
-        setLoading(false)
-        return null
+      if (!account) {
+        await connect()
+      } else {
+        await update()
       }
-      onSuccess(account, trigger)
     } catch (error) {
       setLoading(false)
     }
   }
 
+  // TODO - if received account from props = display error login failed
   return (
     <form
       className="form"
diff --git a/src/components/ContentComponents/KonnectorViewer/KonnectorViewerCard.tsx b/src/components/ContentComponents/KonnectorViewer/KonnectorViewerCard.tsx
index 8074ff68e..70b9eeaec 100644
--- a/src/components/ContentComponents/KonnectorViewer/KonnectorViewerCard.tsx
+++ b/src/components/ContentComponents/KonnectorViewer/KonnectorViewerCard.tsx
@@ -19,9 +19,11 @@ import IFluidConfig from 'services/IFluidConfig'
 import KonnectorNotFound from 'components/ContentComponents/Konnector/KonnectorNotFound'
 import KonnectorForm from 'components/ContentComponents/Konnector/KonnectorForm'
 import KonnectorResult from 'components/ContentComponents/Konnector/KonnectorResult'
+import KonnectorLaunch from 'components/ContentComponents/Konnector/KonnectorLaunch'
 
-import { Konnector } from 'doctypes'
+import { Konnector, Trigger, TriggerState } from 'doctypes'
 import { JobState } from 'services/jobsService'
+import { TriggerService } from 'services/triggersService'
 
 interface KonnectorViewerCardProps {
   fluidConfig: IFluidConfig
@@ -39,6 +41,9 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
   t,
 }: KonnectorViewerCardProps) => {
   const [account, setAccount] = useState<Account | null>(null)
+  const [trigger, setTrigger] = useState<Trigger | null>(null)
+  const [triggerState, setTriggerState] = useState<TriggerState | null>(null)
+  const [shouldLaunch, setLaunch] = useState<boolean>(false)
 
   const [setActive, setActiveState] = useState('')
   const [setHeight, setHeightState] = useState('0px')
@@ -51,6 +56,10 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
   const iconType = getPicto(fluid)
 
   const iconAddType = isParam ? getParamPicto(fluid) : getAddPicto(fluid)
+  const loginFailed: boolean =
+    triggerState != null &&
+    triggerState.last_error != undefined &&
+    triggerState.last_error === 'LOGIN_FAILED'
 
   const toggleAccordion = () => {
     setActiveState(setActive === '' ? 'active' : '')
@@ -72,8 +81,24 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
     )
   }
 
-  const handleConnexion = (_account: Account) => {
+  const updateState = async (trigger: Trigger) => {
+    const triggerState = await TriggerService.fetchTriggerState(client, trigger)
+    if (triggerState) {
+      setTriggerState(triggerState)
+    }
+  }
+
+  const handleSuccessForm = (_account: Account, _trigger: Trigger) => {
     setAccount(_account)
+    setTrigger(_trigger)
+    setLaunch(true)
+  }
+
+  const handleKonnectorLaunch = () => {
+    if (trigger) {
+      updateState(trigger)
+    }
+    setLaunch(false)
   }
 
   const handleJobState = (_jobState: JobState) => {
@@ -90,6 +115,14 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
         )
         if (subscribed && _account) {
           setAccount(_account)
+          const _trigger = await TriggerService.fetchTriggerFromAccount(
+            client,
+            _account
+          )
+          if (subscribed && _trigger) {
+            setTrigger(_trigger)
+            await updateState(_trigger)
+          }
         }
       }
     }
@@ -108,18 +141,18 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
             onClick={toggleAccordion}
           >
             <div className="accordion-icon">
-              {!account ? (
-                <StyledIcon className="icon" icon={iconAddType} size={49} />
-              ) : (
+              {account && !loginFailed ? (
                 <StyledIcon className="icon" icon={iconType} size={49} />
+              ) : (
+                <StyledIcon className="icon" icon={iconAddType} size={49} />
               )}
             </div>
             <div className="state-picto">{getKonnectorStateMarkup()}</div>
             <div className="accordion-info">
               <div className="accordion-title text-16-normal">
-                {!account
-                  ? t('KONNECTORCONFIG.LABEL_CONNECTTO_' + FluidType[fluid])
-                  : t('FLUID.' + FluidType[fluid] + '.LABEL')}
+                {account && !loginFailed
+                  ? t('FLUID.' + FluidType[fluid] + '.LABEL')
+                  : t('KONNECTORCONFIG.LABEL_CONNECTTO_' + FluidType[fluid])}
               </div>
             </div>
             <StyledIconButton icon={setActive ? chevronUp : chevronDown} />
@@ -134,17 +167,22 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
               <KonnectorNotFound
                 konnectorSlug={fluidConfig.konnectorConfig.slug}
               />
-            ) : !account ? (
-              <KonnectorForm
-                fluidConfig={fluidConfig}
-                konnector={konnector}
-                handleConnexion={handleConnexion}
+            ) : shouldLaunch && trigger ? (
+              <KonnectorLaunch
+                trigger={trigger}
+                handleKonnectorLaunch={handleKonnectorLaunch}
               />
-            ) : (
+            ) : account && !loginFailed ? (
               <KonnectorResult
                 account={account}
                 handleJobState={handleJobState}
               />
+            ) : (
+              <KonnectorForm
+                fluidConfig={fluidConfig}
+                konnector={konnector}
+                handleSuccessForm={handleSuccessForm}
+              />
             )}
           </div>
         </div>
diff --git a/src/components/ContentComponents/OAuth/OAuthForm.tsx b/src/components/ContentComponents/OAuth/OAuthForm.tsx
index fb8b91c0f..b0d982ad9 100644
--- a/src/components/ContentComponents/OAuth/OAuthForm.tsx
+++ b/src/components/ContentComponents/OAuth/OAuthForm.tsx
@@ -13,6 +13,7 @@ import StyledBlackSpinner from 'components/CommonKit/Spinner/StyledBlackSpinner'
 interface OAuthFormProps {
   konnector: Konnector
   onSuccess: Function
+  loginFailed: boolean
   client: Client
   t: Function
 }
diff --git a/src/doctypes/io-cozy-triggers.ts b/src/doctypes/io-cozy-triggers.ts
index 9eb418912..60e696f4a 100644
--- a/src/doctypes/io-cozy-triggers.ts
+++ b/src/doctypes/io-cozy-triggers.ts
@@ -11,6 +11,18 @@ export type Trigger = {
   }
 }
 
+export type TriggerState = {
+  trigger_id: string
+  status: string
+  last_error?: string
+  last_executed_job_id: string
+  last_execution: string
+  last_failed_job_id: string
+  last_failure: string
+  last_manual_execution: string
+  last_manual_job_id: string
+}
+
 export function isTrigger(trigger: any): trigger is Trigger {
   return (
     trigger &&
-- 
GitLab