Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • web-et-numerique/factory/llle_project/ecolyo
1 result
Select Git revision
Show changes
Showing
with 422 additions and 359 deletions
import React from 'react'
import React, { useState, useContext, useEffect } from 'react'
import { withClient, Client } from 'cozy-client'
import { translate } from 'cozy-ui/react/I18n'
import { AppContext } from 'components/Contexts/AppContextProvider'
import StyledButton from 'components/CommonKit/Button/StyledButton'
import StyledBlackSpinner from 'components/CommonKit/Spinner/StyledBlackSpinner'
import { Account, Trigger } from 'doctypes'
import { TriggerService } from 'services/triggersService'
import { AccountService } from 'services/accountService'
import { isKonnectorRunning } from 'cozy-harvest-lib/dist/helpers/triggers'
import {
KonnectorJob,
ERROR_EVENT,
LOGIN_SUCCESS_EVENT,
SUCCESS_EVENT,
} from 'cozy-harvest-lib/dist/models/KonnectorJob'
interface KonnectorResultProps {
date: string
updating: boolean
errored: boolean
updateKonnector: (event: any) => void
deleteAccount: (event: any) => void
account: Account
handleJobState: Function
client: Client
t: Function
}
const KonnectorResult: React.FC<KonnectorResultProps> = ({
date,
updating,
errored,
updateKonnector,
deleteAccount,
account,
handleJobState,
client,
t,
}: KonnectorResultProps) => {
const [trigger, setTrigger] = useState<Trigger | null>(null)
const [updating, setUpdating] = useState<boolean>(false)
const [lastExecutionDate, setLastExecutionDate] = useState<string>('-')
const [status, setStatus] = useState<string>('')
const context = useContext(AppContext)
const updateState = async (trigger: Trigger) => {
const triggerState = await TriggerService.fetchTriggerState(client, trigger)
if (triggerState) {
setLastExecutionDate(
new Date(triggerState.last_execution).toLocaleString()
)
setStatus(triggerState.status)
handleJobState(triggerState.status)
await context.refreshFluidTypes()
}
}
const callbackResponse = async () => {
if (trigger) {
await updateState(trigger)
}
setUpdating(false)
}
const updateKonnector = async () => {
setUpdating(true)
setStatus('')
setLastExecutionDate('-')
handleJobState('')
if (trigger && !isKonnectorRunning(trigger)) {
const konnectorJob = new KonnectorJob(client, trigger)
await konnectorJob.launch()
konnectorJob.jobWatcher.on(ERROR_EVENT, () => {
callbackResponse()
})
konnectorJob.jobWatcher.on(LOGIN_SUCCESS_EVENT, () => {
callbackResponse()
})
konnectorJob.jobWatcher.on(SUCCESS_EVENT, () => {
callbackResponse()
})
}
}
const deleteAccount = async () => {
setUpdating(true)
try {
if (account) {
await AccountService.deleteAccount(client, account)
await context.refreshFluidTypes()
}
} catch (error) {
setUpdating(false)
}
}
useEffect(() => {
let subscribed = true
async function getData() {
const _trigger = await TriggerService.fetchTriggerFromAccount(
client,
account
)
if (subscribed && _trigger) {
setTrigger(_trigger)
await updateState(_trigger)
}
}
getData()
return () => {
subscribed = false
}
}, [])
return (
<div className="accordion-update-result">
<div className="accordion-update">
<div
className={
errored
status === 'errored'
? 'accordion-caption-red text-16-normal'
: 'accordion-caption text-16-normal'
}
>
{t('KONNECTORCONFIG.LABEL_UPDATEDAT')}
</div>
<div>{date}</div>
<div>{lastExecutionDate}</div>
</div>
<div className="inline-buttons">
<StyledButton type="button" color="primary" onClick={updateKonnector}>
<StyledButton
type="button"
color="primary"
onClick={updateKonnector}
disabled={updating}
>
{updating ? (
<StyledBlackSpinner size="2em" />
) : (
......@@ -56,4 +149,4 @@ const KonnectorResult: React.FC<KonnectorResultProps> = ({
)
}
export default translate()(KonnectorResult)
export default translate()(withClient(KonnectorResult))
......@@ -3,7 +3,6 @@ import { withClient, Client } from 'cozy-client'
import { Konnector } from 'doctypes'
import KonnectorService from 'services/konnectorService'
import KonnectorStatusService from 'services/konnectorStatusService'
import KonnectorViewerCard from 'components/ContentComponents/KonnectorViewer/KonnectorViewerCard'
import IFluidConfig from 'services/IFluidConfig'
......@@ -20,7 +19,7 @@ const KonnectorViewer: React.FC<KonnectorViewerProps> = ({
isParam = false,
}: KonnectorViewerProps) => {
const [konnector, setKonnector] = useState<Konnector | null>(null)
const [lastTrigger, setLastTrigger] = useState<any>(null)
const [loaded, setLoaded] = useState<boolean>(false)
useEffect(() => {
let subscribed = true
......@@ -28,35 +27,15 @@ const KonnectorViewer: React.FC<KonnectorViewerProps> = ({
client,
fluidConfig.konnectorConfig.slug
)
const kss = new KonnectorStatusService(client)
async function getData() {
const _konnector: Konnector = await konnectorService.fetchKonnector()
if (!_konnector || !_konnector.slug) {
throw new Error(
`Could not find konnector for ${fluidConfig.konnectorConfig.slug}`
)
}
if (subscribed && _konnector) {
setKonnector(_konnector)
}
const allTriggers = await kss.getAllTriggers()
if (allTriggers) {
const lastTrigger = allTriggers
.filter(
trigger =>
trigger.worker === 'konnector' &&
trigger.message.konnector === fluidConfig.konnectorConfig.slug
)
.sort((a, b) => (new Date(a) > new Date(b) ? 1 : -1))
.shift()
if (subscribed && lastTrigger) {
setLastTrigger(lastTrigger)
}
if (subscribed) {
setLoaded(true)
}
}
getData()
return () => {
subscribed = false
......@@ -65,11 +44,10 @@ const KonnectorViewer: React.FC<KonnectorViewerProps> = ({
return (
<>
{!konnector ? null : (
{!loaded ? null : (
<KonnectorViewerCard
fluidConfig={fluidConfig}
konnector={konnector}
trigger={lastTrigger}
isParam={isParam}
/>
)}
......
import React, { useState, useEffect, useRef, useContext } from 'react'
import { ConnectionService } from 'services/connectionService'
import { TriggerService } from 'services/triggersService'
import React, { useState, useEffect, useRef } from 'react'
import { AccountService } from 'services/accountService'
import { AppContext } from 'components/Contexts/AppContextProvider'
import { JobService, JobState } from 'services/jobsService'
import { FluidType } from 'enum/fluid.enum'
import { withClient, Client } from 'cozy-client'
......@@ -18,21 +13,21 @@ import chevronUp from 'assets/icons/ico/chevron-up.svg'
import StyledIcon from 'components/CommonKit/Icon/StyledIcon'
import StyledIconButton from 'components/CommonKit/IconButton/StyledIconButton'
import failurePicto from 'components/ContentComponents/KonnectorViewer/picto-failure.png'
import KonnectorStatusService from 'services/konnectorStatusService'
import failurePicto from 'assets/png/picto/picto-failure.png'
import IFluidConfig from 'services/IFluidConfig'
import KonnectorNotFound from 'components/ContentComponents/Konnector/KonnectorNotFound'
import KonnectorForm from 'components/ContentComponents/Konnector/KonnectorForm'
import KonnectorOAuthForm from 'components/ContentComponents/Konnector/KonnectorOAuthForm'
import KonnectorLoading from 'components/ContentComponents/Konnector/KonnectorLoading'
import KonnectorResult from 'components/ContentComponents/Konnector/KonnectorResult'
import KonnectorLaunch from 'components/ContentComponents/Konnector/KonnectorLaunch'
import { Konnector, Trigger } from 'doctypes'
import { Konnector, Trigger, TriggerState } from 'doctypes'
import { JobState } from 'services/jobsService'
import { TriggerService } from 'services/triggersService'
interface KonnectorViewerCardProps {
fluidConfig: IFluidConfig
konnector: Konnector
trigger: any | null
client: Client
isParam: boolean
t: Function
......@@ -41,34 +36,32 @@ interface KonnectorViewerCardProps {
const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
fluidConfig,
konnector,
trigger,
client,
isParam,
t,
}: KonnectorViewerCardProps) => {
const [login, setLogin] = useState<string>('')
const [password, setPassword] = useState<string>('')
const [loading, setLoading] = useState<boolean>(false)
const [updating, setUpdating] = useState<boolean>(false)
const [konnectorAccountId, setAccountId] = useState<string>('')
const [isKonnectorAcc, setAccount] = useState<boolean>(false)
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')
const [updateTrigger, setUpdateTrigger] = useState<any>(null)
const [updateDate, setUpdateDate] = useState<string>(
new Date('0001-01-01T00:00:00Z').toDateString()
)
// const [frequency, setFrequency] = useState<string>('daily')
const [error, setError] = useState<string>('')
const [jobState, setJobState] = useState<string>('')
const [launchedJob, setlaunchedJob] = useState<any>(null)
const [isLoading, setLoading] = useState<boolean>(true)
const content: React.MutableRefObject<null> = useRef<null>(null)
const type: string = fluidConfig.konnectorConfig.type
const fluid: FluidType = getFuildType(type)
const iconType = getPicto(fluid)
const context = useContext(AppContext)
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' : '')
......@@ -82,260 +75,126 @@ const KonnectorViewerCard: React.FC<KonnectorViewerCardProps> = ({
)
}
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
try {
e.preventDefault()
setError('')
setLoading(true)
if (!login || !password) {
setError('Please enter a login and password')
setLoading(false)
return null
}
setJobState(JobState.Running)
const connectionService = new ConnectionService(
client,
fluidConfig.konnectorConfig.slug,
login,
password
)
const data = await connectionService.connectNewUser()
setLoading(false)
if (!data) {
setError('Error during the user connection')
setLoading(false)
setJobState(JobState.Errored)
return null
}
trigger = await KonnectorStatusService.getSingleTrigger(
client,
data.trigger_id
)
setUpdateTrigger(trigger)
setlaunchedJob(data)
setUpdateDate(new Date(data.queued_at).toDateString())
setAccountId(data.message.account)
setError('Connected')
setAccount(true)
return data
} catch (error) {
setLoading(false)
setError(error.message)
}
const getKonnectorStateMarkup = () => {
return jobState === JobState.Errored ? (
<img className="state-icon" src={failurePicto}></img>
) : (
''
)
}
const deleteAccount = async () => {
try {
const account = await AccountService.getAccount(
client,
konnectorAccountId
)
if (!account) {
setError('Error fetching account')
setLoading(false)
}
const delAccount = await AccountService.deleteAccount(client, account)
if (!delAccount) {
setError('Error during deletion account')
setLoading(false)
}
setError('')
setJobState('')
toggleAccordion()
trigger = null
setAccount(false)
await context.refreshFluidTypes()
} catch (error) {
setLoading(false)
setError(error.message)
const updateState = async (trigger: Trigger) => {
const triggerState = await TriggerService.fetchTriggerState(client, trigger)
if (triggerState) {
setTriggerState(triggerState)
}
}
const updateKonnector = async () => {
setError('')
setJobState('')
setUpdating(true)
try {
const account = await AccountService.getAccount(
client,
konnectorAccountId
)
const triggersServices = new TriggerService(client, account, konnector)
if (updateTrigger !== null) {
triggersServices.setTrigger(updateTrigger)
} else {
triggersServices.setTrigger(trigger)
}
const job = await triggersServices.launchTrigger()
if (!job) {
throw new Error(`Error during trigger launching`)
}
setlaunchedJob(job)
setUpdateDate(new Date(job.queued_at).toDateString())
} catch (error) {
setUpdating(false)
setError(error.message)
}
const handleSuccessForm = (_account: Account, _trigger: Trigger) => {
setAccount(_account)
setTrigger(_trigger)
setLaunch(true)
}
const initOauthAccount = async (oauthAccountId: string) => {
setError('')
setJobState('')
setLoading(true)
try {
const account = await AccountService.getAccount(client, oauthAccountId)
const triggersServices = new TriggerService(client, account, konnector)
const trigger: Trigger = await triggersServices.createTrigger()
if (!trigger) {
throw new Error(`Error during trigger creation`)
}
//Launch the creation trigger
const job = await triggersServices.launchTrigger()
if (!job) {
throw new Error(`Error during trigger launching`)
}
setUpdateTrigger(trigger)
setlaunchedJob(job)
setUpdateDate(new Date(job.queued_at).toDateString())
setAccountId(job.message.account)
setError('Connected')
setAccount(true)
} catch (error) {
setLoading(false)
setError(error.message)
const handleKonnectorLaunch = async () => {
if (trigger) {
await updateState(trigger)
}
setLaunch(false)
}
const getIcon = (jobState: string) => {
switch (jobState) {
case JobState.Errored:
return failurePicto
// case JobState.Running:
// return pendingPicto
// case JobState.Done:
// return successPicto
default:
return ''
}
}
const getKonnectorStateMarkup = (jobState: string) => {
const iconSrc = getIcon(jobState)
if (iconSrc === '') return ''
return <img className="state-icon" src={iconSrc}></img>
}
const jobStateCallBack = async (state: string) => {
setJobState(state)
if (state !== JobState.Running) {
setLoading(false)
setUpdating(false)
setJobState(state)
context.refreshFluidTypes()
}
const handleJobState = (_jobState: JobState) => {
setJobState(_jobState)
}
useEffect(() => {
let subscribed = true
async function getTriggerData() {
if (trigger || launchedJob) {
const jobService = new JobService(client)
let runningJob = null
if (trigger) {
let triggerState = null
triggerState = TriggerService.fetchStateFromTrigger(trigger)
const konnectorAcc = TriggerService.fetchKonnectorAccountFromTrigger(
trigger
async function getData() {
setLoading(true)
if (konnector) {
const _account = await AccountService.getAccountByType(
client,
konnector.slug
)
if (subscribed && _account) {
setAccount(_account)
const _trigger = await TriggerService.fetchTriggerFromAccount(
client,
_account
)
if (subscribed && konnectorAcc.konnector === konnector.slug) {
setAccountId(konnectorAcc.account)
setAccount(true)
if (subscribed && _trigger) {
setTrigger(_trigger)
await updateState(_trigger)
}
if (subscribed && !launchedJob) setJobState(triggerState.status)
if (triggerState.status === JobState.Running)
runningJob = jobService.fetchJob(triggerState.last_executed_job_id)
}
if (launchedJob) runningJob = launchedJob
if (runningJob) jobService.watch(runningJob, jobStateCallBack)
}
setLoading(false)
}
getTriggerData()
getData()
return () => {
subscribed = false
}
}, [trigger, launchedJob])
}, [])
return (
<>
<div className={`accordion ${setActive}`}>
<div>
<div
className={`accordion-header ${setActive}`}
onClick={toggleAccordion}
>
<div className="accordion-icon">
{!isKonnectorAcc ? (
<StyledIcon className="icon" icon={iconAddType} size={49} />
) : (
<StyledIcon className="icon" icon={iconType} size={49} />
)}
</div>
<div className="state-picto">
{getKonnectorStateMarkup(jobState)}
</div>
<div className="accordion-info">
<div className="accordion-title text-16-normal">
{!isKonnectorAcc
? t('KONNECTORCONFIG.LABEL_CONNECTTO_' + FluidType[fluid])
: t('FLUID.' + FluidType[fluid] + '.LABEL')}
{isLoading ? null : (
<div className={`accordion ${setActive}`}>
<div>
<div
className={`accordion-header ${setActive}`}
onClick={toggleAccordion}
>
<div className="accordion-icon">
{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 && !loginFailed
? t('FLUID.' + FluidType[fluid] + '.LABEL')
: t('KONNECTORCONFIG.LABEL_CONNECTTO_' + FluidType[fluid])}
</div>
</div>
<StyledIconButton icon={setActive ? chevronUp : chevronDown} />
</div>
<StyledIconButton icon={setActive ? chevronUp : chevronDown} />
</div>
<div
ref={content}
style={{ maxHeight: `${setHeight}` }}
className={`accordion-content ${setActive}`}
>
{!isKonnectorAcc ? (
!fluidConfig.konnectorConfig.oauth ? (
<KonnectorForm
fluidConfig={fluidConfig}
login={login}
setLogin={setLogin}
password={password}
setPassword={setPassword}
loading={loading}
error={error}
handleSubmit={handleSubmit}
<div
ref={content}
style={{ maxHeight: `${setHeight}` }}
className={`accordion-content ${setActive}`}
>
{!konnector ? (
<KonnectorNotFound
konnectorSlug={fluidConfig.konnectorConfig.slug}
/>
) : shouldLaunch && trigger ? (
<KonnectorLaunch
trigger={trigger}
handleKonnectorLaunch={handleKonnectorLaunch}
/>
) : account && !loginFailed ? (
<KonnectorResult
account={account}
handleJobState={handleJobState}
/>
) : (
<KonnectorOAuthForm
<KonnectorForm
fluidConfig={fluidConfig}
konnector={konnector}
siteLink={fluidConfig.siteLink}
onSuccess={initOauthAccount}
loading={loading}
account={account}
trigger={trigger}
handleSuccessForm={handleSuccessForm}
/>
)
) : loading ? (
<KonnectorLoading />
) : (
<KonnectorResult
date={
trigger
? TriggerService.fetchDateFromTrigger(trigger)
: updateDate
}
updating={updating}
errored={jobState === JobState.Errored}
updateKonnector={updateKonnector}
deleteAccount={deleteAccount}
/>
)}
)}
</div>
</div>
</div>
</div>
)}
</>
)
}
......
......@@ -11,6 +11,7 @@ import ChallengeIconOffNotif from 'assets/icons/tabbar/defi/off-notif.svg'
import ParameterIconOff from 'assets/icons/tabbar/parametre/off.svg'
import ConsoIconOn from 'assets/icons/tabbar/conso/on.svg'
import ParameterIconOn from 'assets/icons/tabbar/parametre/on.svg'
import logoGrandLyon from 'assets/icons/tabbar/grand-lyon.svg'
interface NavbarProps {
t: Function
......@@ -39,14 +40,10 @@ export const Navbar = ({ t }: NavbarProps) => {
className="c-nav-link"
activeClassName="is-active"
>
<Icon
className="c-nav-icon off"
icon={
challengeNotification
? ChallengeIconOffNotif
: ChallengeIconOff
}
/>
{challengeNotification && (
<div className="nb-challenge-notif">1</div>
)}
<Icon className="c-nav-icon off" icon={ChallengeIconOff} />
<Icon className="c-nav-icon on" icon={ChallengeIconOn} />
{t('Nav.challenges')}
</NavLink>
......@@ -65,6 +62,7 @@ export const Navbar = ({ t }: NavbarProps) => {
</li>
</ul>
</nav>
<Icon className="logo-grand-lyon" icon={logoGrandLyon} size={100} />
</aside>
)
}
......
......@@ -13,6 +13,7 @@ import StyledBlackSpinner from 'components/CommonKit/Spinner/StyledBlackSpinner'
interface OAuthFormProps {
konnector: Konnector
onSuccess: Function
loginFailed: boolean
client: Client
t: Function
}
......
......@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'
import get from 'lodash/get'
import { Client } from 'cozy-client'
const useInstanceSettings = (client: Client) => {
const userInstanceSettings = (client: Client) => {
const [settings, setSettings] = useState({})
const [fetchStatus, setFetchStatus] = useState('idle')
......@@ -12,9 +12,6 @@ const useInstanceSettings = (client: Client) => {
const response = await client
.getStackClient()
.fetchJSON('GET', '/settings/instance')
// const response = await client.query(
// client.all('io.cozy.settings').getById('instance')
// )
setSettings(get(response, 'data.attributes'), {})
setFetchStatus('loaded')
} catch (error) {
......@@ -30,4 +27,4 @@ const useInstanceSettings = (client: Client) => {
}
}
export default useInstanceSettings
export default userInstanceSettings
......@@ -48,10 +48,10 @@
{
"_id": "CHA00000003",
"type": 0,
"title": "Winter is leaving",
"description": "Et si dans les 7 prochains jours vous réussissiez à consommer moins que dans les 7 derniers",
"title": "Méga Coques en stock",
"description": "Et si dans les 4 prochaines semaines vous réussissiez à consommer moins que dans les 4 dernières",
"level": 3,
"duration": { "days": 7 },
"duration": { "days": 28 },
"fluidTypes": [0, 1, 2],
"relationships": {
"availableEcogestures": {
......@@ -77,9 +77,9 @@
{
"_id": "CHA00000004",
"type": 0,
"title": "Mega Coques en stock",
"title": "Winter is leaving",
"description": "Et si dans les 7 prochains jours vous réussissiez à consommer moins que dans les 7 derniers",
"level": 4,
"level": 901,
"duration": { "days": 7 },
"fluidTypes": [0, 1, 2],
"relationships": {
......@@ -106,9 +106,9 @@
{
"_id": "CHA00000005",
"type": 0,
"title": "Giga Coques en stock",
"title": "ga Winter is leaving",
"description": "Et si dans les 7 prochains jours vous réussissiez à consommer moins que dans les 7 derniers",
"level": 5,
"level": 902,
"duration": { "days": 7 },
"fluidTypes": [0, 1, 2],
"relationships": {
......
export const ACCOUNTS_DOCTYPE = 'io.cozy.accounts'
type AuthLoginData = {
login: string
credentials_encrypted?: string
password?: string
}
type OAuthData = {
access_token: string
refresh_token: string
scope: string | null
}
export type Account = {
_id: string
account_type: string
auth: {
credentials_encrypted: string
login: string
}
auth: AuthLoginData | OAuthData
identifier: string
state?: string | null
}
......
......@@ -3,7 +3,7 @@ export const TRIGGERS_DOCTYPE = 'io.cozy.triggers'
export type Trigger = {
_id: string
type: string
workker: string
worker: string
arguments: string
message: {
account: string
......@@ -11,12 +11,24 @@ 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 &&
'_id' in trigger &&
'type' in trigger &&
'workker' in trigger &&
'worker' in trigger &&
'arguments' in trigger &&
'message' in trigger
)
......
......@@ -121,7 +121,14 @@
"BTN_UPDATE": "Mettre à jour",
"BTN_DELETE": "Supprimer",
"LOADING_DATA": "Vos premières données seront disponibles dans quelques minutes et les prochaines données seront chargées automatiquement.",
"PLZ_WAIT": "Veuillez patienter..."
"PLZ_WAIT": "Veuillez patienter...",
"NOT_INSTALLED": "Le connecteur n'est pas installé. Veuillez l'installer en cliquant sur le bouton ci-dessous.",
"ERROR_NO_LOGIN_PASSWORD": "Identifiant et mot de passe requis",
"ERROR_ACCOUNT_CREATION": "Une erreur est survenue, veuillez essayer de nouveau.",
"ERROR_LOGIN_FAILED": "Identifiants invalides",
"SUCCESS": "Félicitations, vos premières données sont disponibles et les prochaines seront chargées automatiquement.",
"ERROR_DATA": "Une erreur est survenue pendant le rapatriement des données.",
"OK": "Ok"
},
"INDICATOR": {
"DISPLAY_OTHER_FLUID": "Voir",
......@@ -140,6 +147,7 @@
"ONGOING_CHALLENGE": "En cours",
"ENDINGDATE_UNDEFINED": "Date non connue",
"LOCKED": "Vous devez finir le défi précédent pour accéder à celui-ci",
"FULLY_LOCKED": "Ce défi sera disponible dans une prochaine mise à jour",
"START": "Allons-y !",
"NOT_NOW": "Pas maintenant !",
"STOP": "Arrêter le défi",
......@@ -180,7 +188,7 @@
"oauth": {
"connect": {
"enedis": {
"info" : "En cliquant sur ce bouton, vous allez accéder à votre compte personnel Enedis où vous pourrez donner votre accord pour qu’Enedis nous transmette vos données.",
"info" : "En cliquant sur ce bouton, vous accéderez à votre compte Enedis. Vous pourrez donner votre accord pour récupérer vos données de consommation électriques dans votre cloud personnel",
"label1": "J'accède à mon",
"label2": "espace client Enedis"
}
......
......@@ -98,15 +98,26 @@ export class AccountService {
}
}
static updateAccount = async (client: Client, account: Account) => {
try {
const updatedAccount: Account = await accountsMutations(
client
).updateAccount(account)
return updatedAccount
} catch (error) {
throw error
}
}
static getAccountByType = async (client: Client, type: string) => {
try {
const query = client
.find('io.cozy.accounts')
// eslint-disable-next-line @typescript-eslint/camelcase
.where({ account_type: type })
// .sortBy([{ 'cozyMetadata.updatedAt': 'desc' }])
.limitBy(1)
return await client.query(query)
const result = await client.query(query)
return result.data[0] ? result.data[0] : null
} catch (error) {
throw error
}
......
......@@ -202,16 +202,14 @@ export default class ChallengeManager implements IChallengeManager {
return 0
}
public async updateUserLevel(level?: number) {
public async updateUserLevel(level: number) {
await this._client
.query(this._client.find(USERPROFILE_DOCTYPE).limitBy(1))
.then(async ({ data }) => {
const doc = data[0]
let actualLevel = 0
if (level) {
let actualLevel = doc.level
if (level > actualLevel) {
actualLevel = level
} else {
actualLevel = doc.level
}
await this._client.save({
...doc,
......@@ -445,6 +443,16 @@ export default class ChallengeManager implements IChallengeManager {
return challengeTypes
}
public async getUserLevel() {
let userLevel
await this._client
.query(this._client.find(USERPROFILE_DOCTYPE).limitBy(1))
.then(async ({ data }) => {
userLevel = data[0].level
})
return userLevel
}
public async startChallenge(
challenge: ChallengeType,
fluidTypes: FluidType[],
......
......@@ -48,11 +48,15 @@ export class ConnectionService {
if (!trigger) {
throw new Error(`Error during trigger creation`)
}
//Launch the creation trigger
const job = await triggersServices.launchTrigger()
if (!job) {
throw new Error(`Error during trigger launching`)
return {
account: account,
trigger: trigger,
}
return job
//Launch the creation trigger
// const job = await triggersServices.launchTrigger()
// if (!job) {
// throw new Error(`Error during trigger launching`)
// }
// return job
}
}
......@@ -16,6 +16,7 @@ export default class KonnectorStatusService {
return 'konnector status'
}
// TODO - move to triggerservices
async getTriggerbyKonnector(konnector: Konnector) {
const query = this._client
.find('io.cozy.triggers')
......@@ -120,13 +121,13 @@ export default class KonnectorStatusService {
),
])
const data: FluidType[] = []
if (elecData && elecData.data && elecData.data[0]) {
if (elecData) {
data.push(fluidConfig[FluidType.ELECTRICITY].fluidTypeId)
}
if (gasData && gasData.data && gasData.data[0]) {
if (gasData) {
data.push(fluidConfig[FluidType.GAS].fluidTypeId)
}
if (waterData && waterData.data && waterData.data[0]) {
if (waterData) {
data.push(fluidConfig[FluidType.WATER].fluidTypeId)
}
return data
......
......@@ -24,7 +24,7 @@ export class TriggerService {
this._trigger = {
_id: '',
type: '',
workker: '',
worker: '',
arguments: '',
message: {
account: '',
......@@ -65,14 +65,10 @@ export class TriggerService {
'TriggersServices : createTrigger - _triggerAttributes or _client not found'
)
}
try {
this._trigger = await triggersMutations(this._client).createTrigger(
this._triggerAttributes
)
return this._trigger
} catch (error) {
throw error
}
this._trigger = await triggersMutations(this._client).createTrigger(
this._triggerAttributes
)
return this._trigger
}
setTrigger = (trigger: Trigger) => {
......@@ -110,4 +106,25 @@ export class TriggerService {
trigger.current_state.last_execution
).toLocaleString(DateTime.DATETIME_MED)
}
static async fetchTriggerFromAccount(client: Client, account: Account) {
if (account == null) return null
const query = client
.find('io.cozy.triggers')
.where({ 'message.account': account._id })
.sortBy([{ 'cozyMetadata.updatedAt': 'desc' }])
.limitBy(1)
const result = await client.query(query)
return result.data[0] ? result.data[0] : null
}
static async fetchTriggerState(client: Client, trigger: Trigger) {
if (trigger == null) return null
const triggerState = await client
.getStackClient()
.fetchJSON('GET', `/jobs/triggers/${trigger._id}`)
return triggerState.data.attributes.current_state
? triggerState.data.attributes.current_state
: null
}
}
......@@ -238,8 +238,15 @@
position: absolute;
top: 15px;
@media #{$large-phone} {
top: 65px;
}
top: 65px;
}
&.--ecolyo-royal {
@extend .cp-content;
top: -38px;
@media #{$large-phone} {
top: 12px;
}
}
.cm-win-badge {
grid-column: 1;
grid-row: 1;
......@@ -289,8 +296,11 @@
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 1rem;
margin-top: 3rem;
width: 100%;
@media #{$large-phone} {
margin-top: 1rem;
}
.day-solo {
display: flex;
flex-direction: column;
......@@ -312,6 +322,9 @@
.futur {
background-color: $grey-dark;
}
.none {
opacity: 0;
}
.date-label {
width: 0.625rem;
height: 0.625rem;
......@@ -343,6 +356,7 @@
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: 100%;
.pile-section {
display: grid;
......@@ -469,7 +483,10 @@
max-width: 53rem;
&.--ongoing {
@extend .cp-valid;
width: 60%;
width: 25%;
@media #{$large-phone} {
width: 60%;
}
}
.cp-left-button {
margin-right: 0.25rem;
......
......@@ -54,7 +54,7 @@
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
justify-content: space-around;
&.ec-content-unlocked {
padding: 0.4rem 0;
}
......@@ -64,11 +64,6 @@
.ec-content-icon{
min-height: 50px;
}
.ec-content-challenge-text {
display: flex;
flex: 1;
align-items: center;
}
.ec-content-short-name {
display: flex;
flex: 1;
......
......@@ -23,6 +23,7 @@
.form-group {
display: flex;
flex-direction: column;
margin: 1.5rem 0 0 0;
.form-trailing-icon {
float: right;
position: relative;
......@@ -39,6 +40,10 @@
.form-message {
color: $red-error;
min-height: 1.25rem;
margin-top: 0.125rem;
}
.form-button {
margin-top: 0.125rem;
}
::placeholder {
color: $google-text-1;
......
......@@ -44,6 +44,7 @@
}
.state-picto {
position: absolute;
display: flex;
}
}
.accordion-update-result {
......@@ -111,39 +112,59 @@
}
}
// KonnectorNotFound
.knotfound {
margin: 0 1.5rem;
@media #{$large-phone} {
margin: 0;
}
.knotfound-text {
color: $text-bright;
padding-top: 1rem;
}
.knotfound-button {
margin-bottom: 1rem;
}
}
// KonnectorOAuthForm
.koauthform{
.koauthform {
margin: 0 1.5rem;
@media #{$large-phone} {
margin: 0;
}
.koauthform-text{
.koauthform-text {
color: $text-bright;
padding-top: 1rem;
}
.koauthform-button{
.koauthform-button {
margin-bottom: 1rem;
}
}
// KonnectorLoading
.kload-content {
.klaunch-content {
margin: 0.5rem 1.5rem;
@media #{$large-phone} {
margin: 0.5rem 0;
}
.kload-content-text {
.klaunch-content-text {
color: $text-bright;
margin: 1rem 0;
}
.kload-content-text-center {
.klaunch-content-text-center {
text-align: center;
}
.klaunch-info-txt {
margin-top: 1.5rem;
}
}
.state-icon {
height: 22px;
width: 22px;
margin-left: 32px;
margin-bottom: 40px;
position: absolute;
bottom: 8px;
left: 30px;
}
......@@ -17,6 +17,14 @@
@media #{$tablet} {
background-color: $primary-color;
}
.logo-grand-lyon {
position: absolute;
top: 50%;
left: 100px;
@media #{$tablet} {
display: none;
}
}
}
.c-nav-link {
padding: 0 1rem;
......@@ -76,3 +84,24 @@
box-shadow: unset;
}
}
.nb-challenge-notif {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
left: 42px;
bottom: 22px;
width: 1.25rem;
height: 1.25rem;
color: $dark-light;
border-radius: 50%;
border: 1px solid $dark-light;
z-index: 1;
background: $blue-radial-gradient;
font-size: 12px;
@media #{$tablet} {
left: 25px;
bottom: unset;
}
}