diff --git a/frontend/src/assets/locales/en/translation.json b/frontend/src/assets/locales/en/translation.json index aafb5ce7..fafc0f04 100644 --- a/frontend/src/assets/locales/en/translation.json +++ b/frontend/src/assets/locales/en/translation.json @@ -1113,7 +1113,8 @@ "see_contract_details": "See contract details" }, "error": { - "empty_signature": "The signature is required" + "empty_signature": "The signature is required", + "error_signing": "An error occurred while signing the contract!" } }, "reject": { @@ -1312,4 +1313,4 @@ "clear": "Clear", "apply_all": "Apply to all" } -} +} \ No newline at end of file diff --git a/frontend/src/assets/locales/ro/translation.json b/frontend/src/assets/locales/ro/translation.json index a9cd2ba4..9b7c3af4 100644 --- a/frontend/src/assets/locales/ro/translation.json +++ b/frontend/src/assets/locales/ro/translation.json @@ -1119,7 +1119,8 @@ "see_contract_details": "Vezi detaliile contractului" }, "error": { - "empty_signature": "Semnătura este obligatorie" + "empty_signature": "Semnătura este obligatorie", + "error_signing": "A apărut o eroare la semnarea contractului!" } }, "reject": { @@ -1153,8 +1154,10 @@ "edit_title": "Editează template", "success_add": "Template-ul a fost adaugat!", "success_edit": "Template-ul a fost actualizat!", + "success_delete": "Template-ul a fost eliminat!", "error_add": "Eroare la adaugarea template-ului!", "error_edit": "Eroare la actualizarea template-ului!", + "error_delete": "Eroare la eliminarea template-ului!", "subheading": { "p1": "Acest template a fost realizat respectând normele din domeniu.", "p1_link": "Află mai multe", @@ -1179,6 +1182,11 @@ "download_all": "Descarcă toate" } }, + "delete_modal": { + "title": "Confirmă eliminarea template-ului", + "description": "Ești sigur că vrei să elimini template-ul?", + "confirm_btn_label": "Da, elimină" + }, "tooltip": "Datele contractului (Numărul, perioada contractului și data întemeierii) se completează în momentul atribuirii contractului către unul sau mai mulți voluntari.", "template_name": "Numele template-ului", "organization": { diff --git a/frontend/src/components/DocumentTemplatesTable.tsx b/frontend/src/components/DocumentTemplatesTable.tsx index 651dcb96..5a599c76 100644 --- a/frontend/src/components/DocumentTemplatesTable.tsx +++ b/frontend/src/components/DocumentTemplatesTable.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import CardBody from './CardBody'; import DataTableComponent from './DataTableComponent'; import Card from '../layouts/CardLayout'; import CardHeader from './CardHeader'; import { IDocumentTemplateListItem } from '../common/interfaces/template.interface'; -import { useDocumentTemplatesQuery } from '../services/documents-templates/documents-templates.service'; +import { useDeleteDocumentTemplateMutation, useDocumentTemplatesQuery } from '../services/documents-templates/documents-templates.service'; import { OrderDirection } from '../common/enums/order-direction.enum'; import { format } from 'date-fns'; import { SortOrder, TableColumn } from 'react-data-table-component'; @@ -14,6 +14,8 @@ import { ArrowDownTrayIcon, EyeIcon, PencilIcon, PlusIcon, TrashIcon } from '@he import Popover from './Popover'; import { Link, useNavigate } from 'react-router-dom'; import Button from './Button'; +import ConfirmationModal from './ConfirmationModal'; +import { useErrorToast, useSuccessToast } from '../hooks/useToast'; const createArchiveRoute = (name: string) => `/actions-archive?author=${name.split(' ').join('+')}`; @@ -64,14 +66,40 @@ const DocumentTemplatesTableHeader = [ export const DocumentTemplatesTable = ({ query, setQuery }: DocumentTemplatesProps) => { const { t } = useTranslation(['doc_templates']); const navigate = useNavigate(); + const [selectedDeleteDocumentTemplate, setSelectedDeleteDocumentTemplate] = useState(null); - const { data: templates, isLoading: isLoadingDocumentTemplates } = useDocumentTemplatesQuery({ + const { data: templates, isLoading: isLoadingDocumentTemplates, refetch } = useDocumentTemplatesQuery({ limit: 10, page: 1, orderBy: 'name', orderDirection: OrderDirection.ASC, }); + const { mutate: deleteDocumentTemplate } = useDeleteDocumentTemplateMutation(); + + const handleDeleteDocumentTemplate = (template: IDocumentTemplateListItem) => { + setSelectedDeleteDocumentTemplate(template); + }; + + const handleCancelDelete = () => { + setSelectedDeleteDocumentTemplate(null); + }; + + const handleConfirmDelete = () => { + if (selectedDeleteDocumentTemplate) { + deleteDocumentTemplate(selectedDeleteDocumentTemplate?.id, { + onSuccess: () => { + setSelectedDeleteDocumentTemplate(null); + useSuccessToast(t('success_delete')); + refetch(); + }, + onError: () => { + useErrorToast(t('error_delete')); + }, + }); + } + }; + // pagination const onRowsPerPageChange = (limit: number) => { setQuery( @@ -125,7 +153,7 @@ export const DocumentTemplatesTable = ({ query, setQuery }: DocumentTemplatesPro { label: t('table.table_actions.delete'), icon: , - onClick: () => { }, + onClick: (row: IDocumentTemplateListItem) => { handleDeleteDocumentTemplate(row) }, alert: true, }, ]; @@ -152,38 +180,50 @@ export const DocumentTemplatesTable = ({ query, setQuery }: DocumentTemplatesPro }; return ( - - -

{t('table.title')}

-
-
+
+ + - - - - +
+ {selectedDeleteDocumentTemplate && + - - + } + ); }; diff --git a/frontend/src/components/SignatureContent.tsx b/frontend/src/components/SignatureContent.tsx index 4c502740..341fc08c 100644 --- a/frontend/src/components/SignatureContent.tsx +++ b/frontend/src/components/SignatureContent.tsx @@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next'; import { ArrowLeftIcon, CheckIcon, XMarkIcon } from '@heroicons/react/24/outline'; import LoadingContent from './LoadingContent'; import Button from './Button'; - +import { useErrorToast } from '../hooks/useToast'; export const SignatureContent = ({ contract, setSidePanelContent, @@ -71,6 +71,11 @@ export const SignatureContent = ({ onSuccess: () => { setSidePanelContent(2); }, + onError: () => { + useErrorToast(t('sign.error.error_signing')); + // show contract info content + setSidePanelContent(0); + }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ['document-contract', contract?.documentId], diff --git a/frontend/src/services/documents-templates/documents-templates.api.ts b/frontend/src/services/documents-templates/documents-templates.api.ts index 4a062d34..607467b8 100644 --- a/frontend/src/services/documents-templates/documents-templates.api.ts +++ b/frontend/src/services/documents-templates/documents-templates.api.ts @@ -32,3 +32,7 @@ export const updateContractTemplate = (id: string, data: IAddContractTemplatePay export const getContractTemplate = (id: string) => { return API.get(`/documents/templates/${id}`).then((res) => res.data); }; + +export const deleteContractTemplate = (id: string) => { + return API.delete(`/documents/templates/${id}`).then((res) => res.data); +}; diff --git a/frontend/src/services/documents-templates/documents-templates.service.ts b/frontend/src/services/documents-templates/documents-templates.service.ts index 537c7fa3..1de729a2 100644 --- a/frontend/src/services/documents-templates/documents-templates.service.ts +++ b/frontend/src/services/documents-templates/documents-templates.service.ts @@ -1,6 +1,7 @@ import { useMutation, useQuery } from 'react-query'; import { addContractTemplate, + deleteContractTemplate, getContractTemplate, getTemplateById, getTemplates, @@ -89,3 +90,12 @@ export const useDocumentTemplateByIdQuery = (id?: string) => { enabled: !!id, }); }; + +export const useDeleteDocumentTemplateMutation = () => { + return useMutation((id: string) => deleteContractTemplate(id), { + onError: (error) => { + console.log('⭕️ ERROR IN DELETE DOCUMENT TEMPLATE MUTATION ⭕️', error); + return Promise.resolve(error); + }, + }); +}; diff --git a/mobile/app.config.ts b/mobile/app.config.ts index e6d109bd..e8a2fe98 100644 --- a/mobile/app.config.ts +++ b/mobile/app.config.ts @@ -70,7 +70,7 @@ const expoConfig: ExpoConfig = { url: 'https://u.expo.dev/6aaad982-5a5c-4af8-b66c-7689afe74e1f', }, runtimeVersion: { - policy: 'sdkVersion', + policy: 'appVersion', }, owner: 'commit-global', }; diff --git a/mobile/src/assets/locales/en/translation.json b/mobile/src/assets/locales/en/translation.json index acb0d819..90eec7cf 100644 --- a/mobile/src/assets/locales/en/translation.json +++ b/mobile/src/assets/locales/en/translation.json @@ -129,7 +129,8 @@ "label": "City" }, "birthday": { - "label": "Date of birth" + "label": "Date of birth", + "required": "The date of birth is required" } } } diff --git a/mobile/src/assets/locales/ro/translation.json b/mobile/src/assets/locales/ro/translation.json index c0d2a1c3..ca1b98e8 100644 --- a/mobile/src/assets/locales/ro/translation.json +++ b/mobile/src/assets/locales/ro/translation.json @@ -129,7 +129,8 @@ "label": "Oraș" }, "birthday": { - "label": "Data nașterii" + "label": "Data nașterii", + "required": "Data nașterii este obligatorie" } } } diff --git a/mobile/src/common/utils/document-contracts.helpers.ts b/mobile/src/common/utils/document-contracts.helpers.ts index 75a97356..98a1c8e3 100644 --- a/mobile/src/common/utils/document-contracts.helpers.ts +++ b/mobile/src/common/utils/document-contracts.helpers.ts @@ -8,6 +8,9 @@ import { } from '../interfaces/user-profile.interface'; export const isOver16 = (birthday: string | Date) => { + if (!birthday) { + return true; + } const birthdayDate = typeof birthday === 'string' ? parseISO(birthday) : birthday; const today = new Date(); const age = differenceInYears(today, birthdayDate); diff --git a/mobile/src/components/SignatureBottomSheet.tsx b/mobile/src/components/SignatureBottomSheet.tsx index 15c19e27..22df782a 100644 --- a/mobile/src/components/SignatureBottomSheet.tsx +++ b/mobile/src/components/SignatureBottomSheet.tsx @@ -1,5 +1,9 @@ import React, { useEffect, useMemo, useState } from 'react'; -import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet'; +import BottomSheet, { + BottomSheetBackdrop, + BottomSheetHandle, + BottomSheetView, +} from '@gorhom/bottom-sheet'; import { Animated, StyleSheet, View } from 'react-native'; import { useReducedMotion } from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -10,10 +14,10 @@ import { SvgXml } from 'react-native-svg'; import { Text, useTheme } from '@ui-kitten/components'; import InlineLink from './InlineLink'; import upsIcon from '../assets/svg/ups-icon'; -import { renderBackdrop } from '../components/BottomSheet'; import { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types'; import { SignatureViewRef } from 'react-native-signature-canvas'; import LottieView from 'lottie-react-native'; +import { renderBackdrop } from './BottomSheet'; interface SignatureBottomSheetProps { bottomSheetRef: React.RefObject; snapPoints: number[]; @@ -134,14 +138,21 @@ export const SignatureBottomSheet = ({ const insets = useSafeAreaInsets(); const theme = useTheme(); + const renderUncloseableBackdrop = (props: any) => { + return ; + }; + return ( {!isFinishedSigning.isFinished ? ( diff --git a/mobile/src/screens/CreateUser.tsx b/mobile/src/screens/CreateUser.tsx index b83075a1..838bc8bf 100644 --- a/mobile/src/screens/CreateUser.tsx +++ b/mobile/src/screens/CreateUser.tsx @@ -60,6 +60,7 @@ const schema = yup.object({ value: '50', })}`, ), + birthday: yup.date().required(`${i18n.t('register:create_user.form.birthday.required')}`), }); const CreateUser = ({ navigation }: any) => { @@ -192,6 +193,7 @@ const CreateUser = ({ navigation }: any) => { disabled={isLoading} name="birthday" error={errors.birthday} + required={true} /> { const [isUserOver16, setIsUserOver16] = useState( userProfile?.birthday ? isOver16(userProfile?.birthday) - : userProfile?.userPersonalData.cnp + : userProfile?.userPersonalData ? isOver16FromCNP(userProfile?.userPersonalData.cnp) : true, ); diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx index e470f35a..7eb037da 100644 --- a/mobile/src/screens/Settings.tsx +++ b/mobile/src/screens/Settings.tsx @@ -20,6 +20,7 @@ import { useUserProfile } from '../store/profile/profile.selector'; import { ALLOW_FONT_SCALLING } from '../common/constants/constants'; import { Screen } from '../components/Screen'; import { usePaddingTop } from '../hooks/usePaddingTop'; +import Constants from 'expo-constants'; export enum SETTINGS_ROUTES { ACCOUNT_DATA = 'account-data', @@ -106,9 +107,15 @@ const Settings = ({ navigation }: any) => { return ( - - {`${t('title')}`} - + + + {`${t('title')}`} + + {`${Constants.expoConfig?.version || ''}`} + + {!userProfile?.profilePicture && ( @@ -144,6 +151,11 @@ const Settings = ({ navigation }: any) => { export default Settings; const styles = StyleSheet.create({ + header: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + }, list: { backgroundColor: 'white', },