From 65ee4bdc621559f339a7e45cc9e7a487a13ee9f8 Mon Sep 17 00:00:00 2001 From: dev-rminds Date: Tue, 29 Apr 2025 10:15:48 +0300 Subject: [PATCH 01/10] move prevalidations to organization level --- .../modals/ModalCreatePrevalidation.tsx | 5 +- .../ModalPrevalidationsUpload.tsx} | 655 ++++++++++-------- .../pages/csv_validations/CsvValidations.tsx | 108 --- .../OrganizationsFundsShowStatisticsCard.tsx | 2 +- .../Prevalidations.tsx} | 314 ++++++--- react/src/dashboard/i18n/i18n-nl.js | 6 +- .../dashboard/props/models/Prevalidation.tsx | 2 + react/src/dashboard/router/routes.tsx | 8 +- react/src/dashboard/services/FundService.ts | 4 - .../services/PrevalidationService.ts | 38 +- 10 files changed, 624 insertions(+), 518 deletions(-) rename react/src/dashboard/components/{pages/csv_validations/elements/CSVUpload.tsx => modals/ModalPrevalidationsUpload.tsx} (57%) delete mode 100644 react/src/dashboard/components/pages/csv_validations/CsvValidations.tsx rename react/src/dashboard/components/pages/{csv_validations/elements/PrevalidatedTable.tsx => prevalidations/Prevalidations.tsx} (61%) diff --git a/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx b/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx index fc0910ad1..61b78fe80 100644 --- a/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx +++ b/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx @@ -100,7 +100,8 @@ export default function ModalCreatePrevalidation({ } prevalidationService - .submit( + .store( + fund.organization_id, { ...values, ...dateValues, @@ -137,7 +138,7 @@ export default function ModalCreatePrevalidation({ ); const removeExtraRecord = useCallback( - (recordKey) => { + (recordKey: string) => { if (prevalidationRecords?.includes(recordKey)) { prevalidationRecords.splice(prevalidationRecords.indexOf(recordKey), 1); delete form.values[recordKey]; diff --git a/react/src/dashboard/components/pages/csv_validations/elements/CSVUpload.tsx b/react/src/dashboard/components/modals/ModalPrevalidationsUpload.tsx similarity index 57% rename from react/src/dashboard/components/pages/csv_validations/elements/CSVUpload.tsx rename to react/src/dashboard/components/modals/ModalPrevalidationsUpload.tsx index 6f94f600e..e4d0989c8 100644 --- a/react/src/dashboard/components/pages/csv_validations/elements/CSVUpload.tsx +++ b/react/src/dashboard/components/modals/ModalPrevalidationsUpload.tsx @@ -1,23 +1,36 @@ -import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import Fund from '../../../../props/models/Fund'; -import { useFundService } from '../../../../services/FundService'; -import useOpenModal from '../../../../hooks/useOpenModal'; -import ModalCreatePrevalidation from '../../../modals/ModalCreatePrevalidation'; -import { useFileService } from '../../../../services/FileService'; -import CSVProgressBar from '../../../elements/csv-progress-bar/CSVProgressBar'; -import RecordType from '../../../../props/models/RecordType'; +import React, { Fragment, useCallback, useMemo, useRef, useState } from 'react'; +import { ModalState } from '../../modules/modals/context/ModalContext'; +import Fund from '../../props/models/Fund'; +import { useFileService } from '../../services/FileService'; +import { fileSize } from '../../helpers/string'; import Papa from 'papaparse'; -import { isEmpty, uniqueId } from 'lodash'; -import usePushSuccess from '../../../../hooks/usePushSuccess'; -import { usePrevalidationService } from '../../../../services/PrevalidationService'; -import ModalDuplicatesPicker from '../../../modals/ModalDuplicatesPicker'; -import useTranslate from '../../../../hooks/useTranslate'; -import usePushDanger from '../../../../hooks/usePushDanger'; -import { ResponseError } from '../../../../props/ApiResponses'; -import { fileSize } from '../../../../helpers/string'; +import { uniqueId, isEmpty } from 'lodash'; +import usePushSuccess from '../../hooks/usePushSuccess'; +import usePushDanger from '../../hooks/usePushDanger'; +import { ResponseError } from '../../props/ApiResponses'; +import ModalDuplicatesPicker from './ModalDuplicatesPicker'; +import useOpenModal from '../../hooks/useOpenModal'; +import CSVProgressBar from '../elements/csv-progress-bar/CSVProgressBar'; +import useTranslate from '../../hooks/useTranslate'; import classNames from 'classnames'; -import { fileToText } from '../../../../helpers/utils'; -import usePushApiError from '../../../../hooks/usePushApiError'; +import usePushInfo from '../../hooks/usePushInfo'; +import { fileToText } from '../../helpers/utils'; +import { useFundService } from '../../services/FundService'; +import RecordType from '../../props/models/RecordType'; +import { usePrevalidationService } from '../../services/PrevalidationService'; +import usePushApiError from '../../hooks/usePushApiError'; + +type CSVErrorProp = { + emptyHeader?: string | string[]; + emptyBody?: string | string[]; + invalidRecordTypes?: string | string[]; + missingRecordTypes?: string | string[]; + invalidRows?: string | string[]; +}; + +type CSVWarningProp = { + optionalRecordTypes?: string | string[]; +}; type RowDataPropData = { [key: string]: string }; @@ -28,17 +41,22 @@ type RowDataProp = { data: RowDataPropData; }; -export default function CSVUpload({ +export default function ModalPrevalidationsUpload({ fund, - onUpdated = null, - recordTypes = [], + modal, + className, + recordTypes, + onCompleted, }: { fund: Fund; - onUpdated?: () => void; - recordTypes: Array; + modal: ModalState; + className?: string; + recordTypes?: Array; + onCompleted: () => void; }) { - const openModal = useOpenModal(); + const pushInfo = usePushInfo(); const translate = useTranslate(); + const openModal = useOpenModal(); const pushDanger = usePushDanger(); const pushSuccess = usePushSuccess(); const pushApiError = usePushApiError(); @@ -47,16 +65,27 @@ export default function CSVUpload({ const fundService = useFundService(); const prevalidationService = usePrevalidationService(); + const [data, setData] = useState>(null); + const [loading, setLoading] = useState(false); + const [changed, setChanged] = useState(false); + const [csvFile, setCsvFile] = useState(null); + const [hideModal, setHideModal] = useState(false); const [isDragOver, setIsDragOver] = useState(false); - const [dataChunkSize] = useState(100); + const [dataChunkSize] = useState(50); + const [progressBar, setProgressBar] = useState(null); + const [csvComparing, setCsvComparing] = useState(false); + + const [csvErrors, setCsvErrors] = useState({}); + const [csvWarnings, setCsvWarnings] = useState({}); + const [csvIsValid, setCsvIsValid] = useState(false); + const [csvProgress, setCsvProgress] = useState(0); + const [progressStatus, setProgressStatus] = useState(''); const [acceptedFiles] = useState(['.csv']); - const abort = useRef(false); + const abortRef = useRef(false); const inputRef = useRef(null); - const [data, setData] = useState(null); - const criteriaRecordTypeKeys = useMemo(() => { return recordTypes?.filter((recordType) => recordType.criteria)?.map((recordType) => recordType.key); }, [recordTypes]); @@ -71,62 +100,42 @@ export default function CSVUpload({ })[0]?.value; }, [fund.criteria, fundRecordKey]); - const [csvFile, setCsvFile] = useState(null); - const [csvErrors, setCsvErrors] = useState(null); - const [csvIsValid, setCsvIsValid] = useState(false); - const [csvWarnings, setCsvWarnings] = useState(null); - const [csvProgress, setCsvProgress] = useState(null); - const [csvProgressBar, setCsvProgressBar] = useState(null); - const [csvComparing, setCsvComparing] = useState(false); + const closeModal = useCallback(() => { + if (loading) { + return pushInfo('Bezig met uploaden.'); + } + + if (changed) { + onCompleted(); + } - const reset = useCallback(() => { - abort.current = true; + modal.close(); + }, [changed, loading, modal, onCompleted, pushInfo]); + + const downloadExampleCsv = useCallback(() => { + fileService.downloadFile((fund.key || 'fund') + '_sample.csv', fundService.sampleCSV(fund)); + }, [fileService, fund, fundService]); + + const reset = useCallback((abortRefValue = true) => { + abortRef.current = abortRefValue; setCsvFile(null); - setCsvErrors(null); + setCsvErrors({}); setCsvIsValid(false); - setCsvWarnings(null); setCsvProgress(null); - setCsvProgressBar(null); - setCsvComparing(false); - }, []); - - const onDragEvent = useCallback((e: React.DragEvent, isDragOver: boolean) => { - e?.preventDefault(); - e?.stopPropagation(); - - setIsDragOver(isDragOver); }, []); const filterSelectedFiles = useCallback( (files: FileList) => { return [...files].filter((file) => { - return acceptedFiles.filter((type) => file.name.endsWith(type)); + return acceptedFiles.includes('.' + file.name.split('.')[file.name.split('.').length - 1]); }); }, [acceptedFiles], ); - const updateProgressBarValue = useCallback((progress: number) => { - setCsvProgressBar(progress); - setProgressStatus(progress < 100 ? 'Aan het uploaden...' : 'Klaar!'); - }, []); - - const chunkList = useCallback((arr: Array, len: number) => { - const chunks = []; - const n = arr.length; - - let i = 0; - - while (i < n) { - chunks.push(arr.slice(i, (i += len))); - } - - return chunks; - }, []); - - const validateFile = useCallback( - function (data: Array<{ [key: string]: string }>): Array { + const validateCsvData = useCallback( + function (data: Array): Array { return data .map((row, row_key) => { const rowRecordKeys = Object.keys(row); @@ -136,9 +145,10 @@ export default function CSVUpload({ }); if (missingRecordTypes.length > 0) { - return `Lijn ${ - row_key + 1 - }: heet ontbrekende verplichte persoonsgegevens: "${missingRecordTypes.join('", "')}"`; + return [ + `Lijn ${row_key + 1}:`, + `heet ontbrekende verplichte persoonsgegevens: "${missingRecordTypes.join('", "')}"`, + ].join(' '); } return null; @@ -148,6 +158,58 @@ export default function CSVUpload({ [fund?.csv_required_keys], ); + const showInvalidRows = useCallback( + (errors = {}, rows = [], rowIndex = 0) => { + const items = Object.keys(errors) + .map(function (key) { + const keyData = key.split('.'); + const keyDataId = keyData[1]; + const fieldKey = keyData[2]; + const index = parseInt(keyDataId, 10) + 1 + rowIndex; + + return [index, errors[key], fieldKey]; + }) + .sort((a, b) => a[0] - b[0]); + + const uniqueRows = items.reduce((arr, item) => { + return arr.includes(item[0]) ? arr : [...arr, item[0]]; + }, []); + + const message = [ + `${uniqueRows.length} van ${rows.length}`, + `rij(en) uit het bulkbestand zijn niet geimporteerd,`, + `bekijk het bestand bij welke rij(en) het mis gaat.`, + ].join(' '); + + pushDanger('Waarschuwing', message); + + setHideModal(true); + + openModal((modal) => ( + ({ + value: `Rij: ${item[0]}: ${item[2]} - ${item[1]}`, + _uid: uniqueId('rand_'), + label: item?.[fund.csv_primary_key], + }))} + onConfirm={() => { + reset(); + }} + onCancel={() => { + reset(); + }} + /> + )); + }, + [fund.csv_primary_key, openModal, pushDanger, reset], + ); + const parseCsvFile = useCallback( async (file: File): Promise>> => { return await new Promise(function (complete) { @@ -163,19 +225,15 @@ export default function CSVUpload({ ); const uploadFile = useCallback( - async (file: File) => { - reset(); - - if (!file) { - return setCsvErrors('Kies eerst een .csv bestand.'); - } - + async (file?: File) => { const results = await parseCsvFile(file); if (!results) { - return; + return reset(); } + results.data = results.data.filter((item) => !!item); + const data = (results.data = results.data.filter((item) => !!item)); const header = data.length > 0 ? data[0] : []; @@ -183,14 +241,18 @@ export default function CSVUpload({ return Array.isArray(row) && row.filter((item) => !!item).length > 0; }); - setCsvFile(file); - if (header.length == 0) { - return setCsvErrors('Het .csv bestand is leeg, controleer het bestand.'); + setCsvErrors({ emptyHeader: 'Het .csv bestand is leeg, controleer het bestand' }); + setCsvIsValid(false); + return; } if (body.length == 0) { - return setCsvErrors('Het .csv bestand heeft kolomnamen maar geen inhoud, controleer de inhoud.'); + setCsvErrors({ + emptyBody: 'Het .csv bestand heeft kolomnamen maar geen inhoud, controleer de inhoud.', + }); + setCsvIsValid(false); + return; } // append eligibility key @@ -211,28 +273,27 @@ export default function CSVUpload({ return fund.csv_required_keys.indexOf(recordTypeKey) == -1; }); + const csvErrors: CSVErrorProp = {}; + const csvWarnings: CSVWarningProp = {}; + if (invalidRecordTypes.length > 0) { - return setCsvErrors( - `Het .csv bestand heeft de volgende ongeldige persoonsgegevens: '${invalidRecordTypes.join( - "', '", - )}'`, - ); + csvErrors.invalidRecordTypes = `Het .csv bestand heeft de volgende ongeldige persoonsgegevens: '${invalidRecordTypes.join( + "', '", + )}'`; } if (missingRecordTypes.length > 0) { - return setCsvErrors( - `In het .csv bestand ontbreken persoonsgegevens die verplicht zijn voor dit fonds '${ - fund.name - }': '${missingRecordTypes.join("', '")}'`, - ); + csvErrors.missingRecordTypes = `In het .csv bestand ontbreken persoonsgegevens die verplicht zijn voor dit fonds '${ + fund.name + }': '${missingRecordTypes.join("', '")}'`; } if (optionalRecordTypes.length > 0) { - setCsvWarnings([ + csvWarnings.optionalRecordTypes = [ `In het .csv bestand zijn persoonsgegevens toegevoegd die optioneel zijn voor "${fund.name}" fonds. `, 'Controleer of deze persoonsgegevens echt nodig zijn voor de toekenning. ', `De volgende persoonsgegevens zijn optioneel: "${optionalRecordTypes.join("', '")}".`, - ]); + ]; } const parsedData = body.reduce(function (result, val) { @@ -245,66 +306,43 @@ export default function CSVUpload({ }); return isEmpty(row) ? result : [...result, row]; - }, []); + }, []) as RowDataProp[]; - const invalidRows = validateFile(parsedData); + const invalidRows = validateCsvData(parsedData); if (invalidRows.length > 0) { - return setCsvErrors(['Volgende problemen zijn opgetreden bij dit .csv bestand:', ...invalidRows]); + csvErrors.invalidRows = ['Volgende problemen zijn opgetreden bij dit .csv bestand:', ...invalidRows]; } + setCsvFile(file); + + setCsvErrors(csvErrors); + setCsvWarnings(csvWarnings); + setData(parsedData); - setCsvIsValid(true); + setCsvIsValid(Object.keys(csvErrors).length === 0); setCsvProgress(1); }, - [parseCsvFile, fund, fundRecordKey, fundRecordKeyValue, validateFile, reset, criteriaRecordTypeKeys], + [criteriaRecordTypeKeys, fund, fundRecordKey, fundRecordKeyValue, parseCsvFile, reset, validateCsvData], ); - const showInvalidRows = useCallback( - (errors = {}, rows = [], rowIndex = 0) => { - const items = Object.keys(errors) - .map(function (key) { - const keyData = key.split('.'); - const keyDataId = keyData[1]; - const fieldKey = keyData[2]; - const index = parseInt(keyDataId, 10) + 1 + rowIndex; - - return [index, errors[key], fieldKey]; - }) - .sort((a, b) => a[0] - b[0]); + const updateProgressBarValue = useCallback((progress: number) => { + setProgressBar(progress); + setProgressStatus(progress < 100 ? 'Aan het uploaden...' : 'Klaar!'); + }, []); - const uniqueRows = items.reduce((arr, item) => { - return arr.includes(item[0]) ? arr : [...arr, item[0]]; - }, []); + const chunkList = useCallback((arr: Array, len: number) => { + const chunks = []; + const n = arr.length; - const message = [ - `${uniqueRows.length} van ${rows.length}`, - `rij(en) uit het bulkbestand zijn niet geimporteerd,`, - `bekijk het bestand bij welke rij(en) het mis gaat.`, - ].join(' '); + let i = 0; - pushDanger('Waarschuwing', message); + while (i < n) { + chunks.push(arr.slice(i, (i += len))); + } - openModal((modal) => ( - ({ - value: `Rij: ${item[0]}: ${item[2]} - ${item[1]}`, - _uid: uniqueId('rand_'), - label: item?.[fund.csv_primary_key], - }))} - onConfirm={() => reset()} - onCancel={() => reset()} - /> - )); - }, - [fund.csv_primary_key, openModal, pushDanger, reset], - ); + return chunks; + }, []); const startUploadingToServer = useCallback( (data: Array, overwriteUids: Array = []) => { @@ -320,7 +358,7 @@ export default function CSVUpload({ const uploadChunk = async function (data: Array<{ [key: string]: string }>) { prevalidationService - .submitCollection(data, fund.id, overwriteUids, { + .storeBatch(fund.organization_id, data, fund.id, overwriteUids, { name: csvFile.name, content: await fileToText(csvFile), total: data.length, @@ -329,19 +367,21 @@ export default function CSVUpload({ chunkSize: dataChunkSize, }) .then(() => { + setChanged(true); + currentChunkNth++; updateProgressBarValue((currentChunkNth / chunksCount) * 100); if (currentChunkNth == chunksCount) { setTimeout(() => { - setCsvProgressBar(100); + setProgressBar(100); setCsvProgress(3); - onUpdated?.(); + onCompleted?.(); resolve(null); }, 0); } else { - if (abort.current) { - return (abort.current = false); + if (abortRef.current) { + return (abortRef.current = false); } uploadChunk(submitData[currentChunkNth]); @@ -368,7 +408,8 @@ export default function CSVUpload({ chunkList, dataChunkSize, fund.id, - onUpdated, + fund.organization_id, + onCompleted, prevalidationService, pushDanger, showInvalidRows, @@ -422,6 +463,8 @@ export default function CSVUpload({ value: row[fund.csv_primary_key], })); + setHideModal(true); + openModal((modal) => ( 0) { return startUploadingToServer(newAndUpdatedRecords, updatePrimaryKeys).then(() => { if (skipUids.length > 0) { @@ -471,24 +516,25 @@ export default function CSVUpload({ }, console.error); } - onUpdated?.(); + onCompleted?.(); setCsvProgress(3); updateProgressBarValue(100); pushSuccess('Klaar!', skipUids.length + ' gegevens overgeslagen, geen nieuwe aangemaakt!'); }} onCancel={() => { - onUpdated?.(); + setHideModal(false); + onCompleted?.(); }} /> )); } }, - [fund.csv_primary_key, onUpdated, openModal, pushSuccess, startUploadingToServer, updateProgressBarValue], + [fund.csv_primary_key, onCompleted, openModal, pushSuccess, startUploadingToServer, updateProgressBarValue], ); const submitCollectionCheck = useCallback(() => { setCsvProgress(2); - abort.current = false; + abortRef.current = false; const submitData = chunkList(JSON.parse(JSON.stringify(data)), dataChunkSize); const chunksCount = submitData.length; @@ -501,7 +547,7 @@ export default function CSVUpload({ const uploadChunk = function (data: Array) { prevalidationService - .submitCollectionCheck(data, fund.id, []) + .submitCollectionCheck(fund.organization_id, data, fund.id, []) .then((res) => { currentChunkNth++; updateProgressBarValue((currentChunkNth / chunksCount) * 100); @@ -510,6 +556,8 @@ export default function CSVUpload({ if (currentChunkNth == chunksCount) { setTimeout(() => { + setLoading(false); + pushSuccess('Vergelijken...', 'Gegevens ingeladen! Vergelijken met .csv...', { icon: 'timer-sand', }); @@ -520,8 +568,8 @@ export default function CSVUpload({ ); }, 0); } else { - if (abort.current) { - return (abort.current = false); + if (abortRef.current) { + return (abortRef.current = false); } uploadChunk(submitData[currentChunkNth]); @@ -540,6 +588,7 @@ export default function CSVUpload({ }); }; + setLoading(true); uploadChunk(submitData[currentChunkNth]); }, [ chunkList, @@ -547,6 +596,7 @@ export default function CSVUpload({ data, dataChunkSize, fund?.id, + fund?.organization_id, prevalidationService, pushDanger, pushSuccess, @@ -557,6 +607,7 @@ export default function CSVUpload({ const onConfirmUpload = useCallback(() => { setCsvComparing(true); + pushSuccess('Inladen...', 'Inladen van gegevens voor controle op dubbele waarden!', { icon: 'download-outline', }); @@ -564,168 +615,170 @@ export default function CSVUpload({ submitCollectionCheck(); }, [pushSuccess, submitCollectionCheck]); - const addSinglePrevalidation = useCallback(() => { - openModal((modal) => ( - onUpdated?.()} - /> - )); - }, [fund, onUpdated, openModal, recordTypes]); - - const downloadSample = useCallback(() => { - fileService.downloadFile((fund.key || 'fund') + '_sample.csv', fundService.sampleCSV(fund)); - }, [fileService, fund, fundService]); + const onDragEvent = useCallback((e: React.DragEvent, isDragOver: boolean) => { + e?.preventDefault(); + e?.stopPropagation(); - useEffect(() => { - return () => reset(); - }, [reset]); + setIsDragOver(isDragOver); + }, []); return (
onDragEvent(e, true)} - onDragEnter={(e) => onDragEvent(e, true)} - onDragLeave={(e) => onDragEvent(e, false)} - onDragEnd={(e) => onDragEvent(e, false)} - onDrop={(e) => { - onDragEvent(e, false); - uploadFile(filterSelectedFiles(e.dataTransfer.files)?.[0]).then(); - }}> -
- { - uploadFile(filterSelectedFiles(e.target.files)?.[0]).then(); - e.target.value = null; - }} - /> - - {csvProgress <= 1 && ( -
inputRef.current.click()}> -
-
-
-
- {translate('csv_upload.labels.upload')} -
- {translate('csv_upload.labels.swipe')} -
-
- )} - -
-
- {csvProgress <= 1 && ( - - )} - - {csvProgress <= 1 && ( - - )} -
- -
- {csvProgress <= 1 && ( - - )} -
-
- - {csvProgress >= 2 && ( -
-
- {csvProgress === 2 &&
} - {csvProgress === 3 &&
} -
- - -
- )} - - {csvProgress <= 1 && csvFile && ( -
- {csvFile && ( -
-
-
- {csvIsValid ? ( -
- ) : ( -
- )} + className={classNames( + 'modal', + 'modal-bulk-upload', + 'modal-animated', + (modal.loading || hideModal) && 'modal-loading', + isDragOver && 'is-dragover', + className, + )}> +
+
+ +
Upload CSV-bestand
+
+
onDragEvent(e, true)} + onDragEnter={(e) => onDragEvent(e, true)} + onDragLeave={(e) => onDragEvent(e, false)} + onDragEnd={(e) => onDragEvent(e, false)} + onDrop={(e) => { + onDragEvent(e, false); + uploadFile(filterSelectedFiles(e.dataTransfer.files)?.[0]).then(); + }}> +
+ { + uploadFile(filterSelectedFiles(e.target.files)?.[0]).then(); + e.target.value = null; + }} + /> + + {csvProgress <= 1 && ( +
inputRef.current.click()}> +
+
-
-
{csvFile.name}
-
{fileSize(csvFile.size)}
+
+ {translate('csv_upload.labels.upload')} +
+ {translate('csv_upload.labels.swipe')}
-
+ )} + +
+ {csvProgress <= 1 && ( + + )} + {csvProgress <= 1 && ( + + )} +
- {csvProgress == 1 && csvIsValid && !csvComparing && ( -
-
- - - + {csvProgress >= 2 && ( +
+
+ {csvProgress == 2 &&
} + {csvProgress == 3 && ( +
+ )} +
+ +
+ )} + + {csvFile && csvProgress < 2 && ( +
+
+
+
+ {csvIsValid ? ( +
+ ) : ( +
+ )} +
+
+
{csvFile.name}
+
{fileSize(csvFile.size)}
+
+
reset(false)} />
- )} -
- )} - {csvWarnings && !csvErrors && ( -
- {[].concat(csvWarnings).map((warning) => ( -
{warning}
- ))} -
- )} + {Object.keys(csvErrors).length === 0 && Object.keys(csvWarnings).length > 0 && ( +
+ {Object.keys(csvWarnings).map((key) => ( +
{csvWarnings[key]}
+ ))} +
+ )} - {csvErrors && ( - - {[].concat(csvErrors).map((error, index) => ( -
- {error} -
- ))} -
- )} + {Object.keys(csvErrors).length > 0 && ( +
+ {Object.keys(csvErrors).map((key) => ( +
{csvErrors[key]}
+ ))} +
+ )} +
+ )} +
- )} +
- {csvProgress == 3 && ( -
- + )} + +
+ +
+ + {csvProgress < 3 ? ( + + ) : ( + + )} +
- )} +
); diff --git a/react/src/dashboard/components/pages/csv_validations/CsvValidations.tsx b/react/src/dashboard/components/pages/csv_validations/CsvValidations.tsx deleted file mode 100644 index 1eee831f2..000000000 --- a/react/src/dashboard/components/pages/csv_validations/CsvValidations.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useState, useCallback, useEffect, Fragment } from 'react'; -import { useFundService } from '../../../services/FundService'; -import Fund from '../../../props/models/Fund'; -import CSVUpload from './elements/CSVUpload'; -import { useRecordTypeService } from '../../../services/RecordTypeService'; -import RecordType from '../../../props/models/RecordType'; -import PrevalidatedTable from './elements/PrevalidatedTable'; -import EmptyCard from '../../elements/empty-card/EmptyCard'; -import useTranslate from '../../../hooks/useTranslate'; -import LoadingCard from '../../elements/loading-card/LoadingCard'; -import { hasPermission } from '../../../helpers/utils'; -import useSetProgress from '../../../hooks/useSetProgress'; -import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptionsFund from '../../elements/select-control/templates/SelectControlOptionsFund'; - -export default function CsvValidations() { - const translate = useTranslate(); - const setProgress = useSetProgress(); - - const fundService = useFundService(); - const recordTypeService = useRecordTypeService(); - - const [fund, setFund] = useState(null); - const [funds, setFunds] = useState>(null); - const [recordTypes, setRecordTypes] = useState>(null); - - const [filters, setFilters] = useState({}); - - const fetchFunds = useCallback(() => { - setProgress(0); - - fundService - .listPublic({ state: 'active_paused_and_closed' }) - .then((res) => { - const list = res.data.data.filter((fund) => hasPermission(fund.organization, 'validate_records')); - setFund(list[0] || null); - setFunds(list); - }) - .finally(() => setProgress(100)); - }, [fundService, setProgress]); - - const fetchRecordTypes = useCallback(() => { - setProgress(0); - - recordTypeService - .list() - .then((res) => setRecordTypes(res.data)) - .finally(() => setProgress(100)); - }, [recordTypeService, setProgress]); - - useEffect(() => { - fetchFunds(); - }, [fetchFunds]); - - useEffect(() => { - fetchRecordTypes(); - }, [fetchRecordTypes]); - - if (!funds) { - return ; - } - - return ( - -
-
-
{translate('csv_validation.header.title')}
- -
-
-
-
- setFund(fund)} - optionsComponent={SelectControlOptionsFund} - /> -
-
-
-
-
- - {fund && fund?.state != 'closed' && ( - setFilters((filters) => ({ ...filters }))} - /> - )} -
- - {fund && } - - {funds?.length == 0 && ( - - )} -
- ); -} diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowStatisticsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowStatisticsCard.tsx index 73de62a85..01c0a2a1e 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowStatisticsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowStatisticsCard.tsx @@ -92,7 +92,7 @@ export default function OrganizationsFundsShowStatisticsCard({ { - navigateState('csv-validation', { fundId: fund.organization_id }); + navigateState('csv-validation', { organizationId: fund.organization_id }); }}>
{translate('fund_card_sponsor.labels.applicants')}
diff --git a/react/src/dashboard/components/pages/csv_validations/elements/PrevalidatedTable.tsx b/react/src/dashboard/components/pages/prevalidations/Prevalidations.tsx similarity index 61% rename from react/src/dashboard/components/pages/csv_validations/elements/PrevalidatedTable.tsx rename to react/src/dashboard/components/pages/prevalidations/Prevalidations.tsx index 3a3b71d54..bbf26d657 100644 --- a/react/src/dashboard/components/pages/csv_validations/elements/PrevalidatedTable.tsx +++ b/react/src/dashboard/components/pages/prevalidations/Prevalidations.tsx @@ -1,58 +1,63 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import Fund from '../../../../props/models/Fund'; -import RecordType from '../../../../props/models/RecordType'; -import useFilter from '../../../../hooks/useFilter'; -import usePaginatorService from '../../../../modules/paginator/services/usePaginatorService'; -import ClickOutside from '../../../elements/click-outside/ClickOutside'; -import FilterItemToggle from '../../../elements/tables/elements/FilterItemToggle'; -import SelectControl from '../../../elements/select-control/SelectControl'; -import { dateFormat, dateParse } from '../../../../helpers/dates'; -import DatePickerControl from '../../../elements/forms/controls/DatePickerControl'; -import ModalExportTypeLegacy from '../../../modals/ModalExportTypeLegacy'; -import useOpenModal from '../../../../hooks/useOpenModal'; -import { PaginationData } from '../../../../props/ApiResponses'; -import Prevalidation from '../../../../props/models/Prevalidation'; -import { usePrevalidationService } from '../../../../services/PrevalidationService'; -import Paginator from '../../../../modules/paginator/components/Paginator'; -import { useEmployeeService } from '../../../../services/EmployeeService'; -import useActiveOrganization from '../../../../hooks/useActiveOrganization'; -import ModalNotification from '../../../modals/ModalNotification'; -import usePushSuccess from '../../../../hooks/usePushSuccess'; -import LoadingCard from '../../../elements/loading-card/LoadingCard'; +import React, { useState, useCallback, useEffect, useMemo } from 'react'; +import { useFundService } from '../../../services/FundService'; +import Fund from '../../../props/models/Fund'; +import { useRecordTypeService } from '../../../services/RecordTypeService'; +import RecordType from '../../../props/models/RecordType'; +import useTranslate from '../../../hooks/useTranslate'; +import LoadingCard from '../../elements/loading-card/LoadingCard'; +import { hasPermission } from '../../../helpers/utils'; +import useSetProgress from '../../../hooks/useSetProgress'; +import SelectControl from '../../elements/select-control/SelectControl'; +import SelectControlOptionsFund from '../../elements/select-control/templates/SelectControlOptionsFund'; +import useActiveOrganization from '../../../hooks/useActiveOrganization'; +import useOpenModal from '../../../hooks/useOpenModal'; +import usePushSuccess from '../../../hooks/usePushSuccess'; +import usePushApiError from '../../../hooks/usePushApiError'; +import { useFileService } from '../../../services/FileService'; +import { useEmployeeService } from '../../../services/EmployeeService'; +import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; +import { usePrevalidationService } from '../../../services/PrevalidationService'; +import Employee from '../../../props/models/Employee'; +import { PaginationData } from '../../../props/ApiResponses'; +import Prevalidation from '../../../props/models/Prevalidation'; +import useConfigurableTable from '../vouchers/hooks/useConfigurableTable'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; import { format } from 'date-fns'; -import { useFileService } from '../../../../services/FileService'; -import EmptyCard from '../../../elements/empty-card/EmptyCard'; -import useTranslate from '../../../../hooks/useTranslate'; -import useSetProgress from '../../../../hooks/useSetProgress'; -import Employee from '../../../../props/models/Employee'; -import usePushApiError from '../../../../hooks/usePushApiError'; -import useConfigurableTable from '../../vouchers/hooks/useConfigurableTable'; -import TableTopScroller from '../../../elements/tables/TableTopScroller'; -import TableRowActions from '../../../elements/tables/TableRowActions'; -import TableEmptyValue from '../../../elements/table-empty-value/TableEmptyValue'; - -export default function PrevalidatedTable({ - fund, - recordTypes = [], - externalFilters = {}, -}: { - fund: Fund; - recordTypes: Array; - externalFilters: object; -}) { +import ModalExportTypeLegacy from '../../modals/ModalExportTypeLegacy'; +import ModalNotification from '../../modals/ModalNotification'; +import ModalCreatePrevalidation from '../../modals/ModalCreatePrevalidation'; +import ModalPrevalidationsUpload from '../../modals/ModalPrevalidationsUpload'; +import ClickOutside from '../../elements/click-outside/ClickOutside'; +import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; +import DatePickerControl from '../../elements/forms/controls/DatePickerControl'; +import { dateFormat, dateParse } from '../../../helpers/dates'; +import LoaderTableCard from '../../elements/loader-table-card/LoaderTableCard'; +import TableTopScroller from '../../elements/tables/TableTopScroller'; +import { strLimit } from '../../../helpers/string'; +import TableRowActions from '../../elements/tables/TableRowActions'; +import TableEmptyValue from '../../elements/table-empty-value/TableEmptyValue'; +import Paginator from '../../../modules/paginator/components/Paginator'; +import { NumberParam, StringParam } from 'use-query-params'; +import EmptyCard from '../../elements/empty-card/EmptyCard'; + +export default function Prevalidations() { const translate = useTranslate(); const openModal = useOpenModal(); + const setProgress = useSetProgress(); const pushSuccess = usePushSuccess(); const pushApiError = usePushApiError(); - const setProgress = useSetProgress(); const activeOrganization = useActiveOrganization(); const fileService = useFileService(); + const fundService = useFundService(); const employeeService = useEmployeeService(); const paginatorService = usePaginatorService(); + const recordTypeService = useRecordTypeService(); const prevalidationService = usePrevalidationService(); + const [funds, setFunds] = useState>(null); const [paginatorKey] = useState('products'); + const [recordTypes, setRecordTypes] = useState>(null); const [employees, setEmployees] = useState>(null); const [prevalidations, setPrevalidations] = useState>(null); @@ -77,7 +82,49 @@ export default function PrevalidatedTable({ { key: 0, name: 'Nee' }, ]); + const [filterValues, filterValuesActive, filterUpdate, filter] = useFilterNext<{ + q?: string; + to?: string; + from?: string; + state?: string; + fund_id?: number; + exported?: number; + page?: number; + per_page?: number; + }>( + { + q: '', + fund_id: null, + state: states[0].key, + exported: statesExported[0].key, + from: null, + to: null, + page: 1, + per_page: paginatorService.getPerPage(paginatorKey, 10), + }, + { + queryParams: { + q: StringParam, + fund_id: NumberParam, + state: StringParam, + exported: NumberParam, + from: StringParam, + to: StringParam, + per_page: NumberParam, + page: NumberParam, + }, + }, + ); + + const fund = useMemo(() => { + return funds?.find((fund) => fund.id === filterValues?.fund_id); + }, [funds, filterValues?.fund_id]); + const headers = useMemo(() => { + if (!fund?.csv_primary_key) { + return null; + } + const headers: string[] = prevalidations?.data ?.reduce((headers, prevalidation) => { return prevalidation.records @@ -88,15 +135,15 @@ export default function PrevalidatedTable({ ?.filter((header: string) => !header?.endsWith('_hash')) ?.sort(); - const primaryKey = headers?.indexOf(fund.csv_primary_key); + const primaryKey = headers?.indexOf(fund?.csv_primary_key); if (primaryKey !== -1) { headers?.splice(primaryKey, 1); - headers?.unshift(fund.csv_primary_key); + headers?.unshift(fund?.csv_primary_key); } return headers; - }, [fund.csv_primary_key, prevalidations]); + }, [fund?.csv_primary_key, prevalidations]); const rows = useMemo(() => { return prevalidations?.data?.map((prevalidation) => ({ @@ -111,20 +158,10 @@ export default function PrevalidatedTable({ prevalidationService.getColumns(headers || [], typesByKey), ); - const filter = useFilter({ - q: '', - fund_id: fund ? fund.id : null, - state: states[0].key, - exported: statesExported[0].key, - from: null, - to: null, - per_page: paginatorService.getPerPage(paginatorKey), - }); - const doExport = useCallback( (exportType: string) => { prevalidationService - .export({ ...externalFilters, ...filter.activeValues, fund_id: fund.id, export_type: exportType }) + .export(fund.organization_id, { ...filterValuesActive, fund_id: fund.id, export_type: exportType }) .then((res) => { const dateTime = format(new Date(), 'yyyy-MM-dd HH:mm:ss'); const fileType = res.headers['content-type'] + ';charset=utf-8;'; @@ -133,7 +170,15 @@ export default function PrevalidatedTable({ fileService.downloadFile(fileName, res.data, fileType); }, pushApiError); }, - [fileService, externalFilters, filter.activeValues, fund.key, fund.id, prevalidationService, pushApiError], + [ + fileService, + filterValuesActive, + fund?.key, + fund?.id, + fund?.organization_id, + prevalidationService, + pushApiError, + ], ); const exportData = useCallback(() => { @@ -148,13 +193,17 @@ export default function PrevalidatedTable({ }, [doExport, openModal]); const fetchPrevalidations = useCallback(() => { + if (!fund?.id) { + return; + } + setProgress(0); prevalidationService - .list({ ...externalFilters, ...filter.activeValues, fund_id: fund.id }) + .list(activeOrganization.id, { ...filterValuesActive, fund_id: fund.id }) .then((res) => setPrevalidations(res.data)) .finally(() => setProgress(100)); - }, [setProgress, prevalidationService, externalFilters, filter.activeValues, fund.id]); + }, [setProgress, prevalidationService, filterValuesActive, fund?.id, activeOrganization.id]); const fetchEmployees = useCallback(() => { setProgress(0); @@ -165,6 +214,29 @@ export default function PrevalidatedTable({ .finally(() => setProgress(100)); }, [setProgress, activeOrganization.id, employeeService]); + const fetchFunds = useCallback(() => { + setProgress(0); + + fundService + .list(activeOrganization?.id, { state: 'active_paused_and_closed' }) + .then((res) => { + const funds = res.data.data.filter((fund) => hasPermission(fund.organization, 'validate_records')); + + setFunds(funds); + filterUpdate({ fund_id: funds?.[0]?.id }); + }) + .finally(() => setProgress(100)); + }, [setProgress, fundService, activeOrganization?.id, filterUpdate]); + + const fetchRecordTypes = useCallback(() => { + setProgress(0); + + recordTypeService + .list() + .then((res) => setRecordTypes(res.data)) + .finally(() => setProgress(100)); + }, [recordTypeService, setProgress]); + const deletePrevalidation = useCallback( (prevalidation: Prevalidation) => { openModal((modal) => ( @@ -180,10 +252,12 @@ export default function PrevalidatedTable({ onClick: () => { modal.close(); - prevalidationService.destroy(prevalidation.uid).then(() => { - pushSuccess('Gegeven verwijderd'); - fetchPrevalidations(); - }); + prevalidationService + .destroy(prevalidation.fund.organization_id, prevalidation.uid) + .then(() => { + pushSuccess('Gegeven verwijderd'); + fetchPrevalidations(); + }); }, }} buttonCancel={{ onClick: () => modal.close() }} @@ -193,6 +267,29 @@ export default function PrevalidatedTable({ [fetchPrevalidations, openModal, prevalidationService, pushSuccess], ); + const createPrevalidation = useCallback( + (fund: Fund, onCreate?: () => void) => { + openModal((modal) => ( + onCreate?.()} + /> + )); + }, + [openModal, recordTypes], + ); + + const uploadPrevalidations = useCallback( + (fund: Fund, onCreate?: () => void) => { + openModal((modal) => ( + + )); + }, + [openModal, recordTypes], + ); + useEffect(() => { fetchEmployees(); }, [fetchEmployees]); @@ -201,6 +298,18 @@ export default function PrevalidatedTable({ fetchPrevalidations(); }, [fetchPrevalidations]); + useEffect(() => { + fetchFunds(); + }, [fetchFunds]); + + useEffect(() => { + fetchRecordTypes(); + }, [fetchRecordTypes]); + + if (funds?.length === 0) { + return ; + } + if (!prevalidations) { return ; } @@ -208,9 +317,40 @@ export default function PrevalidatedTable({ return (
-
{translate('prevalidated_table.header.title')}
+
+ {translate('prevalidated_table.header.title')} ({prevalidations?.meta?.total}) +
-
+
+ + + + +
+ filterUpdate({ fund_id: fund?.id })} + optionsComponent={SelectControlOptionsFund} + /> +
+ {filter.show && (
- {rows.length > 0 && headers && ( +
{configsElement} @@ -335,6 +481,16 @@ export default function PrevalidatedTable({ {rows?.map((row) => ( {row.uid} + + +
+ {strLimit(row.fund?.name, 32)} +
+ +
+ {strLimit(row.fund?.implementation?.name, 32)} +
+ {employeesByAddress?.[row?.identity_address] || 'Unknown'} @@ -393,22 +549,18 @@ export default function PrevalidatedTable({
- )} - - {prevalidations?.meta.total === 0 && ( - - )} - {prevalidations?.meta && ( -
- -
- )} + {prevalidations?.meta.total > 0 && ( +
+ +
+ )} +
); } diff --git a/react/src/dashboard/i18n/i18n-nl.js b/react/src/dashboard/i18n/i18n-nl.js index fed30ca56..aed34eb5f 100644 --- a/react/src/dashboard/i18n/i18n-nl.js +++ b/react/src/dashboard/i18n/i18n-nl.js @@ -329,6 +329,8 @@ export default { }, buttons: { choose: 'Kies een ander fonds', + create: 'Activatiecode aanmaken', + upload: 'Upload .csv bestand', }, }, // FINANCIAL DASHBOARD = financial-dashboard-transaction.pug @@ -1741,10 +1743,11 @@ export default { // PRE VALIDATED TABLE = prevalidated_table.pug prevalidated_table: { header: { - title: 'Gegevens van aanvragers', + title: 'Klaarzetten', }, labels: { code: 'Code', + fund: 'Fonds', employee: 'Medewerker', search: 'Zoeken', exported: 'Geëxporteerd', @@ -1758,6 +1761,7 @@ export default { export_selected: 'Exporteer selectie', export_csv: 'Exporteer als .CSV', export_xls: 'Exporteer als .XLS', + add_new: 'Exporteer als .XLS', }, }, diff --git a/react/src/dashboard/props/models/Prevalidation.tsx b/react/src/dashboard/props/models/Prevalidation.tsx index be17fb8cb..07c22a2a8 100644 --- a/react/src/dashboard/props/models/Prevalidation.tsx +++ b/react/src/dashboard/props/models/Prevalidation.tsx @@ -1,4 +1,5 @@ import PrevalidationRecord from './PrevalidationRecord'; +import Fund from './Fund'; export default interface Prevalidation { id: number; @@ -8,6 +9,7 @@ export default interface Prevalidation { identity_address: string; records_hash: string; state: string; + fund?: Fund; uid?: string; uid_hash?: string; } diff --git a/react/src/dashboard/router/routes.tsx b/react/src/dashboard/router/routes.tsx index e68df8e65..0f49ac58c 100644 --- a/react/src/dashboard/router/routes.tsx +++ b/react/src/dashboard/router/routes.tsx @@ -7,7 +7,7 @@ import FundRequests from '../components/pages/fund-requests/FundRequests'; import FundRequestsView from '../components/pages/fund-requests-view/FundRequestsView'; import Home from '../components/pages/home/Home'; import Employees from '../components/pages/employees/Employees'; -import CsvValidations from '../components/pages/csv_validations/CsvValidations'; +import Prevalidations from '../components/pages/prevalidations/Prevalidations'; import Organizations from '../components/pages/organizations/Organizations'; import IdentityRestore from '../components/pages/auth/IdentityRestore'; import Redirect from '../components/pages/redirect/Redirect'; @@ -605,9 +605,9 @@ router.state('feedback', , { altPath: `/organizations/:organizationId/feedback`, }); -router.state('csv-validation', , { - path: `/aanvragers-toevoegen`, - altPath: `/csv-validations`, +router.state('csv-validation', , { + path: `/organisaties/:organizationId/aanvragers-toevoegen`, + altPath: `/organizations/:organizationId/csv-validations`, }); router.state('preferences-emails', , { diff --git a/react/src/dashboard/services/FundService.ts b/react/src/dashboard/services/FundService.ts index 8353d736b..7915d934e 100644 --- a/react/src/dashboard/services/FundService.ts +++ b/react/src/dashboard/services/FundService.ts @@ -40,10 +40,6 @@ export class FundService { return this.apiRequest.get(`${this.prefix}/${company_id}/funds`, data); } - public listPublic(data: object = {}): Promise }>> { - return this.apiRequest.get(`${this.prefix_public}`, data); - } - public read(company_id: number, fund_id: number, data: object = {}): Promise> { return this.apiRequest.get(`${this.prefix}/${company_id}/funds/${fund_id}`, data); } diff --git a/react/src/dashboard/services/PrevalidationService.ts b/react/src/dashboard/services/PrevalidationService.ts index 59c6a3f84..dab496ad0 100644 --- a/react/src/dashboard/services/PrevalidationService.ts +++ b/react/src/dashboard/services/PrevalidationService.ts @@ -15,26 +15,31 @@ export class PrevalidationService { * * @param data */ - public prefix = '/platform/prevalidations'; + public prefix = '/platform/organizations'; - public list(filters: object = {}): Promise> { - return this.apiRequest.get(`${this.prefix}`, filters); + /** + * @param organization_id + * @param filters + */ + public list(organization_id: number, filters: object = {}): Promise> { + return this.apiRequest.get(`${this.prefix}/${organization_id}/prevalidations`, filters); } - public submit(data: object = {}, fund_id: number = null): Promise> { - return this.apiRequest.post(`${this.prefix}`, { + public store(organization_id: number, data: object = {}, fund_id: number = null): Promise> { + return this.apiRequest.post(`${this.prefix}/${organization_id}/prevalidations`, { data: data, fund_id: fund_id, }); } - public submitCollection( + public storeBatch( + organization_id: number, data: Array<{ [key: string]: string }>, fund_id: number = null, overwrite: Array = [], file?: object, ): Promise { - return this.apiRequest.post(`${this.prefix}/collection`, { + return this.apiRequest.post(`${this.prefix}/${organization_id}/prevalidations/collection`, { data: data, fund_id: fund_id, overwrite: overwrite, @@ -43,6 +48,7 @@ export class PrevalidationService { } public submitCollectionCheck( + organization_id: number, data: Array, fund_id: number = null, overwrite: Array = [], @@ -52,33 +58,33 @@ export class PrevalidationService { db: Array<{ uid_hash: string; records_hash: string }>; }; }> { - return this.apiRequest.post(`${this.prefix}/collection/hash`, { + return this.apiRequest.post(`${this.prefix}/${organization_id}/prevalidations/collection/hash`, { data: data, fund_id: fund_id, overwrite: overwrite, }); } - public destroy(code: string): Promise> { - return this.apiRequest.delete(`${this.prefix}/${code}`); + public destroy(organization_id: number, code: string): Promise> { + return this.apiRequest.delete(`${this.prefix}/${organization_id}/prevalidations/${code}`); } - public export(filters: object = {}): Promise> { - return this.apiRequest.get(`${this.prefix}/export`, filters, { + public export(organization_id: number, filters: object = {}): Promise> { + return this.apiRequest.get(`${this.prefix}/${organization_id}/prevalidations/export`, filters, { responseType: 'arraybuffer', }); } public getColumns(headers: Array, typesByKey: object): Array { - const list = ['code', 'employee', ...headers, 'active', 'exported']; + const list = ['code', 'fund', 'employee', ...headers, 'active', 'exported']; return list.map((key) => ({ key, - label: typesByKey[key] || `prevalidated_table.labels.${key}`, + label: typesByKey?.[key] || `prevalidated_table.labels.${key}`, tooltip: { key: key, - title: typesByKey[key] || `prevalidated_table.labels.${key}`, - description: typesByKey[key] || `prevalidated_table.tooltips.${key}`, + title: typesByKey?.[key] || `prevalidated_table.labels.${key}`, + description: typesByKey?.[key] || `prevalidated_table.tooltips.${key}`, }, })); } From d7cb9baa8442e6b74392ed52bd51c3cbe6d818ff Mon Sep 17 00:00:00 2001 From: dev-rminds Date: Sat, 10 May 2025 14:27:05 +0300 Subject: [PATCH 02/10] ui consistency, refactoring and cleanup for labels, borders and form groups --- .../_common/blocks/block-banner-editor.scss | 6 +- .../_common/blocks/block-danger_zone.scss | 2 +- .../blocks/block-financial-dashboard.scss | 2 +- .../_common/blocks/block-mail_preview.scss | 2 +- .../_common/blocks/block-markdownable.scss | 2 +- .../scss/_common/blocks/block-pincode.scss | 4 +- .../block-pre-checks-blocks-editor.scss | 2 +- .../scss/_common/blocks/block-product.scss | 2 +- .../scss/_common/blocks/block-sessions.scss | 2 +- .../block-subsidy-product-overview.scss | 2 +- .../blocks/block-voucher-records-editor.scss | 2 +- .../block-feature-text-image-columns.scss | 2 +- .../marketplace-features/block-feature.scss | 2 +- .../marketplace-features/block-features.scss | 2 +- .../scss/_common/components/buttons.scss | 2 +- .../scss/_common/components/forms.scss | 173 +--- .../scss/_common/components/labels.scss | 47 +- .../scss/_common/components/modals.scss | 8 +- .../scss/_common/components/tables.scss | 4 +- .../scss/_common/components/tags.scss | 79 -- .../scss/_common/dashboard.scss | 92 +-- .../scss/_common/includes/printables.scss | 2 +- .../scss/_common/includes/third-party.scss | 172 ---- .../forus-platform/scss/_common/landing.scss | 41 +- .../select-control-organizations.scss | 4 +- .../scss/includes/components/_form.scss | 212 ----- .../scss/includes/components/_label.scss | 8 - .../scss/includes/components/table.scss | 7 - .../scss/includes/includes/shame.scss | 2 - .../scss/includes/includes/third-party.scss | 150 ---- .../elements/forms/controls/FormGroup.tsx | 31 +- .../forms/controls/MultiSelectControl.tsx | 24 +- .../FundCriteriaEditorItem.tsx | 74 +- .../elements/image_cropper/Label.tsx | 46 ++ .../resource-states/FundFormStateLabels.tsx | 24 +- .../resource-states/FundRequestStateLabel.tsx | 21 +- .../resource-states/FundStateLabels.tsx | 40 +- .../ReimbursementStateLabel.tsx | 45 ++ .../resource-states/TransactionStateLabel.tsx | 8 +- .../tables/elements/FilterItemToggle.tsx | 2 +- .../components/modals/Modal2FADeactivate.tsx | 23 +- .../modals/ModalCreatePrevalidation.tsx | 18 +- .../modals/ModalDuplicatesPicker.tsx | 2 +- .../modals/ModalFundInviteProviders.tsx | 18 +- .../components/modals/ModalFundOffers.tsx | 8 +- .../components/modals/ModalPayoutEdit.tsx | 16 - .../components/modals/ModalPayoutsUpload.tsx | 33 +- .../ModalPreCheckEditFundExclusions.tsx | 116 ++- .../modals/ModalReimbursementDetailsEdit.tsx | 48 +- .../modals/ModalReservationCreate.tsx | 32 +- .../components/modals/ModalVoucherCreate.tsx | 317 ++++---- .../modals/ModalVoucherDeactivation.tsx | 2 +- .../modals/ModalVoucherRecordEdit.tsx | 39 +- .../ModalVoucherTransaction.tsx | 188 +++-- .../components/modals/ModalVouchersUpload.tsx | 54 +- .../components/pages/auth/SignUpProvider.tsx | 26 +- .../SignUpStepOrganizationAdd.tsx | 26 +- .../bank-connections/BankConnections.tsx | 12 +- .../pages/bi-connection/BiConnection.tsx | 562 ++++++------- .../elements/PrevalidatedTable.tsx | 15 +- .../components/pages/feedback/Feedback.tsx | 54 +- .../elements/FinancialFilters.tsx | 8 +- .../FundBackofficeEdit.tsx | 251 +++--- .../FundProviderProductSubsidyEdit.tsx | 46 +- .../FundProviderProductView.tsx | 11 +- .../elements/FundProviderProductEditor.tsx | 310 ++++---- .../pages/fund-provider/FundProvider.tsx | 5 +- .../elements/SubsidyFundProducts.tsx | 9 +- .../elements/SubsidyFundSponsorProducts.tsx | 9 +- .../modals/ModalEditProfileBankAccount.tsx | 4 - .../modals/ModalEditProfileRecords.tsx | 6 - .../PreferencesEmails.tsx | 25 +- .../pages/identity-security/Security2FA.tsx | 5 +- .../identity-security/SecuritySessions.tsx | 5 +- .../ImplementationsBlockEditorItem.tsx | 23 +- ...lementationsCmsHomeProductsBlockEditor.tsx | 54 +- .../elements/ImplementationsCmsPageForm.tsx | 249 +++--- .../ImplementationsCms.tsx | 293 ++++--- .../ImplementationsCookies.tsx | 3 +- .../ImplementationsTranslations.tsx | 2 - .../ImplementationsDigid.tsx | 10 +- .../ImplementationsEmail.tsx | 22 +- .../ImplementationsNotificationsBranding.tsx | 87 +- .../elements/SystemNotificationEditor.tsx | 34 +- .../ImplementationsNotificationsSend.tsx | 63 +- .../ImplementationsNotifications.tsx | 28 +- .../offices-edit/elements/OfficesForm.tsx | 71 +- .../OrganizationsContacts.tsx | 163 ++-- .../elements/OrganizationForm.tsx | 259 +++--- .../OrganizationsFundsEdit.tsx | 744 +++++++++--------- .../OrganizationsFundsSecurity.tsx | 50 +- .../OrganizationsFundsSecurityAuth2FAForm.tsx | 115 ++- ...anizationsFundsShowImplementationsCard.tsx | 5 +- .../OrganizationsSecurity.tsx | 194 +++-- .../OrganizationsTranslations.tsx | 8 - .../pages/payment-methods/PaymentMethods.tsx | 13 +- .../elements/MollieConnectionForm.tsx | 34 +- .../MollieConnectionProfileDetails.tsx | 12 +- .../components/pages/pre-check/PreCheck.tsx | 88 +-- .../elements/ProductCategoriesControl.tsx | 35 +- .../products-edit/elements/ProductsForm.tsx | 613 +++++++-------- .../pages/products-view/ProductView.tsx | 5 +- .../elements/ProviderFundInvitationsTable.tsx | 44 +- .../ProviderFundUnsubscriptionsTable.tsx | 17 +- .../elements/ProviderFundsTable.tsx | 15 +- .../ReimbursementsView.tsx | 29 +- .../elements/ReimbursementsTable.tsx | 28 +- .../ReservationsSettings.tsx | 116 +-- .../ReservationExtraPaymentDetails.tsx | 9 +- .../ReservationExtraPaymentRefunds.tsx | 7 +- .../pages/reservations/Reservations.tsx | 2 - .../elements/ReservationLabel.tsx | 39 +- .../SponsorFundUnsubscriptionTableItem.tsx | 21 +- .../ProductMonitoredHistoryCardFunds.tsx | 15 +- .../SponsorProviderOrganizations.tsx | 22 +- .../TransactionBulksView.tsx | 11 +- .../TransactionBulkTransactionsTable.tsx | 10 +- .../TransactionSettings.tsx | 230 +++--- .../pages/transactions/Transactions.tsx | 34 +- .../vouchers-view/VouchersViewComponent.tsx | 11 +- .../elements/VoucherTransactions.tsx | 9 +- .../elements/VoucherRecordsEditor.tsx | 73 +- .../src/dashboard/i18n/en/i18n-components.js | 1 - .../dashboard/props/models/Reimbursement.tsx | 2 +- .../templates/FundsListItemList.tsx | 3 +- .../components/modals/Modal2FADeactivate.tsx | 22 +- .../modals/ModalDeactivateVoucher.tsx | 2 +- .../identity-security/SecuritySessions.tsx | 4 +- .../ReimbursementsEdit.tsx | 54 +- 129 files changed, 3320 insertions(+), 4442 deletions(-) delete mode 100644 react/assets/forus-platform/scss/_common/components/tags.scss create mode 100644 react/src/dashboard/components/elements/image_cropper/Label.tsx create mode 100644 react/src/dashboard/components/elements/resource-states/ReimbursementStateLabel.tsx diff --git a/react/assets/forus-platform/scss/_common/blocks/block-banner-editor.scss b/react/assets/forus-platform/scss/_common/blocks/block-banner-editor.scss index 91a26d486..8acb01164 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-banner-editor.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-banner-editor.scss @@ -49,7 +49,7 @@ gap: 10px; padding: 30px 30px; z-index: 1; - border-radius: 4px; + border-radius: var(--border-radius); .banner-editor-title { font: 500 15px/20px var(--base-font); @@ -109,7 +109,7 @@ .banner-editor-control-color { padding: 0 5px; border: 1px solid var(--border-color); - border-radius: 5px; + border-radius: var(--border-radius); display: flex; flex-direction: row; align-items: center; @@ -122,7 +122,7 @@ .banner-editor-control-color-preview { width: 16px; height: 16px; - border-radius: 4px; + border-radius: var(--border-radius); box-shadow: 1px 1px 5px 0 rgba(25, 39, 52, 0.11); } diff --git a/react/assets/forus-platform/scss/_common/blocks/block-danger_zone.scss b/react/assets/forus-platform/scss/_common/blocks/block-danger_zone.scss index d7c0a67b4..397e4ed70 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-danger_zone.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-danger_zone.scss @@ -2,7 +2,7 @@ display: flex; flex-direction: column; border: 1px solid var(--color-danger); - border-radius: 3px; + border-radius: var(--border-radius); background: #fff; align-items: center; margin-bottom: 20px; diff --git a/react/assets/forus-platform/scss/_common/blocks/block-financial-dashboard.scss b/react/assets/forus-platform/scss/_common/blocks/block-financial-dashboard.scss index 2a0150be8..1e037033c 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-financial-dashboard.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-financial-dashboard.scss @@ -122,7 +122,7 @@ flex-basis: 33.333%; margin-right: 20px; background: #ffffff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 2px 8px rgba(#000, 0.1); cursor: default; diff --git a/react/assets/forus-platform/scss/_common/blocks/block-mail_preview.scss b/react/assets/forus-platform/scss/_common/blocks/block-mail_preview.scss index 15d38ff3b..25146ea8d 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-mail_preview.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-mail_preview.scss @@ -77,7 +77,7 @@ $mailFont: Verdana, Arial, sans-serif; padding: 5px 75px; font: 600 14px/40px $mailFont; color: #fff; - border-radius: 3px; + border-radius: var(--border-radius); text-decoration: none; background-color: #315efd; cursor: pointer; diff --git a/react/assets/forus-platform/scss/_common/blocks/block-markdownable.scss b/react/assets/forus-platform/scss/_common/blocks/block-markdownable.scss index e21983311..22ce764c9 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-markdownable.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-markdownable.scss @@ -114,7 +114,7 @@ .note-editing-area { border: 1px solid var(--border-color); - border-radius: 3px; + border-radius: var(--border-radius); background-color: #ffffff; .note-placeholder { diff --git a/react/assets/forus-platform/scss/_common/blocks/block-pincode.scss b/react/assets/forus-platform/scss/_common/blocks/block-pincode.scss index f8aa1d4a0..9de0adbef 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-pincode.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-pincode.scss @@ -30,7 +30,7 @@ width: 40px; border: 1px solid var(--border-color); background: #fff; - border-radius: 4px; + border-radius: var(--border-radius); margin-right: 6px; padding: 9px 0; font: 600 18px/38px 'Open Sans', arial, sans-serif; @@ -84,7 +84,7 @@ background: #b7bfc6; width: 7px; height: 2px; - border-radius: 5px; + border-radius: var(--border-radius); } } } diff --git a/react/assets/forus-platform/scss/_common/blocks/block-pre-checks-blocks-editor.scss b/react/assets/forus-platform/scss/_common/blocks/block-pre-checks-blocks-editor.scss index dc65bebaa..2818c20f8 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-pre-checks-blocks-editor.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-pre-checks-blocks-editor.scss @@ -164,7 +164,7 @@ width: 100%; height: 100%; object-fit: cover; - border-radius: 4px; + border-radius: var(--border-radius); border: 1px solid var(--border-color); } } diff --git a/react/assets/forus-platform/scss/_common/blocks/block-product.scss b/react/assets/forus-platform/scss/_common/blocks/block-product.scss index 6da44719d..00a668c4c 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-product.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-product.scss @@ -8,7 +8,7 @@ .block-product-media { flex: 0 0 190px; border: 1px solid #d4d9dd; - border-radius: 4px; + border-radius: var(--border-radius); overflow: hidden; img { diff --git a/react/assets/forus-platform/scss/_common/blocks/block-sessions.scss b/react/assets/forus-platform/scss/_common/blocks/block-sessions.scss index bcb83fd59..dcf3e0559 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-sessions.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-sessions.scss @@ -122,7 +122,7 @@ display: block; width: 3px; height: 3px; - border-radius: 3px; + border-radius: var(--border-radius); position: absolute; left: 0; top: 50%; diff --git a/react/assets/forus-platform/scss/_common/blocks/block-subsidy-product-overview.scss b/react/assets/forus-platform/scss/_common/blocks/block-subsidy-product-overview.scss index d968c1845..81c9b9717 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-subsidy-product-overview.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-subsidy-product-overview.scss @@ -2,7 +2,7 @@ display: flex; flex-direction: row; background: #ffffff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 2px 8px rgba(#000, 0.1); margin: 0 0 30px; overflow: hidden; diff --git a/react/assets/forus-platform/scss/_common/blocks/block-voucher-records-editor.scss b/react/assets/forus-platform/scss/_common/blocks/block-voucher-records-editor.scss index 17e5fcc19..5c529f50a 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-voucher-records-editor.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-voucher-records-editor.scss @@ -1,6 +1,6 @@ &.block-voucher-records-editor { .block-voucher-record-list { - border-radius: 5px; + border-radius: var(--border-radius); border: 1px dashed var(--border-color); padding: 15px; margin-bottom: 20px; diff --git a/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature-text-image-columns.scss b/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature-text-image-columns.scss index c26477112..71dcb52be 100644 --- a/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature-text-image-columns.scss +++ b/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature-text-image-columns.scss @@ -59,7 +59,7 @@ display: block; width: 5px; height: 100%; - border-radius: 3px; + border-radius: var(--border-radius); background: linear-gradient(0deg, #7db75a 0%, #7db75a 100%), #e6eeaf; position: absolute; top: 0; diff --git a/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature.scss b/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature.scss index c5d9f23df..0793c72ee 100644 --- a/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature.scss +++ b/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-feature.scss @@ -44,7 +44,7 @@ .block-feature-label { font: 600 11px/14px var(--base-font); padding: 2px 4px; - border-radius: 4px; + border-radius: var(--border-radius); border: 1px solid #dadfe5; background: #ebeef1; color: #151b26; diff --git a/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-features.scss b/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-features.scss index 9d5f6cf0a..35ae4d59c 100644 --- a/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-features.scss +++ b/react/assets/forus-platform/scss/_common/blocks/marketplace-features/block-features.scss @@ -27,7 +27,7 @@ .features-label { font: 600 11px/14px var(--base-font); padding: 2px 4px; - border-radius: 4px; + border-radius: var(--border-radius); border: 1px solid #dadfe5; background: #ebeef1; color: #151b26; diff --git a/react/assets/forus-platform/scss/_common/components/buttons.scss b/react/assets/forus-platform/scss/_common/components/buttons.scss index 80a8c673f..e91ed63c8 100644 --- a/react/assets/forus-platform/scss/_common/components/buttons.scss +++ b/react/assets/forus-platform/scss/_common/components/buttons.scss @@ -1,7 +1,7 @@ .button { display: inline-flex; width: fit-content; - border-radius: 3px; + border-radius: var(--border-radius); font: 500 13px/20px var(--base-font); padding: 7px 10px; box-shadow: var(--box-shadow); diff --git a/react/assets/forus-platform/scss/_common/components/forms.scss b/react/assets/forus-platform/scss/_common/components/forms.scss index dd88430c1..ee0016d79 100644 --- a/react/assets/forus-platform/scss/_common/components/forms.scss +++ b/react/assets/forus-platform/scss/_common/components/forms.scss @@ -1,20 +1,4 @@ .form { - datepicker, - .datepicker { - border: none; - outline: none; - position: relative; - - .form-control { - position: absolute; - left: -1px; - top: -1px; - right: -1px; - bottom: -1px; - width: calc(100% + 2px) !important; - } - } - .form-label { display: block; cursor: default; @@ -224,7 +208,7 @@ color: var(--text-color); font: 500 13px/24px var(--base-font); transition: background-color 0.4s ease, border 0.4s ease; - border-radius: 3px; + border-radius: var(--border-radius); appearance: none; &[disabled] { @@ -387,7 +371,7 @@ height: 36px; color: var(--text-color); font: 600 16px/24px var(--base-font); - border-radius: 3px; + border-radius: var(--border-radius); &.form-value-placeholder-sm { padding: 0 0; @@ -467,132 +451,6 @@ } } - &.form-group-inline { - margin-bottom: 10px; - flex-wrap: wrap; - position: relative; - - .block-form_tooltip { - position: absolute; - top: 20px; - right: -45px; - transform: translate(0, -50%); - z-index: 5; - } - - & > .form-label { - width: 200px; - padding-top: 8px; - padding-bottom: 8px; - margin: 0; - text-align: right; - padding-right: 10px; - float: left; - color: black; - - &.form-label-required { - &:before { - content: '*'; - padding-right: 2px; - display: inline-block; - margin-left: -8px; - width: 8px; - } - - &:after { - display: none; - } - } - } - - & > .form-offset, - & > .form-control, - & > .react-datepicker-wrapper { - width: calc(100% - 200px); - float: left; - - .form-toggle { - padding: 8px 0; - } - } - - & > .form-error { - margin-left: 200px; - width: calc(100% - 200px); - float: left; - } - - & > .form-title { - padding: 8px 0; - width: calc(100% - 200px); - float: left; - } - - &.form-group-inline-xl { - & > .form-label { - width: 250px; - } - - & > .form-offset, - & > .form-control { - width: calc(100% - 250px); - } - - & > .form-error { - margin-left: 250px; - width: calc(100% - 250px); - } - } - - &.form-group-inline-lg { - & > .form-label { - width: 145px; - } - - & > .form-offset, - & > .form-control { - width: calc(100% - 145px); - } - - & > .form-error { - margin-left: 145px; - width: calc(100% - 145px); - } - } - - &.form-group-inline-md { - & > .form-label { - width: 125px; - } - - & > .form-offset, - & > .form-control { - width: calc(100% - 125px); - } - - & > .form-error { - margin-left: 125px; - width: calc(100% - 125px); - } - } - - &.form-group-inline-sm { - & > .form-label { - width: 80px; - } - - & > .form-offset, - & > .form-control { - width: calc(100% - 80px); - } - - & > .form-error { - margin-left: 80px; - width: calc(100% - 80px); - } - } - } - &:last-child, &.form-group-last { margin-bottom: 0 !important; @@ -601,7 +459,7 @@ .control-frame { border: 1px solid #eef1f5; - border-radius: 5px; + border-radius: var(--border-radius); padding: 10px 15px 10px; margin: 5px 0 10px; font: 400 14px var(--base-font); @@ -899,6 +757,7 @@ .select-control { width: var(--selector-width); position: absolute; + z-index: 2; .select-control-input { .form-control:not([type='radio']):not([type='checkbox']) { @@ -959,7 +818,7 @@ margin-right: 5px; margin-left: -25px; float: left; - border-radius: 3px; + border-radius: var(--border-radius); .mdi { color: #262626; @@ -1125,7 +984,7 @@ color: #9ca6af; background: #f6f9fc; border: 1px dashed #d4d9dd; - border-radius: 3px; + border-radius: var(--border-radius); word-wrap: break-word; white-space: pre-wrap; } @@ -1136,24 +995,4 @@ font: 600 14px/20px var(--base-font); color: #151b26; } - - @media screen and (max-width: 600px) { - .form-group { - &.form-group-inline { - .form-label { - width: auto !important; - padding: 3px 0 !important; - - &.form-label-required { - padding-left: 5px !important; - } - } - - .form-offset, - .form-control { - width: 100% !important; - } - } - } - } } diff --git a/react/assets/forus-platform/scss/_common/components/labels.scss b/react/assets/forus-platform/scss/_common/components/labels.scss index 4bc4f2668..45377d5bc 100644 --- a/react/assets/forus-platform/scss/_common/components/labels.scss +++ b/react/assets/forus-platform/scss/_common/components/labels.scss @@ -5,12 +5,13 @@ border-radius: calc(var(--border-radius)); cursor: default; white-space: nowrap; + align-items: center; .mdi { font-size: 1.5em; float: right; color: inherit; - line-height: 24px; + line-height: 20px; &.icon-start { margin-left: -5px; @@ -61,6 +62,11 @@ color: #fff; } + &.label-text { + color: #8ca3a6; + background-color: transparent; + } + &.label-primary { background: var(--color-primary); color: #fff; @@ -71,46 +77,7 @@ color: var(--color-primary); } - &.label-primary-variant { - background: var(--color-primary-light); - color: #fff; - } - - &.label-sm { - padding: 0 5px; - line-height: 18px; - font-size: 10px; - font-weight: 700; - } - - &.label-lg { - padding: 4px 10px; - line-height: 18px; - font-size: 11px; - font-weight: 700; - } - - &.label-round { - border-radius: 30px; - } - - &.label-tag { - font: 600 12px/25px var(--base-font); - padding: 0 10px; - } - &:not(:last-child):not(:last-of-type) { margin: 0 5px 5px 0; } - - &[ng-click] { - cursor: pointer; - } -} - -@media screen and (max-width: 1000px) { - .label { - padding: 0 10px; - font: 700 11px/22px var(--base-font); - } } diff --git a/react/assets/forus-platform/scss/_common/components/modals.scss b/react/assets/forus-platform/scss/_common/components/modals.scss index 32ce9200f..138b327da 100644 --- a/react/assets/forus-platform/scss/_common/components/modals.scss +++ b/react/assets/forus-platform/scss/_common/components/modals.scss @@ -447,7 +447,7 @@ border: 1px solid #eff6f8; background: #fff; padding: 10px 80px; - border-radius: 5px; + border-radius: var(--border-radius); font: 400 22px/34px var(--base-font); color: #646f79; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05); @@ -864,7 +864,7 @@ .modal-warning { border: 1px dashed #d4d9dd; - border-radius: 3px; + border-radius: var(--border-radius); padding: 15px 13px; margin-top: 20px; background-color: #f6f9fc; @@ -949,7 +949,7 @@ margin-bottom: 15px; .icon { - border-radius: 5px; + border-radius: var(--border-radius); border: 1px solid #d4d9dd; background: #fff; display: flex; @@ -987,7 +987,7 @@ flex-basis: 0; flex-grow: 1; max-width: 100%; - border-radius: 5px; + border-radius: var(--border-radius); border: 1px dashed #d4d9dd; background: #fff; padding: 20px; diff --git a/react/assets/forus-platform/scss/_common/components/tables.scss b/react/assets/forus-platform/scss/_common/components/tables.scss index 18e18b5c1..e33c0b602 100644 --- a/react/assets/forus-platform/scss/_common/components/tables.scss +++ b/react/assets/forus-platform/scss/_common/components/tables.scss @@ -403,12 +403,12 @@ &.td-media-sm { width: 30px; - border-radius: 4px; + border-radius: var(--border-radius); } &.td-media-md { width: 40px; - border-radius: 4px; + border-radius: var(--border-radius); } &.td-media-round { diff --git a/react/assets/forus-platform/scss/_common/components/tags.scss b/react/assets/forus-platform/scss/_common/components/tags.scss deleted file mode 100644 index 26b7365bd..000000000 --- a/react/assets/forus-platform/scss/_common/components/tags.scss +++ /dev/null @@ -1,79 +0,0 @@ -.tag { - border-radius: 20px; - color: #fff; - font: 600 12px/25px var(--base-font); - padding: 0 10px; - display: inline-flex; - margin-bottom: 10px; - cursor: default; - - .mdi { - font-size: 1.5em; - float: right; - color: inherit; - line-height: 24px; - - &.icon-start { - margin-left: -5px; - margin-right: 5px; - } - - &.icon-end { - margin-left: 5px; - margin-right: -5px; - } - } - - .tag-link { - cursor: pointer; - } - - &.tag-primary { - background: var(--color-primary); - } - - &.tag-primary-light { - background: var(--color-primary-light); - } - - &.tag-success { - background: #2cc6ab; - } - - &.tag-danger { - background: #e63b3b; - } - - &.tag-warning { - background: #ff9b00; - } - - &.tag-default { - background: #8ca3a6; - } - - &.tag-text { - color: #8ca3a6; - background-color: transparent; - } - - &.tag-sm { - line-height: 20px; - padding: 0 7.5px; - font-size: 11px; - } - - &.tag-square { - border-radius: 2px; - } - - &:first-child, - &:last-child { - margin-bottom: 0; - } - - &:not(:last-of-type), - &:not(:last-child) { - margin-right: 10px; - } -} diff --git a/react/assets/forus-platform/scss/_common/dashboard.scss b/react/assets/forus-platform/scss/_common/dashboard.scss index 84a55f005..acd627981 100644 --- a/react/assets/forus-platform/scss/_common/dashboard.scss +++ b/react/assets/forus-platform/scss/_common/dashboard.scss @@ -14,7 +14,6 @@ @import 'includes/printables'; // components -@import 'components/tags'; @import 'components/forms'; @import 'components/tables'; @import 'components/buttons'; @@ -150,7 +149,7 @@ body { max-width: 80vw; width: 240px; border: 1px solid #f3f4f5; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 5px 25px rgba(#000, 0.15); padding: 5px 20px; @include cf(); @@ -309,7 +308,7 @@ body { .notifications-menu-inner { background: #ffffff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 10px 25px rgba(#000, 0.15); position: relative; @@ -509,7 +508,7 @@ body { top: 60px; border: 1px solid #f3f4f5; background: #fff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 5px 30px rgba(#000, 0.1); min-width: 220px; max-width: 80%; @@ -648,7 +647,7 @@ body { display: flex; flex-direction: row; align-items: flex-start; - border-radius: 3px; + border-radius: var(--border-radius); transition: background-color 0.4s; gap: 6px; @@ -749,7 +748,7 @@ body { &.sidebar-nav-group-active { & > .sidebar-nav-group-header { background: #134478; - border-radius: 3px; + border-radius: var(--border-radius); .sidebar-nav-group-header-icon { .sidebar-nav-group-header-icon-default { @@ -957,11 +956,6 @@ body { } } - .form-group-inline > .form-label { - padding-top: 5px; - padding-bottom: 5px; - } - .block-label-tabs { .label-tab { height: 30px; @@ -1980,7 +1974,7 @@ body { .download-link { border: 1px dashed #d2e6ff; - border-radius: 5px; + border-radius: var(--border-radius); position: relative; display: block; margin-bottom: 25px; @@ -2047,7 +2041,7 @@ body { .download-url { border: 1px dashed #d2e6ff; - border-radius: 5px; + border-radius: var(--border-radius); padding: 13px; width: 320px; margin: 0 auto 25px; @@ -2064,7 +2058,7 @@ body { .download-confirmation { border: 1px dashed #d2e6ff; margin-bottom: 20px; - border-radius: 5px; + border-radius: var(--border-radius); padding: 13px; display: block; cursor: pointer; @@ -2351,7 +2345,7 @@ body { &.card-block-requests { box-shadow: 0 2px 5px rgba(25, 39, 52, 0.11); - border-radius: 4px; + border-radius: var(--border-radius); margin: 20px 0; color: #646f79; background-color: #fff; @@ -2509,7 +2503,7 @@ body { padding: 15px; background: #fff; z-index: 5; - border-radius: 4px; + border-radius: var(--border-radius); font: 500 13px/20px var(--base-font); text-transform: none; color: #45535e; @@ -3091,7 +3085,7 @@ body { box-shadow: none; margin-bottom: 15px; border: 1px solid #e5e6ec; - border-radius: 5px; + border-radius: var(--border-radius); .card-section { background: #fff; @@ -3838,7 +3832,7 @@ body { font: 400 11px/16px var(--base-font); border: 1px dashed #d4d9dd; padding: 17.5px; - border-radius: 5px; + border-radius: var(--border-radius); &.block-info-primary { background-color: #f7f9fc; @@ -3991,7 +3985,7 @@ body { border: 1px solid #d4d9dd; flex-direction: row; padding: 5px 15px; - border-radius: 5px; + border-radius: var(--border-radius); float: left; margin-bottom: 10px; @@ -4454,7 +4448,7 @@ body { position: relative; .card-section-fund { - border-radius: 5px; + border-radius: var(--border-radius); background: #fff; margin-bottom: 12.5px; box-shadow: 0 5px 10px rgba($color: #000000, $alpha: 0.05); @@ -4583,7 +4577,7 @@ body { &:not(.line-item) { width: 100%; border: 2px dashed #d2e6ff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 5px 35px rgba(0, 0, 0, 0.1); position: relative; z-index: 1; @@ -4712,7 +4706,7 @@ body { margin: 0 0 20px; height: 5px; background: #d2e6ff; - border-radius: 5px; + border-radius: var(--border-radius); width: 100%; position: relative; @@ -4722,7 +4716,7 @@ body { top: -1px; bottom: -1px; background: #009ef4; - border-radius: 5px; + border-radius: var(--border-radius); transition: 1s; } } @@ -4795,7 +4789,7 @@ body { padding: 15px 10px 10px; display: block; background: #fff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 5px 10px rgba($color: #000000, $alpha: 0.1); transform: translate(0, 0); transition: 0.4s; @@ -4969,7 +4963,7 @@ body { &.block-file { width: 100%; border: 1px dashed #d4d9dd; - border-radius: 4px; + border-radius: var(--border-radius); text-align: left; cursor: default; display: flex; @@ -5115,23 +5109,6 @@ body { &:last-child { margin-right: 0; } - - &.form-group-inline { - flex-direction: row; - - .form-label { - line-height: 14px; - padding-right: 10px; - color: var(--color-primary); - width: auto; - } - - & > .form-offset, - & > .form-control, - & > .form-control { - width: auto; - } - } } .form-control { @@ -5328,7 +5305,7 @@ body { &.block-information { background: #fff; padding: 15px 20px; - border-radius: 4px; + border-radius: var(--border-radius); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); font: 400 13px/20px var(--base-font); margin-bottom: 15px; @@ -5396,7 +5373,7 @@ body { &:not(.line-item) { width: 220px; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 5px 35px rgba(0, 0, 0, 0.1); position: relative; z-index: 1; @@ -5974,7 +5951,7 @@ body { button { background: rgba(53, 97, 255, 0.15); - border-radius: 5px; + border-radius: var(--border-radius); font: 500 14px/25px var(--base-font); color: #3561ff; margin: 0 auto; @@ -6484,7 +6461,7 @@ body { display: block; width: 4px; height: 4px; - border-radius: 5px; + border-radius: var(--border-radius); background: var(--color-primary-light); left: 0; top: 50%; @@ -6657,7 +6634,7 @@ body { font: 700 14px/30px var(--base-font); padding: 10px 65px; text-align: center; - border-radius: 5px; + border-radius: var(--border-radius); &.button-primary { background: #305dfb; @@ -6703,23 +6680,6 @@ body { .form-group { margin-bottom: 15px; - - &.form-group-inline { - & > .form-label { - width: auto; - float: none; - text-align: left; - padding: 0; - } - - & > .form-control, - & > .form-offset, - & > .form-error { - float: none; - width: 100%; - margin: 0; - } - } } } @@ -6740,7 +6700,7 @@ body { &.block-office-edit-card { background: #fff; border: 1px solid #d2e6ff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 2px 5px 5px rgba($color: #000000, $alpha: 0.05); margin-bottom: 25px; @@ -6896,7 +6856,7 @@ body { .button { background-color: #e1e8ff; - border-radius: 5px; + border-radius: var(--border-radius); } } } diff --git a/react/assets/forus-platform/scss/_common/includes/printables.scss b/react/assets/forus-platform/scss/_common/includes/printables.scss index a7e9bf71c..78f6ca61e 100644 --- a/react/assets/forus-platform/scss/_common/includes/printables.scss +++ b/react/assets/forus-platform/scss/_common/includes/printables.scss @@ -105,7 +105,7 @@ body { .printable-organization-info { background: #f5f5f5; - border-radius: 5px; + border-radius: var(--border-radius); padding: 20px; margin-left: 70px; margin-right: 70px; diff --git a/react/assets/forus-platform/scss/_common/includes/third-party.scss b/react/assets/forus-platform/scss/_common/includes/third-party.scss index 5f70b07c0..f953c3b4c 100644 --- a/react/assets/forus-platform/scss/_common/includes/third-party.scss +++ b/react/assets/forus-platform/scss/_common/includes/third-party.scss @@ -1,175 +1,3 @@ -/*========== Style Sheet - Third-party ==========*/ -.nano { - position: relative; - width: 100%; - height: 100%; - overflow: hidden; -} -.nano > .nano-content { - position: absolute; - overflow: scroll; - overflow-x: hidden; - top: 0; - right: 0; - bottom: 0; - left: 0; -} -.nano > .nano-content:focus { - outline: thin dotted; -} -.nano > .nano-content::-webkit-scrollbar { - display: none; -} -.has-scrollbar > .nano-content::-webkit-scrollbar { - display: block; -} -.nano > .nano-pane { - position: absolute; - width: 6px; - right: 6px; - top: 3px; - bottom: 3px; - cursor: pointer; - background-color: #eee; - opacity: 0.5; - transition: all 0.4s; -} -.nano > .nano-pane > .nano-slider { - background: #009ef4; - position: relative; - margin: 0 2px; -} -.nano:hover > .nano-pane, -.nano-pane.active, -.nano-pane.flashed { - opacity: 1; -} - -[ng\:cloak], -[ng-cloak], -[data-ng-cloak], -[x-ng-cloak], -.ng-cloak, -.x-ng-cloak { - display: none !important; -} - -._720kb { - &-datepicker { - &-calendar { - max-width: 275px; - border: 1px solid #e9ecee; - border-radius: 5px; - box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.1); - - &-days-header { - background: #fff; - border-bottom: 0; - padding: 0 5px; - - div { - color: #134478; - font-size: 12px; - } - } - - &-body { - display: flex; - flex-direction: row; - align-content: center; - flex-wrap: wrap; - padding: 0 5px 5px; - margin: 0; - width: 100%; - } - - &-day { - width: calc(100% / 7); - padding: 0; - font-size: 13px; - font-weight: 500; - color: #282b39; - border-radius: 40px; - margin: 0; - height: 35px; - line-height: 35px; - position: relative; - z-index: 1; - transition: color 0.4s; - - &:before { - content: ''; - display: block; - width: 28px; - height: 28px; - margin: 0; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - z-index: -1; - border-radius: 20px; - transition: background 0.4s; - } - - &:hover { - background: transparent; - - &:before { - background: rgba(0, 0, 0, 0.03); - } - } - - &._720kb-datepicker-active { - color: #fff; - background: transparent; - - &:before { - background: #009ef4; - } - } - - &._720kb-datepicker-disabled { - color: rgba(0, 0, 0, 0.2); - background: transparent; - - &:before { - background: rgba(25, 2, 0, 0.02); - } - } - } - - &-header { - &:nth-child(odd), - &:nth-child(even) { - background: #fff; - border-bottom: 1px solid #e9ecee; - } - } - - &-month { - color: #282b39; - font: 500 13px/40px var(--base-font); - - a { - & > span { - color: #282b39; - font: 500 13px/40px var(--base-font); - } - } - } - } - } -} - -datepicker[input-visible='true'] { - ._720kb-datepicker-calendar { - top: 100%; - margin-top: 1px; - left: 0; - } -} - .react-datepicker-wrapper { width: 100%; } diff --git a/react/assets/forus-platform/scss/_common/landing.scss b/react/assets/forus-platform/scss/_common/landing.scss index 4dfb869c2..dc7cd6d6a 100644 --- a/react/assets/forus-platform/scss/_common/landing.scss +++ b/react/assets/forus-platform/scss/_common/landing.scss @@ -149,43 +149,6 @@ .form-group { margin-bottom: 10px; @include cf(); - - &.form-group-inline { - margin-bottom: 10px; - // display: flex; - flex-wrap: wrap; - - & > .form-label { - // flex: 0 0 28%; - // max-width: 28%; - width: 200px; - padding-top: 8px; - padding-bottom: 8px; - margin: 0; - text-align: right; - padding-right: 15px; - float: left; - } - - & > .form-offset, - & > .form-control { - // flex: 0 0 72%; - // max-width: 72%; - width: calc(100% - 200px); - float: left; - } - - & > .form-error { - margin-left: 200px; - width: calc(100% - 200px); - float: left; - } - - &:last-child, - &:last-of-type { - margin-bottom: 0; - } - } } .checkbox { @@ -734,7 +697,7 @@ /*display: block; background: #fff; box-shadow: 0 0 30px rgba(#000, .15); - border-radius: 5px; + border-radius: var(--border-radius); padding: 10px; padding-right: 65px; position: relative; @@ -1253,7 +1216,7 @@ &:not(.line-item) { width: 100%; border: 2px dashed #d2e6ff; - border-radius: 5px; + border-radius: var(--border-radius); box-shadow: 0 5px 35px rgba(0, 0, 0, 0.1); position: relative; z-index: 1; diff --git a/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss b/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss index 02e646168..7063d80d0 100644 --- a/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss +++ b/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss @@ -2,7 +2,7 @@ --control-height: 50px; --control-line-height: 24px; --control-option-height: 36px; - --control-border-radius: 5px; + --control-border-radius: var(--border-radius); border-radius: var(--control-border-radius) !important; @@ -191,7 +191,7 @@ border: 1px solid #d4d9dd; border-top: 0; box-shadow: 0 12px 30px rgba(25, 39, 52, 0.18); - border-radius: 3px; + border-radius: var(--border-radius); .select-control-options { position: relative; diff --git a/react/assets/forus-webshop/scss/includes/components/_form.scss b/react/assets/forus-webshop/scss/includes/components/_form.scss index 79c7d809c..a0d773213 100644 --- a/react/assets/forus-webshop/scss/includes/components/_form.scss +++ b/react/assets/forus-webshop/scss/includes/components/_form.scss @@ -4,23 +4,6 @@ } .form { - datepicker, - .datepicker { - height: 50px; - border: none; - outline: none; - position: relative; - - .form-control { - position: absolute; - left: -1px; - top: -1px; - right: -1px; - bottom: -1px; - width: calc(100% + 2px) !important; - } - } - .form-error { font: 400 13px/20px var(--base-font); color: #ad0003; @@ -609,63 +592,6 @@ margin-bottom: 0; } - &.form-group-inline { - margin-bottom: 10px; - flex-wrap: wrap; - - & > .form-label { - width: 200px; - padding-top: 8px; - padding-bottom: 8px; - margin: 0; - text-align: right; - padding-right: 15px; - float: left; - } - - & > .form-offset, - & > .form-control { - width: calc(100% - 200px); - float: left; - } - - & > .form-error { - margin-left: 200px; - width: calc(100% - 200px); - float: left; - } - - &:last-child, - &:last-of-type { - margin-bottom: 0; - } - - @media screen and (max-width: 1000px) { - display: flex; - flex-direction: column; - - & > .form-label { - float: none; - width: auto; - float: none; - text-align: left; - padding: 0 0 0; - } - - & > .form-offset, - & > .form-control { - width: auto; - float: none; - } - - & > .form-error { - margin-left: 0; - width: auto; - float: none; - } - } - } - &.form-group-fit { width: fit-content; } @@ -683,139 +609,6 @@ } } - datepicker, - .datepicker { - border: none; - outline: none; - position: relative; - - .form-control { - position: absolute; - left: -1px; - top: -1px; - right: -1px; - bottom: -1px; - width: calc(100% + 2px) !important; - } - - ._720kb-datepicker-calendar { - max-width: 340px; - border: 1px solid #e9ecee; - border-radius: var(--border-radius); - box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.1); - top: calc(100% + 5px); - left: 0; - width: 100%; - min-width: 270px; - - &-days-header { - background: #fff; - border-bottom: 0; - padding: 0 5px; - - div { - color: #333333; - font-size: 12px; - } - } - - &-body { - display: flex; - flex-direction: row; - align-content: center; - flex-wrap: wrap; - padding: 0 5px 5px; - margin: 0; - width: 100%; - } - - &-day { - width: calc(100% / 7); - padding: 0; - font-size: 13px; - font-weight: 500; - color: #282b39; - border-radius: 40px; - margin: 0; - height: 38px; - line-height: 38px; - position: relative; - z-index: 1; - transition: color 0.4s; - - &:before { - content: ''; - display: block; - width: 28px; - height: 28px; - margin: 0; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - z-index: -1; - border-radius: 20px; - transition: background 0.4s; - } - - &:hover { - background: transparent; - - &:before { - background: rgba(0, 0, 0, 0.03); - } - } - - &._720kb-datepicker-active { - color: #fff; - background: transparent; - - &:before { - background: var(--color-primary); - } - } - - &._720kb-datepicker-disabled { - color: rgba(0, 0, 0, 0.2); - background: transparent; - - &:before { - background: none; - } - } - } - - &-header { - &:nth-child(odd), - &:nth-child(even) { - background: #fff; - border-bottom: 1px solid #e9ecee; - } - - &:not(.ng-hide):nth-child(2) { - margin-bottom: -10px; - - & ~ ._720kb-datepicker-calendar-body, - & ~ ._720kb-datepicker-calendar-days-header { - display: none; - } - } - } - - &-month { - color: #282b39; - font: 500 13px/40px var(--base-font); - - a { - & > span { - color: #282b39; - font: 500 13px/40px var(--base-font); - } - } - } - } - } - .checkbox { display: inline-block; padding: 5px 15px 0 20px; @@ -1262,11 +1055,6 @@ margin: 0 0 5px; } - datepicker, - .datepicker { - height: 42px; - } - .ui-control .ui-control-clear { right: 10px; diff --git a/react/assets/forus-webshop/scss/includes/components/_label.scss b/react/assets/forus-webshop/scss/includes/components/_label.scss index a5733aa0a..2070c0bea 100644 --- a/react/assets/forus-webshop/scss/includes/components/_label.scss +++ b/react/assets/forus-webshop/scss/includes/components/_label.scss @@ -95,10 +95,6 @@ font-weight: 700; } - &.label-lg { - padding: 2px 10px; - } - &.label-xl { padding: 5px 10px; } @@ -124,9 +120,5 @@ &:not(.label-round) { border-radius: calc(var(--border-radius) / 2); } - - &.label-lg { - padding: 0 10px; - } } } \ No newline at end of file diff --git a/react/assets/forus-webshop/scss/includes/components/table.scss b/react/assets/forus-webshop/scss/includes/components/table.scss index 7c1711ec7..f09225264 100644 --- a/react/assets/forus-webshop/scss/includes/components/table.scss +++ b/react/assets/forus-webshop/scss/includes/components/table.scss @@ -105,13 +105,6 @@ table.table { } } - &[ng-click]:hover { - td, - th { - background: #f6f8f9; - } - } - &:last-child { td { border-bottom: none; diff --git a/react/assets/forus-webshop/scss/includes/includes/shame.scss b/react/assets/forus-webshop/scss/includes/includes/shame.scss index bec67bdbf..6c397ad5a 100644 --- a/react/assets/forus-webshop/scss/includes/includes/shame.scss +++ b/react/assets/forus-webshop/scss/includes/includes/shame.scss @@ -53,8 +53,6 @@ html { } } -[ng-click], -[ui-sref], .clickable, .state-nav-link { cursor: pointer; diff --git a/react/assets/forus-webshop/scss/includes/includes/third-party.scss b/react/assets/forus-webshop/scss/includes/includes/third-party.scss index c2f542dff..80758c46d 100644 --- a/react/assets/forus-webshop/scss/includes/includes/third-party.scss +++ b/react/assets/forus-webshop/scss/includes/includes/third-party.scss @@ -55,48 +55,6 @@ bottom: 180px !important; } -.nano > .nano-content::-webkit-scrollbar { - display: none; -} - -.has-scrollbar > .nano-content::-webkit-scrollbar { - display: block; -} - -.nano > .nano-pane { - position: absolute; - width: 6px; - right: 6px; - top: 3px; - bottom: 3px; - cursor: pointer; - background-color: transparent; - opacity: 0.5; - transition: all .4s; -} - -.nano > .nano-pane > .nano-slider { - background: #d4d9dd; - position: relative; - margin: 0 0px; - border-radius: 8px; -} - -.nano:hover > .nano-pane, -.nano-pane.active, -.nano-pane.flashed { - opacity: 1; -} - -[ng\:cloak], -[ng-cloak], -[data-ng-cloak], -[x-ng-cloak], -.ng-cloak, -.x-ng-cloak { - display: none !important; -} - .gm-style .gm-style-mtc label, .gm-style .gm-style-mtc div { font-weight: 400; @@ -388,114 +346,6 @@ // read speaker skip class, added for referencing } -._720kb { - &-datepicker { - &-calendar { - max-width: 275px; - border: 1px solid #e9ecee; - border-radius: 5px; - box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.1); - - &-days-header { - background: #fff; - border-bottom: 0; - padding: 0 5px; - - div { - color: #134478; - font-size: 12px; - } - } - - &-body { - display: flex; - flex-direction: row; - align-content: center; - flex-wrap: wrap; - padding: 0 5px 5px; - margin: 0; - width: 100%; - } - - &-day { - width: calc(100% / 7); - padding: 0; - font-size: 13px; - font-weight: 500; - color: #282b39; - border-radius: 40px; - margin: 0; - height: 35px; - line-height: 35px; - position: relative; - z-index: 1; - transition: color .4s; - - &:before { - content: ''; - display: block; - width: 28px; - height: 28px; - margin: 0; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - z-index: -1; - border-radius: 20px; - transition: background .4s; - } - - &:hover { - background: transparent; - - &:before { - background: rgba(0, 0, 0, 0.03); - } - } - - &._720kb-datepicker-active { - color: #fff; - background: transparent; - - &:before { - background: #009ef4; - } - } - - &._720kb-datepicker-disabled { - color: rgba(0, 0, 0, 0.2); - background: transparent; - - &:before { - background: rgba(25, 2, 0, 0.02); - } - } - } - - &-header { - &:nth-child(odd), - &:nth-child(even) { - background: #fff; - border-bottom: 1px solid #e9ecee; - } - } - - &-month { - color: #282b39; - font: 500 13px/40px var(--base-font); - - a { - & > span { - color: #282b39; - font: 500 13px/40px var(--base-font); - } - } - } - } - } -} - @media print { .gm-style .gmnoprint, .gmnoprint { diff --git a/react/src/dashboard/components/elements/forms/controls/FormGroup.tsx b/react/src/dashboard/components/elements/forms/controls/FormGroup.tsx index a81656d51..d49b1c27d 100644 --- a/react/src/dashboard/components/elements/forms/controls/FormGroup.tsx +++ b/react/src/dashboard/components/elements/forms/controls/FormGroup.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useState } from 'react'; +import React, { useState } from 'react'; import FormError from '../errors/FormError'; import { uniqueId } from 'lodash'; import classNames from 'classnames'; @@ -6,8 +6,6 @@ import classNames from 'classnames'; export default function FormGroup({ id, error, - inline, - inlineSize, label, input, required, @@ -15,8 +13,6 @@ export default function FormGroup({ }: { id?: string; error?: string | Array; - inline?: boolean; - inlineSize?: 'sm' | 'md' | 'lg' | 'xl'; label?: string | React.ReactElement | Array; input?: (input_id: string) => React.ReactElement; required?: boolean; @@ -25,34 +21,15 @@ export default function FormGroup({ const input_id = useState(id || uniqueId('input_group_id_'))[0]; return ( -
+
{label && ( )} - {inline ? ( -
- {input && input(input_id)} - {error && } -
- ) : ( - - {input && input(input_id)} - {error && } - - )} + {input && input(input_id)} + {error && }
); } diff --git a/react/src/dashboard/components/elements/forms/controls/MultiSelectControl.tsx b/react/src/dashboard/components/elements/forms/controls/MultiSelectControl.tsx index 676a9c6c9..087ec0b6a 100644 --- a/react/src/dashboard/components/elements/forms/controls/MultiSelectControl.tsx +++ b/react/src/dashboard/components/elements/forms/controls/MultiSelectControl.tsx @@ -1,6 +1,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { uniq, uniqueId } from 'lodash'; import SelectControl from '../../select-control/SelectControl'; +import Label from '../../image_cropper/Label'; export default function MultiSelectControl({ id = uniqueId('multiselect_'), @@ -57,26 +58,23 @@ export default function MultiSelectControl({ return (
-
+
-
- -
+
{value?.length > 0 && ( -
+
-
- {value?.map((id) => ( -
- {optionsById?.[id.toString()] || ''} -
removeItem(id)} /> -
- ))} -
+ + {value?.map((id) => ( +
diff --git a/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx b/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx index 1c80be134..50705cb45 100644 --- a/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx +++ b/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx @@ -297,37 +297,33 @@ export default function FundCriteriaEditorItem({
-
- -
+
{recordType?.operators?.length > 0 && operators && (
-
- { - setOperators({ ...operators, [recordType.key]: operator }); - }} - /> -
+ { + setOperators({ ...operators, [recordType.key]: operator }); + }} + />
)} @@ -354,21 +350,19 @@ export default function FundCriteriaEditorItem({ {['select', 'select_number', 'bool'].includes(recordType.type) && operators[recordType.key] != '*' && ( -
- { - values[recordType.key] = value; - setValues({ ...values }); - }} - /> -
+ { + values[recordType.key] = value; + setValues({ ...values }); + }} + /> )} {['date'].includes(recordType.type) && operators[recordType.key] != '*' && ( diff --git a/react/src/dashboard/components/elements/image_cropper/Label.tsx b/react/src/dashboard/components/elements/image_cropper/Label.tsx new file mode 100644 index 000000000..2d6ef29bf --- /dev/null +++ b/react/src/dashboard/components/elements/image_cropper/Label.tsx @@ -0,0 +1,46 @@ +import React, { ReactNode } from 'react'; +import classNames from 'classnames'; + +export type LabelType = + | 'success' + | 'warning' + | 'danger' + | 'default' + | 'text' + | 'primary' + | 'danger_light' + | 'primary_light'; + +export default function Label({ + children, + type, + dusk, + className, + disabled = false, +}: { + children: ReactNode | ReactNode[]; + type: LabelType; + dusk?: string; + className?: string; + disabled?: boolean; +}) { + return ( +
+ {children} +
+ ); +} diff --git a/react/src/dashboard/components/elements/resource-states/FundFormStateLabels.tsx b/react/src/dashboard/components/elements/resource-states/FundFormStateLabels.tsx index e8767d18b..30f369a65 100644 --- a/react/src/dashboard/components/elements/resource-states/FundFormStateLabels.tsx +++ b/react/src/dashboard/components/elements/resource-states/FundFormStateLabels.tsx @@ -1,20 +1,16 @@ -import React, { Fragment, useState } from 'react'; +import React from 'react'; import TableEmptyValue from '../table-empty-value/TableEmptyValue'; import FundForm from '../../../props/models/FundForm'; +import Label from '../image_cropper/Label'; export default function FundFormStateLabels({ fundForm }: { fundForm: FundForm }) { - const [stateLabels] = useState({ - active: 'tag-success', - archived: 'tag-default', - }); + if (fundForm.state == 'active') { + return ; + } - return ( - - {stateLabels[fundForm.state] ? ( - {fundForm.state_locale} - ) : ( - - )} - - ); + if (fundForm.state == 'archived') { + return ; + } + + return ; } diff --git a/react/src/dashboard/components/elements/resource-states/FundRequestStateLabel.tsx b/react/src/dashboard/components/elements/resource-states/FundRequestStateLabel.tsx index e9a21f32f..29009029b 100644 --- a/react/src/dashboard/components/elements/resource-states/FundRequestStateLabel.tsx +++ b/react/src/dashboard/components/elements/resource-states/FundRequestStateLabel.tsx @@ -2,6 +2,7 @@ import React, { Fragment, useCallback, useMemo, useState } from 'react'; import classNames from 'classnames'; import FundRequest from '../../../props/models/FundRequest'; import FundRequestClarification from '../../../props/models/FundRequestClarification'; +import Label from '../image_cropper/Label'; export default function FundRequestStateLabel({ fundRequest }: { fundRequest: FundRequest }) { const [stateLabels] = useState({ @@ -45,13 +46,7 @@ export default function FundRequestStateLabel({ fundRequest }: { fundRequest: Fu {fundRequest.state == 'pending' && fundRequest.employee ? ( {hasRecordsWithPendingClarifications ? ( -
+
) : ( -
+
+ )} ) : ( -
+
{localState.label}
diff --git a/react/src/dashboard/components/elements/resource-states/FundStateLabels.tsx b/react/src/dashboard/components/elements/resource-states/FundStateLabels.tsx index efcb8d039..10238d484 100644 --- a/react/src/dashboard/components/elements/resource-states/FundStateLabels.tsx +++ b/react/src/dashboard/components/elements/resource-states/FundStateLabels.tsx @@ -1,33 +1,27 @@ import Fund from '../../../props/models/Fund'; -import React, { Fragment, useState } from 'react'; +import React from 'react'; import TableEmptyValue from '../table-empty-value/TableEmptyValue'; import useTranslate from '../../../hooks/useTranslate'; +import Label from '../image_cropper/Label'; export default function FundStateLabels({ fund }: { fund: Fund }) { const translate = useTranslate(); - const [stateLabels] = useState({ - active: 'tag-success', - paused: 'tag-warning', - closed: 'tag-default', - waiting: 'tag-warning', - }); + if (fund.archived) { + return ; + } - return ( - - {!fund.archived && stateLabels[fund.state] ? ( - - {translate(`components.organization_funds.states.${fund.state}`)} - - ) : ( - - )} + if (fund.state === 'active') { + return ; + } - {fund.archived && ( - - {translate('components.organization_funds.states.archived')} - - )} - - ); + if (fund.state === 'paused' || fund.state === 'waiting') { + return ; + } + + if (fund.state === 'closed') { + return ; + } + + return ; } diff --git a/react/src/dashboard/components/elements/resource-states/ReimbursementStateLabel.tsx b/react/src/dashboard/components/elements/resource-states/ReimbursementStateLabel.tsx new file mode 100644 index 000000000..610596fae --- /dev/null +++ b/react/src/dashboard/components/elements/resource-states/ReimbursementStateLabel.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import Label from '../image_cropper/Label'; +import Reimbursement from '../../../props/models/Reimbursement'; + +export default function ReimbursementStateLabel({ + reimbursement, + dusk, +}: { + reimbursement: Reimbursement; + dusk?: string; +}) { + if (reimbursement.expired) { + return ( + + ); + } + + if (reimbursement.state === 'pending') { + return ( + + ); + } + + if (reimbursement.state === 'approved') { + return ( + + ); + } + + if (reimbursement.state === 'declined') { + return ( + + ); + } + + return null; +} diff --git a/react/src/dashboard/components/elements/resource-states/TransactionStateLabel.tsx b/react/src/dashboard/components/elements/resource-states/TransactionStateLabel.tsx index 8c9480099..e65562e14 100644 --- a/react/src/dashboard/components/elements/resource-states/TransactionStateLabel.tsx +++ b/react/src/dashboard/components/elements/resource-states/TransactionStateLabel.tsx @@ -1,12 +1,8 @@ import React from 'react'; import Transaction from '../../../props/models/Transaction'; import PayoutTransaction from '../../../props/models/PayoutTransaction'; -import classNames from 'classnames'; +import Label from '../image_cropper/Label'; export default function TransactionStateLabel({ transaction }: { transaction: Transaction | PayoutTransaction }) { - return ( -
- {transaction.state_locale} -
- ); + return ; } diff --git a/react/src/dashboard/components/elements/tables/elements/FilterItemToggle.tsx b/react/src/dashboard/components/elements/tables/elements/FilterItemToggle.tsx index 39cc59b9c..e249668e8 100644 --- a/react/src/dashboard/components/elements/tables/elements/FilterItemToggle.tsx +++ b/react/src/dashboard/components/elements/tables/elements/FilterItemToggle.tsx @@ -25,7 +25,7 @@ export default function FilterItemToggle({ -
{children}
+ {children}
); } diff --git a/react/src/dashboard/components/modals/Modal2FADeactivate.tsx b/react/src/dashboard/components/modals/Modal2FADeactivate.tsx index f0755a712..999ffec5e 100644 --- a/react/src/dashboard/components/modals/Modal2FADeactivate.tsx +++ b/react/src/dashboard/components/modals/Modal2FADeactivate.tsx @@ -165,19 +165,18 @@ export default function Modal2FADeactivate({ {type == 'authenticator' && (
Voer de 6-cijferige code in vanuit de app
)} -
- - -
+ + +
{type == 'phone' && ( diff --git a/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx b/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx index fc0910ad1..1e9f68dfb 100644 --- a/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx +++ b/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx @@ -299,16 +299,14 @@ export default function ModalCreatePrevalidation({
-
- { - formNewRecord.update({ record_type_key }); - }} - /> -
+ { + formNewRecord.update({ record_type_key }); + }} + />
diff --git a/react/src/dashboard/components/modals/ModalDuplicatesPicker.tsx b/react/src/dashboard/components/modals/ModalDuplicatesPicker.tsx index 6e02aae12..4b603275e 100644 --- a/react/src/dashboard/components/modals/ModalDuplicatesPicker.tsx +++ b/react/src/dashboard/components/modals/ModalDuplicatesPicker.tsx @@ -203,7 +203,7 @@ export default function ModalDuplicatesPicker({ {item.model ? labels.label_on : labels.label_off}
-
+
{ diff --git a/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx b/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx index 4bd9c1c2b..91b388faa 100644 --- a/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx +++ b/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx @@ -86,16 +86,14 @@ export default function ModalFundInviteProviders({ Nodig aanbieders uit van: -
- form.update({ fund_id })} - /> -
+ form.update({ fund_id })} + />
diff --git a/react/src/dashboard/components/modals/ModalFundOffers.tsx b/react/src/dashboard/components/modals/ModalFundOffers.tsx index 72c755a44..75d57c54e 100644 --- a/react/src/dashboard/components/modals/ModalFundOffers.tsx +++ b/react/src/dashboard/components/modals/ModalFundOffers.tsx @@ -14,6 +14,7 @@ import usePaginatorService from '../../modules/paginator/services/usePaginatorSe import useTranslate from '../../hooks/useTranslate'; import classNames from 'classnames'; import TableEmptyValue from '../elements/table-empty-value/TableEmptyValue'; +import Label from '../elements/image_cropper/Label'; type LocalProduct = Product & { allowed: boolean; @@ -185,14 +186,11 @@ export default function ModalFundOffers({ -
+
+ ))} diff --git a/react/src/dashboard/components/modals/ModalPayoutEdit.tsx b/react/src/dashboard/components/modals/ModalPayoutEdit.tsx index 99d1d0b39..7a624d29a 100644 --- a/react/src/dashboard/components/modals/ModalPayoutEdit.tsx +++ b/react/src/dashboard/components/modals/ModalPayoutEdit.tsx @@ -151,8 +151,6 @@ export default function ModalPayoutEdit({
( @@ -174,8 +172,6 @@ export default function ModalPayoutEdit({ /> ( @@ -193,8 +189,6 @@ export default function ModalPayoutEdit({ /> @@ -233,8 +227,6 @@ export default function ModalPayoutEdit({ {assignTypes.length > 0 && ( ( @@ -251,8 +243,6 @@ export default function ModalPayoutEdit({ {assignType?.hasInput && ( ( @@ -268,8 +258,6 @@ export default function ModalPayoutEdit({ )} ( @@ -285,8 +273,6 @@ export default function ModalPayoutEdit({ /> ( @@ -302,8 +288,6 @@ export default function ModalPayoutEdit({ /> (