diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx index 38add5a..fcde40e 100644 --- a/src/components/Menu/Menu.tsx +++ b/src/components/Menu/Menu.tsx @@ -46,6 +46,7 @@ export const Menu = () => { navigate('/account/zones')}>Hantera zoner navigate('/account/zones/create')}>Lägg till zoner navigate('/account/events/import')}>Importera data + navigate('/account/about')}>Om Sam logOutAndRedirect()}>Logga ut diff --git a/src/components/SideBar/SideBar.tsx b/src/components/SideBar/SideBar.tsx index 3a637e8..5eededc 100644 --- a/src/components/SideBar/SideBar.tsx +++ b/src/components/SideBar/SideBar.tsx @@ -46,6 +46,15 @@ export const SideBar = () => { > Importera data + ); }; diff --git a/src/modules/Account/About/About.tsx b/src/modules/Account/About/About.tsx new file mode 100644 index 0000000..efa1ebf --- /dev/null +++ b/src/modules/Account/About/About.tsx @@ -0,0 +1,61 @@ +import { SideBar } from 'components/SideBar'; +import { Link } from 'components/Link'; +import * as Styled from './styled'; + +export const About = () => ( + + + + Om Sam +

+ Sam samlar in transportdata för att kunna dela datan mellan olika aktörer i transportkedjan. + Genom tillgänglig data kan beställaren fà bättre förstäelse för hur transporterna + inom olika omräden går och kan använda datan för att bli smartare beställare. + Leverantörer och transportörer kan använda datan för att hitta samarbeten och samlastning. + Mälet med Sam är smartare logistik kring transporter och minskade + körningar för klimatets skull. +

+

Så här fungerar Sam

+

+ Tjänsten Sam bestär av en mobilapp som används av förare, + och den här webbsidan där alla sparade leveranser samlas. + Just nu är tjänsten sà pass utvecklad att vi kan beskriva + transporter som gär till och fràn olika verksamheter i staden, + via geofencing*. Det betyder att endast leveranser till geofencade adresser + registreras - andra stopp pá vägen kommer inte registreras pá webbsidan +

+
+

+ + *Geofence är en internationell fackterm. Den kan översättas med "geostaket" + och är ett geografiskt avgränsat eller definierat omräde som bestämts och som + "inhägnats" med en programvara. + +

+

Leverera transportdata till Sam

+

+ Det finns två sätt att leverera data till Sam. +

+
    +
  1. + Använd appen Sam +
    + Föraren laddar ner appen till sin telefon. Föraren startar spärningen + i appen vid start av en körning. + Varje gäng transporten befinner sig inom ett geofencat omräde blir + det en datapunkt som sparas och blir synlig pà webbsidan. +
  2. +
  3. + Leverera en rapport +
    + Istället för att använda appen Sam kan leverantör eller transportör hämta + motsvarande data frản sitt logistiksystem/TMS (Transport Management System) + och skicka rapport till kontaktperson enligt + överenskommet intervall. + {' '} + +
  4. +
+
+
+); diff --git a/src/modules/Account/About/index.ts b/src/modules/Account/About/index.ts new file mode 100644 index 0000000..bdf079e --- /dev/null +++ b/src/modules/Account/About/index.ts @@ -0,0 +1,3 @@ +import { About } from './About'; + +export default About; diff --git a/src/modules/Account/About/styled.ts b/src/modules/Account/About/styled.ts new file mode 100644 index 0000000..d6fbdc2 --- /dev/null +++ b/src/modules/Account/About/styled.ts @@ -0,0 +1,22 @@ +import styled from 'styled-components'; + +export const ContentContainer = styled.div` + padding: 36px 32px; + padding-bottom: 64px; +`; + +export const InfoContainer = styled.div` + width: 600px; + margin: 24px auto 32px; + @media (max-width: 768px) { + width: 450px; + } +`; + +export const Header = styled.h1` + font-size: var(--font-size-heading-lg); + font-weight: var(--font-weight-800); + line-height: var(--line-height-xxxl); + margin-bottom: var(--spacing-md); + font-family: var(--font-family); +`; diff --git a/src/modules/Account/AccountRouter.tsx b/src/modules/Account/AccountRouter.tsx index 67e8566..f3070d1 100644 --- a/src/modules/Account/AccountRouter.tsx +++ b/src/modules/Account/AccountRouter.tsx @@ -7,6 +7,7 @@ const ZonesSettings = lazy(() => import('./ZonesSettings')); const CreateZones = lazy(() => import('./CreateZones')); const EditZone = lazy(() => import('./EditZone')); const ImportEvents = lazy(() => import('./ImportEvents')); +const About = lazy(() => import('./About')); export const AccountRouter = () => ( @@ -15,6 +16,7 @@ export const AccountRouter = () => ( } /> } /> } /> + } /> } /> diff --git a/src/modules/Account/ImportEvents/components/ImportEventsForm/ImportEventsForm.tsx b/src/modules/Account/ImportEvents/components/ImportEventsForm/ImportEventsForm.tsx index 950da8b..3582efa 100644 --- a/src/modules/Account/ImportEvents/components/ImportEventsForm/ImportEventsForm.tsx +++ b/src/modules/Account/ImportEvents/components/ImportEventsForm/ImportEventsForm.tsx @@ -4,6 +4,9 @@ import { Input, Button, Link, } from 'components'; +import { + Check, Download, Error, InsertDriveFileOutlined, +} from '@mui/icons-material'; import * as Styled from './styled'; import { useImportEventsForm } from './hooks'; @@ -18,8 +21,13 @@ export const ImportEventsForm = () => { apiErrorText, isLoading, importFile, + importErrorText, + setImportFile, + uploadStatus, } = useImportEventsForm(); + const errors = importErrorText ? importErrorText.split('|') : []; + const { getRootProps, getInputProps, @@ -47,26 +55,68 @@ export const ImportEventsForm = () => { :

Dra zoner eller klicka för att ladda upp

} - - - - + {importFile && ( + + + +

{importFile?.name}

+
+ + {uploadStatus === 'success' && } + {uploadStatus === 'error' && } + {uploadStatus === 'idle' && setImportFile(null)}>Ta bort} + +
+ )} + {errors && errors.length > 0 && ( + <> + + + {errors.length} + {' '} + fel + + + {errors.map((error) => ( + {error} + ))} + + )} + {importFile && ( + + + + )} ) : ( -
- setPassword(e.target.value)} - placeholder="Lösenord" - /> + + + Transportdata kan delas i Sam genom import av rapporter. Rapporten skickar du + enligt överenskommet intervall till din kontaktperson. + Kontaktpersonen importerar in rapporten och datan blir sen synlig i Sam. + + + + + + {' '} +

För kontaktperson

+ + setPassword(e.target.value)} + placeholder="Lösenord" + /> + + {apiErrorText && {apiErrorText}}
)} - {apiErrorText && {apiErrorText}} ); }; diff --git a/src/modules/Account/ImportEvents/components/ImportEventsForm/hooks/useImportEventsForm/useImportEventsForm.ts b/src/modules/Account/ImportEvents/components/ImportEventsForm/hooks/useImportEventsForm/useImportEventsForm.ts index 2170dee..da1e204 100644 --- a/src/modules/Account/ImportEvents/components/ImportEventsForm/hooks/useImportEventsForm/useImportEventsForm.ts +++ b/src/modules/Account/ImportEvents/components/ImportEventsForm/hooks/useImportEventsForm/useImportEventsForm.ts @@ -2,20 +2,22 @@ import { AxiosError } from 'axios'; import { useState, useCallback } from 'react'; import { useEventApi } from 'hooks/useEventApi'; -import { useNavigate } from 'react-router-dom'; export const useImportEventsForm = () => { const [isLoading, setIsLoading] = useState(false); const [importFile, setImportFile] = useState(null); const [password, setPassword] = useState(''); const [apiErrorText, setApiErrorText] = useState(''); + const [importErrorText, setImportErrorText] = useState(''); const [passwordIsCorrect, setPasswordIsCorrect] = useState(false); - const navigate = useNavigate(); + const [uploadStatus, setUploadStatus] = useState<'idle' | 'success' | 'error'>('idle'); const { importEventsPassword, importEventsByExcel } = useEventApi(); const onDrop = useCallback((acceptedFiles: any) => { const file = acceptedFiles[0]; + setUploadStatus('idle'); + setImportErrorText(''); setImportFile(file); }, []); @@ -24,10 +26,12 @@ export const useImportEventsForm = () => { try { await importEventsByExcel(importFile as File, password); setApiErrorText(''); - navigate('/events/grouped'); + setImportErrorText(''); + setUploadStatus('success'); } catch (error: AxiosError | any) { if (error) { - setApiErrorText(error.response.data.message); + setUploadStatus('error'); + setImportErrorText(error.response.data.message); } } setIsLoading(false); @@ -63,5 +67,8 @@ export const useImportEventsForm = () => { passwordIsCorrect, password, importFile, + importErrorText, + setImportFile, + uploadStatus, }; }; diff --git a/src/modules/Account/ImportEvents/components/ImportEventsForm/styled.ts b/src/modules/Account/ImportEvents/components/ImportEventsForm/styled.ts index 8cb929c..87ca98a 100644 --- a/src/modules/Account/ImportEvents/components/ImportEventsForm/styled.ts +++ b/src/modules/Account/ImportEvents/components/ImportEventsForm/styled.ts @@ -61,8 +61,7 @@ export const InputContainer = styled.div` `; export const ButtonContainer = styled.div` - display: flex; - justify-content: flex-end; + width: 55%; margin-top: var(--spacing-xs); gap: var(--spacing-xs); `; @@ -102,3 +101,49 @@ export const ListItem = styled.li` border-bottom: none; } `; + +export const Paragraph = styled.p` + line-height: var(--line-height-md); + `; + +export const DownloadContainer = styled.div` + display: flex; + align-items: center; + gap: var(--spacing-xxs); + margin-top: var(--spacing-xs); + margin-bottom: var(--spacing-xl); + a { + color: var(--color-black); + text-decoration: none; + font-weight: bold; + font-size: var(--font-size-body-md); + } +`; + +export const File = styled.div` + display: flex; + align-items: center; + gap: var(--spacing-xxs); + margin-top: var(--spacing-xs); +`; + +export const FileContainer = styled.div` + display: flex; + justify-content: space-between; +`; +export const TextButton = styled.button` + background: none; + border: none; + color: var(--color-primary); + text-decoration: underline; + cursor: pointer; + font-size: var(--font-size-body-md); + &:hover { + text-decoration: none; + } +`; + +export const FileActions = styled.div` + display: flex; + align-items: end; +`; diff --git a/src/modules/Account/ImportEvents/styled.ts b/src/modules/Account/ImportEvents/styled.ts index f8f79b8..02a601a 100644 --- a/src/modules/Account/ImportEvents/styled.ts +++ b/src/modules/Account/ImportEvents/styled.ts @@ -14,9 +14,9 @@ export const FormContainer = styled.div` `; export const Header = styled.h1` - font-size: var(--font-size-heading-xs); + font-size: var(--font-size-heading-lg); font-weight: var(--font-weight-800); line-height: var(--line-height-xxxl); - margin-bottom: var(--spacing-xxs); + margin-bottom: var(--spacing-md); font-family: var(--font-family); `; diff --git a/src/modules/Auth/CreateAccount/components/CreateAccountForm/CreateAccountForm.tsx b/src/modules/Auth/CreateAccount/components/CreateAccountForm/CreateAccountForm.tsx index 1ef88da..75efb42 100644 --- a/src/modules/Auth/CreateAccount/components/CreateAccountForm/CreateAccountForm.tsx +++ b/src/modules/Auth/CreateAccount/components/CreateAccountForm/CreateAccountForm.tsx @@ -1,10 +1,10 @@ -import { Input, Checkbox, Button } from 'components'; +import { Input, Button } from 'components'; import * as Styled from './styled'; import { useCreateAccountForm } from '../../hooks'; export const CreateAccountForm = () => { const { - setFieldValue, formFields, errors, setConsentValue, submitForm, isLoading, + setFieldValue, formFields, errors, submitForm, isLoading, } = useCreateAccountForm(); return ( @@ -82,21 +82,6 @@ export const CreateAccountForm = () => { error={errors.pinCode} info="För att logga in i appen används en pinkod. Bestäm vilken pinkod din verksamhet ska använda. Koden ska bestå av 6 siffror med minst 3 unika siffror och där högst 2 siffror i följd är lika." /> - - - - - Genom att skapa konto säger du ja till - {' '} - xxx - - - diff --git a/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/createAccount.validation.ts b/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/createAccount.validation.ts index e4d73ec..691997c 100644 --- a/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/createAccount.validation.ts +++ b/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/createAccount.validation.ts @@ -19,17 +19,8 @@ export const CreateAccountValidation = z.object({ .string() .regex(passwordRegex, { message: 'Fel format för lösenord - välj ett lösenord som följer reglerna.' }), pinCode: z.string().regex(pinCodeRegex, { message: 'Fel format för pinkod - välj en pinkod som följer reglerna.' }), - contactPerson: z.string().min(1, { message: 'Ange ett kontakt-namn' }), - mobileNumber: z.string().min(1, { message: 'Ange ett mobilnummer för kontakt' }), - consent: z - .boolean() - .optional() - .transform((value) => { - if (value !== true) { - throw new Error('Du måste godkänna villkoren för att skapa ett konto'); - } - return true; - }), + contactPerson: z.string(), + mobileNumber: z.string(), }); export type CreateAccountType = z.infer; diff --git a/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/useCreateAccountForm.ts b/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/useCreateAccountForm.ts index a7106e0..44585a1 100644 --- a/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/useCreateAccountForm.ts +++ b/src/modules/Auth/CreateAccount/hooks/useCreateAccountForm/useCreateAccountForm.ts @@ -31,7 +31,6 @@ export const useCreateAccountForm = () => { pinCode: '', contactPerson: '', mobileNumber: '', - consent: false, }); const setFieldValue = (name: string) => ({ @@ -43,13 +42,6 @@ export const useCreateAccountForm = () => { }); }; - const setConsentValue = (checked: boolean) => { - setFormFields({ - ...formFields, - consent: checked, - }); - }; - const submitForm = (e: React.SyntheticEvent) => { e.preventDefault(); setIsLoading(true); @@ -98,6 +90,5 @@ export const useCreateAccountForm = () => { formFields, errors, isLoading, - setConsentValue, }; };