diff --git a/pages/sites/[slug]/[locale]/claim/[type]/[code].tsx b/pages/sites/[slug]/[locale]/claim/[type]/[code].tsx index d03d2f96c..30c2deb72 100644 --- a/pages/sites/[slug]/[locale]/claim/[type]/[code].tsx +++ b/pages/sites/[slug]/[locale]/claim/[type]/[code].tsx @@ -35,6 +35,10 @@ interface Props { pageProps: PageProps; } +export type RedeemCodeSubmitData = { + code: string; +}; + function ClaimDonation({ pageProps }: Props): ReactElement { const t = useTranslations('Redeem'); const router = useRouter(); @@ -79,12 +83,15 @@ function ClaimDonation({ pageProps }: Props): ReactElement { }; async function redeemingCode(code: string): Promise { - const submitData = { + const submitData: RedeemCodeSubmitData = { code: code, }; if (contextLoaded && user) { try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest< + RedeemedCodeData, + RedeemCodeSubmitData + >({ tenant: pageProps.tenantConfig.id, url: `/app/redeem`, data: submitData, diff --git a/pages/sites/[slug]/[locale]/profile/redeem/[code].tsx b/pages/sites/[slug]/[locale]/profile/redeem/[code].tsx index 2f3303cc2..347a66268 100644 --- a/pages/sites/[slug]/[locale]/profile/redeem/[code].tsx +++ b/pages/sites/[slug]/[locale]/profile/redeem/[code].tsx @@ -8,6 +8,7 @@ import type { AbstractIntlMessages } from 'next-intl'; import type { APIError, SerializedError } from '@planet-sdk/common'; import type { Tenant } from '@planet-sdk/common/build/types/tenant'; import type { RedeemedCodeData } from '../../../../../../src/features/common/types/redeem'; +import type { RedeemCodeSubmitData } from '../../claim/[type]/[code]'; import { useRouter } from 'next/router'; import { useState, useEffect, useContext } from 'react'; @@ -73,13 +74,16 @@ const RedeemCode = ({ pageProps: { tenantConfig } }: Props) => { async function redeemingCode(data: string): Promise { setIsLoading(true); - const submitData = { + const submitData: RedeemCodeSubmitData = { code: data, }; if (contextLoaded && user) { try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest< + RedeemedCodeData, + RedeemCodeSubmitData + >({ tenant: tenantConfig?.id, url: `/app/redeem`, data: submitData, diff --git a/src/features/user/Account/EditModal.tsx b/src/features/user/Account/EditModal.tsx index 17f0e9053..8cc5442e1 100644 --- a/src/features/user/Account/EditModal.tsx +++ b/src/features/user/Account/EditModal.tsx @@ -131,7 +131,10 @@ export const EditModal = ({ if (Object.keys(bodyToSend).length !== 0) { try { - const res = await putAuthenticatedRequest({ + const res = await putAuthenticatedRequest< + ModifyDonations, + BodyToSendType + >({ tenant: tenantConfig?.id, url: `/app/subscriptions/${record?.id}?scope=modify`, data: bodyToSend, diff --git a/src/features/user/BulkCodes/forms/IssueCodesForm.tsx b/src/features/user/BulkCodes/forms/IssueCodesForm.tsx index 9641007ec..8146efa63 100644 --- a/src/features/user/BulkCodes/forms/IssueCodesForm.tsx +++ b/src/features/user/BulkCodes/forms/IssueCodesForm.tsx @@ -152,7 +152,10 @@ const IssueCodesForm = (): ReactElement | null => { const cleanedData = cleanObject(donationData); try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest< + Donation, + PrepaidDonationRequest + >({ tenant: tenantConfig?.id, url: `/app/donations`, data: cleanedData, diff --git a/src/features/user/CompleteSignup/index.tsx b/src/features/user/CompleteSignup/index.tsx index daaaaca27..830faa8e8 100644 --- a/src/features/user/CompleteSignup/index.tsx +++ b/src/features/user/CompleteSignup/index.tsx @@ -178,7 +178,7 @@ export default function CompleteSignup(): ReactElement | null { setRequestSent(true); setIsProcessing(true); try { - const res = await postRequest({ + const res = await postRequest({ tenant: tenantConfig?.id, url: `/app/profile`, data: bodyToSend, diff --git a/src/features/user/ManagePayouts/screens/AddBankAccount.tsx b/src/features/user/ManagePayouts/screens/AddBankAccount.tsx index 93c52aa13..8467daa0b 100644 --- a/src/features/user/ManagePayouts/screens/AddBankAccount.tsx +++ b/src/features/user/ManagePayouts/screens/AddBankAccount.tsx @@ -17,6 +17,21 @@ import { PayoutCurrency } from '../../../../utils/constants/payoutConstants'; import { handleError } from '@planet-sdk/common'; import { useTenant } from '../../../common/Layout/TenantContext'; +export interface AccountData { + currency: string; + payoutMinAmount: string | undefined; + bankName: string; + bankCountry: string; + bankAddress: string; + holderName: string; + holderAddress: string; + accountNumber: string; + routingNumber: string; + bic: string; + branchCode: string; + remarks: string; +} + const AddBankAccount = (): ReactElement | null => { const t = useTranslations('ManagePayouts'); const { payoutMinAmounts, setAccounts, accounts } = usePayouts(); @@ -32,14 +47,14 @@ const AddBankAccount = (): ReactElement | null => { const handleSaveAccount = async (data: FormData) => { setIsProcessing(true); - const accountData = { + const accountData: AccountData = { ...data, currency: data.currency === PayoutCurrency.DEFAULT ? '' : data.currency, payoutMinAmount: data.currency === PayoutCurrency.DEFAULT ? '' : data.payoutMinAmount, }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig?.id, url: '/app/accounts', data: accountData, diff --git a/src/features/user/ManagePayouts/screens/EditBankAccount.tsx b/src/features/user/ManagePayouts/screens/EditBankAccount.tsx index 39570949c..12b63f365 100644 --- a/src/features/user/ManagePayouts/screens/EditBankAccount.tsx +++ b/src/features/user/ManagePayouts/screens/EditBankAccount.tsx @@ -19,6 +19,7 @@ import { useUserProps } from '../../../common/Layout/UserPropsContext'; import { PayoutCurrency } from '../../../../utils/constants/payoutConstants'; import { handleError } from '@planet-sdk/common'; import { useTenant } from '../../../common/Layout/TenantContext'; +import { AccountData } from './AddBankAccount'; const EditBankAccount = (): ReactElement | null => { const { accounts, payoutMinAmounts, setAccounts } = usePayouts(); @@ -37,7 +38,7 @@ const EditBankAccount = (): ReactElement | null => { const handleSaveAccount = async (data: FormData) => { setIsProcessing(true); - const accountData = { + const accountData: AccountData = { ...data, currency: data.currency === PayoutCurrency.DEFAULT ? '' : data.currency, payoutMinAmount: @@ -45,7 +46,7 @@ const EditBankAccount = (): ReactElement | null => { }; try { - const res = await putAuthenticatedRequest({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/accounts/${accountToEdit?.id}`, data: accountData, diff --git a/src/features/user/ManagePayouts/screens/PayoutScheduleForm.tsx b/src/features/user/ManagePayouts/screens/PayoutScheduleForm.tsx index 75ce412ad..0e041e605 100644 --- a/src/features/user/ManagePayouts/screens/PayoutScheduleForm.tsx +++ b/src/features/user/ManagePayouts/screens/PayoutScheduleForm.tsx @@ -47,7 +47,7 @@ const PayoutScheduleForm = (): ReactElement | null => { setIsProcessing(true); try { - const res = await putAuthenticatedRequest({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig?.id, url: '/app/profile', data: { scheduleFrequency: data.scheduleFrequency }, diff --git a/src/features/user/ManageProjects/components/BasicDetails.tsx b/src/features/user/ManageProjects/components/BasicDetails.tsx index b8dc673ed..7f32be2ed 100644 --- a/src/features/user/ManageProjects/components/BasicDetails.tsx +++ b/src/features/user/ManageProjects/components/BasicDetails.tsx @@ -66,6 +66,36 @@ type TreeFormData = FormData & { type ConservationFormData = FormData; +interface SubmitDataBase { + name: string; + slug: string; + website: string; + description: string; + acceptDonations: boolean; + unitCost: number | undefined; + currency: 'EUR'; // Fixed currency + metadata: { + ecosystem: string; + visitorAssistance: boolean; + }; + geometry: { + type: 'Point'; + coordinates: [number, number]; + }; +} + +interface SubmitDataTrees extends SubmitDataBase { + unitType: 'tree' | 'm2'; + classification: string; + countTarget: number; +} + +interface SubmitDataConservation extends SubmitDataBase { + purpose: 'conservation'; +} + +type SubmitData = SubmitDataTrees | SubmitDataConservation; + export default function BasicDetails({ handleNext, token, @@ -306,7 +336,7 @@ export default function BasicDetails({ const onSubmit = async (data: TreeFormData | ConservationFormData) => { setIsUploadingData(true); - const submitData = + const submitData: SubmitData = purpose === 'trees' ? { name: data.name, @@ -361,7 +391,8 @@ export default function BasicDetails({ if (projectGUID) { try { const res = await putAuthenticatedRequest< - ProfileProjectTrees | ProfileProjectConservation + ProfileProjectTrees | ProfileProjectConservation, + SubmitData >({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}`, @@ -379,7 +410,8 @@ export default function BasicDetails({ } else { try { const res = await postAuthenticatedRequest< - ProfileProjectTrees | ProfileProjectConservation + ProfileProjectTrees | ProfileProjectConservation, + SubmitData >({ tenant: tenantConfig?.id, url: `/app/projects`, diff --git a/src/features/user/ManageProjects/components/DetailedAnalysis.tsx b/src/features/user/ManageProjects/components/DetailedAnalysis.tsx index fcab29a3e..18933ae50 100644 --- a/src/features/user/ManageProjects/components/DetailedAnalysis.tsx +++ b/src/features/user/ManageProjects/components/DetailedAnalysis.tsx @@ -1,6 +1,12 @@ import type { ReactElement } from 'react'; import type { SxProps } from '@mui/material'; -import type { APIError, InterventionTypes } from '@planet-sdk/common'; +import type { + AllowedSeasonMonths, + APIError, + InterventionTypes, + LandOwnershipTypes, + SiteOwnerTypes, +} from '@planet-sdk/common'; import type { DetailedAnalysisProps, SiteOwners, @@ -69,30 +75,68 @@ const yearDialogSx: SxProps = { }; type FormData = { - employeesCount: string; - acquisitionYear: Date | null; - mainChallenge: string; - motivation: string; - longTermPlan: string; - siteOwnerName: string; + employeesCount: number | null; + mainChallenge: string | null; + siteOwnerName: string | null; + acquisitionYear: number | null; + longTermPlan: string | null; + motivation: string | null; }; type TreeFormData = FormData & { purpose: 'trees'; - yearAbandoned: Date | null; - firstTreePlanted: Date | null; - plantingDensity: string; - maxPlantingDensity: string; - degradationYear: Date | null; - degradationCause: string; + yearAbandoned: number | null; + firstTreePlanted: string | null; + plantingDensity: number | null; + maxPlantingDensity: number | null; + degradationYear: number | null; + degradationCause: string | null; }; type ConservationFormData = FormData & { purpose: 'conservation'; - areaProtected: string; - startingProtectionYear: Date | null; - actions: string; - benefits: string; + actions: string | null; + benefits: string | null; + startingProtectionYear: number | null; + areaProtected: number | null; +}; + +type MetadataBase = { + employeesCount: number | null; + acquisitionYear: number | null; + mainInterventions: InterventionTypes[]; + longTermPlan: string | null; + mainChallenge: string | null; + motivation: string | null; + siteOwnerName: string | null; +}; + +type TreeMetadata = MetadataBase & { + plantingSeasons: AllowedSeasonMonths[]; + plantingDensity: number | null; + maxPlantingDensity: number | null; + firstTreePlanted: string | null; + siteOwnerType: SiteOwnerTypes[]; + degradationCause: string | null; + degradationYear: number | null; + yearAbandoned: number | null; +}; + +type ConservMetadata = MetadataBase & { + activitySeasons: AllowedSeasonMonths[]; + areaProtected: number | null; + startingProtectionYear: number | null; + landOwnershipType: LandOwnershipTypes[]; + actions: string | null; + benefits: string | null; +}; + +type TreeSubmitData = { + metadata: TreeMetadata; +}; + +type ConservSubmitData = { + metadata: ConservMetadata; }; export default function DetailedAnalysis({ @@ -246,31 +290,31 @@ export default function DetailedAnalysis({ purpose === 'trees' ? { purpose: 'trees', - yearAbandoned: new Date(), + yearAbandoned: null, firstTreePlanted: null, - plantingDensity: '', - maxPlantingDensity: '', - employeesCount: '', - mainChallenge: '', - siteOwnerName: '', - acquisitionYear: null, + plantingDensity: null, + maxPlantingDensity: null, degradationYear: null, - degradationCause: '', - longTermPlan: '', - motivation: '', + degradationCause: null, + employeesCount: null, + mainChallenge: null, + siteOwnerName: null, + acquisitionYear: null, + longTermPlan: null, + motivation: null, } : { purpose: 'conservation', - actions: '', - benefits: '', - employeesCount: '', - acquisitionYear: null, + actions: null, + benefits: null, startingProtectionYear: null, - areaProtected: '', - siteOwnerName: '', - mainChallenge: '', - longTermPlan: '', - motivation: '', + areaProtected: null, + employeesCount: null, + mainChallenge: null, + siteOwnerName: null, + acquisitionYear: null, + longTermPlan: null, + motivation: null, }; const { @@ -284,17 +328,17 @@ export default function DetailedAnalysis({ defaultValues: defaultFormData, }); - const owners: string[] = []; + const owners: SiteOwnerTypes[] = []; for (let i = 0; i < siteOwners.length; i++) { if (siteOwners[i].isSet) { - owners.push(`${siteOwners[i].value}`); + owners.push(`${siteOwners[i].value}` as SiteOwnerTypes); } } - const months: number[] = []; + const months: AllowedSeasonMonths[] = []; for (let i = 0; i < plantingSeasons.length; i++) { if (plantingSeasons[i].isSet) { - const j = i + 1; + const j = (i + 1) as AllowedSeasonMonths; months.push(j); } } @@ -315,62 +359,63 @@ export default function DetailedAnalysis({ return; } setIsUploadingData(true); - const submitData = + const submitData: TreeSubmitData | ConservSubmitData = data.purpose === 'trees' ? { metadata: { + plantingSeasons: months, + plantingDensity: data.plantingDensity, + maxPlantingDensity: data.maxPlantingDensity, + firstTreePlanted: data.firstTreePlanted + ? `${new Date(data.firstTreePlanted).getFullYear()}-${ + new Date(data.firstTreePlanted).getMonth() + 1 + }-${new Date(data.firstTreePlanted).getDate()}` + : null, + siteOwnerType: owners, degradationCause: data.degradationCause, degradationYear: data.degradationYear - ? data.degradationYear.getFullYear() + ? new Date(data.degradationYear).getFullYear() + : null, + yearAbandoned: data.yearAbandoned + ? new Date(data.yearAbandoned).getFullYear() : null, employeesCount: data.employeesCount, acquisitionYear: data.acquisitionYear - ? data.acquisitionYear.getFullYear() + ? new Date(data.acquisitionYear).getFullYear() : null, mainInterventions: mainInterventions, longTermPlan: data.longTermPlan, mainChallenge: data.mainChallenge, motivation: data.motivation, - plantingDensity: data.plantingDensity, - maxPlantingDensity: data.maxPlantingDensity, - plantingSeasons: months, siteOwnerName: data.siteOwnerName, - siteOwnerType: owners, - yearAbandoned: data.yearAbandoned - ? data.yearAbandoned.getFullYear() - : null, - firstTreePlanted: data.firstTreePlanted - ? `${data.firstTreePlanted.getFullYear()}-${ - data.firstTreePlanted.getMonth() + 1 - }-${data.firstTreePlanted.getDate()}` - : null, }, } : { metadata: { - acquisitionYear: data.acquisitionYear - ? data.acquisitionYear.getFullYear() - : null, activitySeasons: months, areaProtected: data.areaProtected, - employeesCount: data.employeesCount, - mainInterventions: mainInterventions, startingProtectionYear: data.startingProtectionYear - ? data.startingProtectionYear.getFullYear() + ? new Date(data.startingProtectionYear).getFullYear() : null, landOwnershipType: owners, actions: data.actions, + benefits: data.benefits, + employeesCount: data.employeesCount, + acquisitionYear: data.acquisitionYear + ? new Date(data.acquisitionYear).getFullYear() + : null, + mainInterventions: mainInterventions, + longTermPlan: data.longTermPlan, mainChallenge: data.mainChallenge, motivation: data.motivation, - longTermPlan: data.longTermPlan, - benefits: data.benefits, siteOwnerName: data.siteOwnerName, }, }; try { const res = await putAuthenticatedRequest< - ProfileProjectTrees | ProfileProjectConservation + ProfileProjectTrees | ProfileProjectConservation, + TreeSubmitData | ConservSubmitData >({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}`, @@ -397,45 +442,31 @@ export default function DetailedAnalysis({ projectPurpose === 'trees' ? { purpose: 'trees', - yearAbandoned: metadata.yearAbandoned - ? new Date(new Date().setFullYear(metadata.yearAbandoned)) - : new Date(), - firstTreePlanted: metadata.firstTreePlanted - ? new Date(metadata.firstTreePlanted) - : new Date(), - plantingDensity: metadata.plantingDensity?.toString() || '', - maxPlantingDensity: metadata.maxPlantingDensity?.toString() || '', - employeesCount: metadata.employeesCount?.toString() || '', - mainChallenge: metadata.mainChallenge || '', - siteOwnerName: metadata.siteOwnerName || '', - acquisitionYear: metadata.acquisitionYear - ? new Date(new Date().setFullYear(metadata.acquisitionYear)) - : new Date(), - degradationYear: metadata.degradationYear - ? new Date(new Date().setFullYear(metadata.degradationYear)) - : new Date(), - degradationCause: metadata.degradationCause || '', - longTermPlan: metadata.longTermPlan || '', - motivation: metadata.motivation || '', + yearAbandoned: metadata.yearAbandoned || null, + firstTreePlanted: metadata.firstTreePlanted || null, + plantingDensity: metadata.plantingDensity || null, + maxPlantingDensity: metadata.maxPlantingDensity || null, + employeesCount: metadata.employeesCount || null, + mainChallenge: metadata.mainChallenge || null, + siteOwnerName: metadata.siteOwnerName || null, + acquisitionYear: metadata.acquisitionYear || null, + degradationYear: metadata.degradationYear || null, + degradationCause: metadata.degradationCause || null, + longTermPlan: metadata.longTermPlan || null, + motivation: metadata.motivation || null, } : { purpose: 'conservation', - actions: metadata.actions || '', - benefits: metadata.benefits || '', - employeesCount: metadata.employeesCount?.toString() || '', - acquisitionYear: metadata.acquisitionYear - ? new Date(new Date().setFullYear(metadata.acquisitionYear)) - : new Date(), - startingProtectionYear: metadata.startingProtectionYear - ? new Date( - new Date().setFullYear(metadata.startingProtectionYear) - ) - : new Date(), - areaProtected: metadata.areaProtected?.toString() || '', - mainChallenge: metadata.mainChallenge || '', - siteOwnerName: metadata.siteOwnerName || '', - longTermPlan: metadata.longTermPlan || '', - motivation: metadata.motivation || '', + actions: metadata.actions || null, + benefits: metadata.benefits || null, + employeesCount: metadata.employeesCount || null, + acquisitionYear: metadata.acquisitionYear || null, + startingProtectionYear: metadata.startingProtectionYear || null, + areaProtected: metadata.areaProtected || null, + mainChallenge: metadata.mainChallenge || null, + siteOwnerName: metadata.siteOwnerName || null, + longTermPlan: metadata.longTermPlan || null, + motivation: metadata.motivation || null, }; // set planting seasons @@ -521,7 +552,6 @@ export default function DetailedAnalysis({ ); setInterventionOptions(initialInterventionOptions); } - reset(formData); } }, [projectDetails]); @@ -544,7 +574,7 @@ export default function DetailedAnalysis({ ( (value ? parseInt(value, 10) > 0 : true), + validate: (value) => + value ? parseInt(value.toString() || '0', 10) > 0 : true, }} render={({ field: { onChange, value, onBlur } }) => ( parseInt(value, 10) > 0, + validate: (value) => parseInt(value?.toString() || '0', 10) > 0, }} render={({ field: { onChange, value, onBlur } }) => ( - value.length === 0 || parseInt(value, 10) > 1, + value?.toString().length === 0 || + parseInt(value?.toString() || '0', 10) > 1, }} render={({ field: { onChange, value, onBlur } }) => ( { const { issueDate, certifierName } = getValues(); setIsUploadingData(true); - const submitData = { + const submitData: SubmitData = { issueDate: issueDate.getFullYear(), certifierName: certifierName, pdfFile: pdf, }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}/certificates`, data: submitData, diff --git a/src/features/user/ManageProjects/components/ProjectMedia.tsx b/src/features/user/ManageProjects/components/ProjectMedia.tsx index 72aeb0fb4..cf3ff5600 100644 --- a/src/features/user/ManageProjects/components/ProjectMedia.tsx +++ b/src/features/user/ManageProjects/components/ProjectMedia.tsx @@ -33,6 +33,16 @@ import { useUserProps } from '../../../common/Layout/UserPropsContext'; import { ProjectCreationTabs } from '..'; import { useTenant } from '../../../common/Layout/TenantContext'; +type PostSubmitData = { + imageFile: string; + description: string | null; + isDefault: boolean; +}; + +type VideoSubmitData = { + videoUrl: string; +}; + export default function ProjectMedia({ handleBack, token, @@ -84,14 +94,14 @@ export default function ProjectMedia({ const uploadPhotos = async (image: string) => { setIsUploadingData(true); - const submitData = { + const submitData: PostSubmitData = { imageFile: image, description: null, isDefault: false, }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}/images`, data: submitData, @@ -165,13 +175,14 @@ export default function ProjectMedia({ const onSubmit = async (data: { youtubeURL: string }) => { // Add isDirty test here setIsUploadingData(true); - const submitData = { + const submitData: VideoSubmitData = { videoUrl: data.youtubeURL, }; try { const res = await putAuthenticatedRequest< - ProfileProjectTrees | ProfileProjectConservation + ProfileProjectTrees | ProfileProjectConservation, + VideoSubmitData >({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}`, diff --git a/src/features/user/ManageProjects/components/ProjectSites.tsx b/src/features/user/ManageProjects/components/ProjectSites.tsx index c0d36d2b8..db24a26c9 100644 --- a/src/features/user/ManageProjects/components/ProjectSites.tsx +++ b/src/features/user/ManageProjects/components/ProjectSites.tsx @@ -8,7 +8,11 @@ import type { Site, SitesScopeProjects, } from '../../../common/types/project'; -import type { FeatureCollection as GeoJson } from 'geojson'; +import type { + FeatureCollection as GeoJson, + GeoJsonProperties, + Geometry, +} from 'geojson'; import React from 'react'; import styles from './../StepForm.module.scss'; @@ -55,6 +59,12 @@ const Map = dynamic(() => import('./MapComponent'), { loading: () =>

, }); +type SubmitData = { + name: string; + geometry: GeoJson; + status: string; +}; + function EditSite({ openModal, handleModalClose, @@ -98,14 +108,14 @@ function EditSite({ const editProjectSite = async (data: ProjectSitesFormData) => { if (geoJson && geoJson.features && geoJson.features.length !== 0) { setIsUploadingData(true); - const submitData = { + const submitData: SubmitData = { name: siteDetails.name, geometry: geoJson, status: data.status, }; try { - const res = await putAuthenticatedRequest({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}/sites/${siteGUID}`, data: submitData, @@ -369,14 +379,14 @@ export default function ProjectSites({ if (!data.name) return; setIsUploadingData(true); - const submitData = { + const submitData: SubmitData = { name: siteDetails.name, geometry: geoJson, status: data.status, }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}/sites`, data: submitData, diff --git a/src/features/user/ManageProjects/components/ProjectSpending.tsx b/src/features/user/ManageProjects/components/ProjectSpending.tsx index 89e81c419..f7ff6beb8 100644 --- a/src/features/user/ManageProjects/components/ProjectSpending.tsx +++ b/src/features/user/ManageProjects/components/ProjectSpending.tsx @@ -56,7 +56,11 @@ type FormData = { year: Date; amount: number; }; - +type SubmitData = { + year: number; + amount: number; + pdfFile: string | ArrayBuffer | null | undefined; +}; export default function ProjectSpending({ handleBack, token, @@ -88,14 +92,14 @@ export default function ProjectSpending({ const updatedAmount = getValues('amount'); const year = getValues('year'); - const submitData = { + const submitData: SubmitData = { year: year.getFullYear(), amount: updatedAmount, pdfFile: pdf, }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}/expenses`, data: submitData, diff --git a/src/features/user/ManageProjects/index.tsx b/src/features/user/ManageProjects/index.tsx index af63490ee..ff62bdd17 100644 --- a/src/features/user/ManageProjects/index.tsx +++ b/src/features/user/ManageProjects/index.tsx @@ -36,6 +36,14 @@ export enum ProjectCreationTabs { PROJECT_SPENDING = 5, REVIEW = 6, } + +type PublishSubmitData = { + publish: boolean; +}; + +type ReviewSubmitData = { + reviewRequested: boolean; +}; export default function ManageProjects({ GUID, token, @@ -100,13 +108,14 @@ export default function ManageProjects({ const submitForReview = async () => { setIsUploadingData(true); - const submitData = { + const submitData: ReviewSubmitData = { reviewRequested: true, }; try { const res = await putAuthenticatedRequest< - ProfileProjectTrees | ProfileProjectConservation + ProfileProjectTrees | ProfileProjectConservation, + ReviewSubmitData >({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}`, @@ -124,13 +133,14 @@ export default function ManageProjects({ const handlePublishChange = async (val: boolean) => { setIsUploadingData(true); - const submitData = { + const submitData: PublishSubmitData = { publish: val, }; try { const res = await putAuthenticatedRequest< - ProfileProjectTrees | ProfileProjectConservation + ProfileProjectTrees | ProfileProjectConservation, + PublishSubmitData >({ tenant: tenantConfig?.id, url: `/app/projects/${projectGUID}`, diff --git a/src/features/user/PlanetCash/components/CreateAccountForm.tsx b/src/features/user/PlanetCash/components/CreateAccountForm.tsx index a4181247c..ec017ea33 100644 --- a/src/features/user/PlanetCash/components/CreateAccountForm.tsx +++ b/src/features/user/PlanetCash/components/CreateAccountForm.tsx @@ -25,6 +25,25 @@ interface Props { allowedCountries: CountryType[]; } +type SubmitData = { + country: ExtendedCountryCode | string; + activate: boolean; +}; + +type PlanetCash = { + id: string; + isActive: boolean; + ownerName: string; + balance: number; + debit: number; + fee: number; + creditLimit: number; + currency: 'EUR' | 'USD'; + country: 'DE' | 'ES' | 'US'; + topUpThreshold: number; + topUpAmount: number; +}; + const CreateAccountForm = ({ allowedCountries, isPlanetCashActive, @@ -42,11 +61,14 @@ const CreateAccountForm = ({ const onSubmit = async (event: FormEvent) => { event.preventDefault(); - const data = { country: country, activate: !isPlanetCashActive }; + const data: SubmitData = { + country: country, + activate: !isPlanetCashActive, + }; setIsProcessing(true); try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig?.id, url: '/app/planetCash', data, diff --git a/src/features/user/Profile/ForestProgress/TargetsModal.tsx b/src/features/user/Profile/ForestProgress/TargetsModal.tsx index ca6f8ec96..76f3adcad 100644 --- a/src/features/user/Profile/ForestProgress/TargetsModal.tsx +++ b/src/features/user/Profile/ForestProgress/TargetsModal.tsx @@ -23,6 +23,14 @@ interface TargetsModalProps { conservTarget: number; } +type SubmitData = { + targets: { + treesDonated: number; + areaRestored: number; + areaConserved: number; + }; +}; + const TargetsModal = ({ open, setOpen, @@ -66,7 +74,7 @@ const TargetsModal = ({ const handleTargets = async () => { setIsTargetModalLoading(true); if (contextLoaded && token && open && !isTargetModalLoading) { - const bodyToSend = { + const bodyToSend: SubmitData = { targets: { treesDonated: isTreesPlantedTargetActive ? treesPlantedTargetLocal @@ -80,7 +88,7 @@ const TargetsModal = ({ }, }; try { - const res = await putAuthenticatedRequest({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/profile`, data: bodyToSend, diff --git a/src/features/user/Profile/ProfileCard/RedeemModal/index.tsx b/src/features/user/Profile/ProfileCard/RedeemModal/index.tsx index 7c3cc94d2..8f50e3160 100644 --- a/src/features/user/Profile/ProfileCard/RedeemModal/index.tsx +++ b/src/features/user/Profile/ProfileCard/RedeemModal/index.tsx @@ -1,6 +1,7 @@ import type { ReactElement } from 'react'; import type { APIError, SerializedError } from '@planet-sdk/common'; import type { RedeemedCodeData } from '../../../../common/types/redeem'; +import type { RedeemCodeSubmitData } from '../../../../../../pages/sites/[slug]/[locale]/claim/[type]/[code]'; import Modal from '@mui/material/Modal'; import Fade from '@mui/material/Fade'; @@ -43,14 +44,17 @@ export default function RedeemModal({ RedeemedCodeData | undefined >(undefined); const [isLoading, setIsLoading] = React.useState(false); - async function redeemingCode(data: string | undefined): Promise { + async function redeemingCode(data: string): Promise { setIsLoading(true); - const submitData = { + const submitData: RedeemCodeSubmitData = { code: data, }; if (contextLoaded && user) { try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest< + RedeemedCodeData, + RedeemCodeSubmitData + >({ tenant: tenantConfig?.id, url: `/app/redeem`, data: submitData, diff --git a/src/features/user/RegisterTrees/RegisterTrees/UploadImages.tsx b/src/features/user/RegisterTrees/RegisterTrees/UploadImages.tsx index 7f91ebfd6..d4979ca37 100644 --- a/src/features/user/RegisterTrees/RegisterTrees/UploadImages.tsx +++ b/src/features/user/RegisterTrees/RegisterTrees/UploadImages.tsx @@ -23,6 +23,11 @@ interface Props { token: string | null; } +type SubmitData = { + imageFile: string; + description: string; +}; + export default function UploadImages({ contributionGUID, token, @@ -36,13 +41,13 @@ export default function UploadImages({ const uploadPhotos = async (image: string) => { setIsUploadingData(true); - const submitData = { + const submitData: SubmitData = { imageFile: image, description: '', }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/contributions/${contributionGUID}/images`, data: submitData, diff --git a/src/features/user/RegisterTrees/RegisterTreesWidget.tsx b/src/features/user/RegisterTrees/RegisterTreesWidget.tsx index 519d449ef..63de1fc30 100644 --- a/src/features/user/RegisterTrees/RegisterTreesWidget.tsx +++ b/src/features/user/RegisterTrees/RegisterTreesWidget.tsx @@ -61,6 +61,14 @@ const dialogSx: SxProps = { }, }; +type SubmitData = { + treeCount: string; + treeSpecies: string; + plantProject: string | null; + plantDate: Date; + geometry: RegisterTreeGeometry; +}; + function RegisterTreesForm({ setContributionGUID, setContributionDetails, @@ -183,7 +191,7 @@ function RegisterTreesForm({ geometry.features?.length >= 1)) ) { setIsUploadingData(true); - const submitData = { + const submitData: SubmitData = { treeCount: data.treeCount, treeSpecies: data.species, plantProject: data.plantProject, @@ -191,7 +199,10 @@ function RegisterTreesForm({ geometry: geometry, }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest< + ContributionProperties, + SubmitData + >({ tenant: tenantConfig?.id, url: `/app/contributions`, data: submitData, diff --git a/src/features/user/Settings/EditProfile/AddressManagement/AddAddress.tsx b/src/features/user/Settings/EditProfile/AddressManagement/AddAddress.tsx index e9981098b..f729c8b4f 100644 --- a/src/features/user/Settings/EditProfile/AddressManagement/AddAddress.tsx +++ b/src/features/user/Settings/EditProfile/AddressManagement/AddAddress.tsx @@ -29,6 +29,16 @@ interface Props { setAddressAction: SetState; } +type SubmitData = { + country: '' | ExtendedCountryCode; + type: 'other'; + address: string | undefined; + address2: string | null; + city: string | undefined; + zipCode: string | undefined; + state: string | null; +}; + const defaultAddressDetail = { address: '', address2: '', @@ -57,13 +67,13 @@ const AddAddress = ({ async (data: FormData) => { if (!contextLoaded || !user || !token) return; setIsLoading(true); - const bodyToSend = { + const bodyToSend: SubmitData = { ...data, country, type: ADDRESS_TYPE.OTHER, }; try { - const res = await postAuthenticatedRequest
({ + const res = await postAuthenticatedRequest({ tenant: tenantConfig.id, url: '/app/addresses', data: bodyToSend, diff --git a/src/features/user/Settings/EditProfile/AddressManagement/EditAddress.tsx b/src/features/user/Settings/EditProfile/AddressManagement/EditAddress.tsx index 537dd85eb..18ff0ae2b 100644 --- a/src/features/user/Settings/EditProfile/AddressManagement/EditAddress.tsx +++ b/src/features/user/Settings/EditProfile/AddressManagement/EditAddress.tsx @@ -1,6 +1,11 @@ import type { ExtendedCountryCode } from '../../../../common/types/country'; import type { SetState } from '../../../../common/types/common'; -import type { Address, APIError } from '@planet-sdk/common'; +import type { + Address, + AddressType, + APIError, + CountryCode, +} from '@planet-sdk/common'; import type { FormData } from './AddAddress'; import type { AddressAction } from '../../../../common/types/profile'; @@ -21,6 +26,11 @@ interface Props { setAddressAction: SetState; } +type SubmitData = FormData & { + country: CountryCode | string; + type: AddressType; +}; + const EditAddress = ({ setIsModalOpen, selectedAddressForAction, @@ -48,13 +58,13 @@ const EditAddress = ({ async (data: FormData) => { if (!contextLoaded || !user || !token) return; setIsLoading(true); - const bodyToSend = { + const bodyToSend: SubmitData = { ...data, country, type: selectedAddressForAction?.type, }; try { - const res = await putAuthenticatedRequest
({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig.id, url: `/app/addresses/${selectedAddressForAction?.id}`, data: bodyToSend, diff --git a/src/features/user/Settings/EditProfile/AddressManagement/UnsetBillingAddress.tsx b/src/features/user/Settings/EditProfile/AddressManagement/UnsetBillingAddress.tsx index e4461371c..c0e0589ea 100644 --- a/src/features/user/Settings/EditProfile/AddressManagement/UnsetBillingAddress.tsx +++ b/src/features/user/Settings/EditProfile/AddressManagement/UnsetBillingAddress.tsx @@ -22,6 +22,10 @@ interface Props { selectedAddressForAction: Address; } +type SubmitData = { + type: 'other'; +}; + const UnsetBillingAddress = ({ addressType, setIsModalOpen, @@ -39,11 +43,11 @@ const UnsetBillingAddress = ({ const unsetAddress = async () => { if (!contextLoaded || !user || !token) return; setIsLoading(true); - const bodyToSend = { + const bodyToSend: SubmitData = { type: ADDRESS_TYPE.OTHER, }; try { - const res = await putAuthenticatedRequest
({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig.id, url: `/app/addresses/${selectedAddressForAction.id}`, data: bodyToSend, diff --git a/src/features/user/Settings/EditProfile/AddressManagement/UpdateAddressType.tsx b/src/features/user/Settings/EditProfile/AddressManagement/UpdateAddressType.tsx index 01cbc4669..1651f28bf 100644 --- a/src/features/user/Settings/EditProfile/AddressManagement/UpdateAddressType.tsx +++ b/src/features/user/Settings/EditProfile/AddressManagement/UpdateAddressType.tsx @@ -23,6 +23,10 @@ interface Props { setAddressAction: SetState; } +type SubmitData = { + type: 'primary' | 'mailing'; +}; + const UpdateAddressType = ({ addressType, setIsModalOpen, @@ -41,11 +45,11 @@ const UpdateAddressType = ({ const updateAddress = async (addressType: 'primary' | 'mailing') => { if (!contextLoaded || !user || !token) return; setIsUploadingData(true); - const bodyToSend = { + const bodyToSend: SubmitData = { type: addressType, }; try { - const res = await putAuthenticatedRequest
({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig.id, url: `/app/addresses/${selectedAddressForAction.id}`, data: bodyToSend, diff --git a/src/features/user/Settings/EditProfile/EditProfileForm.tsx b/src/features/user/Settings/EditProfile/EditProfileForm.tsx index bd9bdc9ef..385450c0f 100644 --- a/src/features/user/Settings/EditProfile/EditProfileForm.tsx +++ b/src/features/user/Settings/EditProfile/EditProfileForm.tsx @@ -59,6 +59,9 @@ type ProfileTypeOption = { value: 'individual' | 'organization' | 'education'; }; +type SubmitData = { + imageFile: string | ArrayBuffer | null | undefined; +}; export default function EditProfileForm() { const [snackbarOpen, setSnackbarOpen] = useState(false); const { setErrors } = React.useContext(ErrorHandlingContext); @@ -160,11 +163,9 @@ export default function EditProfileForm() { reset(); }, [type]); - const handleUserProfileImage = async (bodyToSend: { - imageFile: string | ArrayBuffer | null | undefined; - }) => { + const handleUserProfileImage = async (bodyToSend: SubmitData) => { try { - const res = await putAuthenticatedRequest({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/profile`, data: bodyToSend, diff --git a/src/features/user/Settings/ImpersonateUser/SupportPin.tsx b/src/features/user/Settings/ImpersonateUser/SupportPin.tsx index ff72fe6d5..1fa962680 100644 --- a/src/features/user/Settings/ImpersonateUser/SupportPin.tsx +++ b/src/features/user/Settings/ImpersonateUser/SupportPin.tsx @@ -21,7 +21,7 @@ const SupportPin = () => { token, logoutUser, }); - if (response) { + if (response && user) { const updateUserData = { ...user }; updateUserData['supportPin'] = response?.supportPin; setUser(updateUserData); diff --git a/src/features/user/TreeMapper/Import/components/PlantingLocation.tsx b/src/features/user/TreeMapper/Import/components/PlantingLocation.tsx index fb3a9debc..8807491ac 100644 --- a/src/features/user/TreeMapper/Import/components/PlantingLocation.tsx +++ b/src/features/user/TreeMapper/Import/components/PlantingLocation.tsx @@ -10,7 +10,10 @@ import type { Species, PlantLocation as PlantLocationType, } from '../../../../common/types/plantLocation'; -import type { PlantingLocationFormData } from '../../Treemapper'; +import type { + PlantingLocationFormData, + SpeciesFormData, +} from '../../Treemapper'; import type { MapProject } from '../../../../common/types/ProjectPropsContextInterface'; import type { SetState } from '../../../../common/types/common'; import type { SxProps } from '@mui/material'; @@ -165,6 +168,16 @@ interface Props { setActiveMethod: Function; } +type SubmitData = { + type: 'multi-tree-registration'; + captureMode: 'external'; + geometry: Geometry; + plantedSpecies: SpeciesFormData[]; + plantDate: string; + registrationDate: string; + plantProject: string; +}; + export default function PlantingLocation({ handleNext, userLang, @@ -329,7 +342,7 @@ export default function PlantingLocation({ const onSubmit = async (data: PlantingLocationFormData) => { if (geoJson) { setIsUploadingData(true); - const submitData = { + const submitData: SubmitData = { type: 'multi-tree-registration', captureMode: 'external', geometry: geoJson, @@ -340,7 +353,10 @@ export default function PlantingLocation({ }; try { - const res = await postAuthenticatedRequest({ + const res = await postAuthenticatedRequest< + PlantLocationType, + SubmitData + >({ tenant: tenantConfig?.id, url: `/treemapper/interventions`, data: submitData, diff --git a/src/features/user/TreeMapper/MySpecies/SpeciesAutoComplete.tsx b/src/features/user/TreeMapper/MySpecies/SpeciesAutoComplete.tsx index 59c21a791..a955270a7 100644 --- a/src/features/user/TreeMapper/MySpecies/SpeciesAutoComplete.tsx +++ b/src/features/user/TreeMapper/MySpecies/SpeciesAutoComplete.tsx @@ -25,7 +25,10 @@ interface Props< helperText?: React.ReactNode; // mySpecies?: any; } - +type SubmitData = { + q: string; + t: 'species'; +}; export default function SpeciesSelect< TFieldValues extends FieldValues, TName extends FieldPath @@ -62,7 +65,7 @@ export default function SpeciesSelect< // Todo: debouncing if (value.length > 2) { try { - const res = await postRequest({ + const res = await postRequest({ tenant: tenantConfig?.id, url: `/suggest.php`, data: { diff --git a/src/features/user/Widget/EmbedModal.tsx b/src/features/user/Widget/EmbedModal.tsx index d8a880c38..4007f9ebc 100644 --- a/src/features/user/Widget/EmbedModal.tsx +++ b/src/features/user/Widget/EmbedModal.tsx @@ -19,6 +19,9 @@ interface Props { setEmbedModalOpen: Function; } +type SubmitData = { + isPrivate: boolean; +}; const Alert = styled(MuiAlert)(({ theme }) => { return { backgroundColor: theme.palette.primary.main, @@ -56,12 +59,12 @@ export default function EmbedModal({ const saveProfile = async () => { setIsUploadingData(true); - const bodyToSend = { + const bodyToSend: SubmitData = { isPrivate: false, }; if (contextLoaded && token) { try { - const res = await putAuthenticatedRequest({ + const res = await putAuthenticatedRequest({ tenant: tenantConfig?.id, url: `/app/profile`, data: bodyToSend, diff --git a/src/utils/apiRequests/api.ts b/src/utils/apiRequests/api.ts index 8dba539ab..0a76e9d36 100644 --- a/src/utils/apiRequests/api.ts +++ b/src/utils/apiRequests/api.ts @@ -26,9 +26,9 @@ interface GetAuthRequestOptions extends BaseRequestOptions { queryParams?: { [key: string]: string }; version?: string; } -interface PostAuthRequestOptions extends BaseRequestOptions { +interface PostAuthRequestOptions extends BaseRequestOptions { token: string | null; - data: any; + data: D; logoutUser: (value?: string | undefined) => void; headers?: Record; } @@ -36,13 +36,13 @@ interface DeleteAuthRequestOptions extends BaseRequestOptions { token: string | null; logoutUser: (value?: string | undefined) => void; } -interface PutAuthRequestOptions extends BaseRequestOptions { +interface PutAuthRequestOptions extends BaseRequestOptions { token: string | null; - data?: any; + data?: D; logoutUser: (value?: string | undefined) => void; } -interface PostRequestOptions extends BaseRequestOptions { - data: any; +interface PostRequestOptions extends BaseRequestOptions { + data: D; } interface GetRequestOptions extends BaseRequestOptions { queryParams?: { [key: string]: string }; @@ -171,14 +171,14 @@ export function getAuthenticatedRequest({ }); } -export function postAuthenticatedRequest({ +export function postAuthenticatedRequest({ tenant, url, data, token, logoutUser, headers, -}: PostAuthRequestOptions) { +}: PostAuthRequestOptions) { const lang = localStorage.getItem('language') || 'en'; return new Promise((resolve, reject) => { (async () => { @@ -221,7 +221,11 @@ export function postAuthenticatedRequest({ }); } -export function postRequest({ tenant, url, data }: PostRequestOptions) { +export function postRequest({ + tenant, + url, + data, +}: PostRequestOptions) { const lang = localStorage.getItem('language') || 'en'; return new Promise((resolve, reject) => { (async () => { @@ -299,13 +303,13 @@ export function deleteAuthenticatedRequest({ }); } -export function putAuthenticatedRequest({ +export function putAuthenticatedRequest({ tenant, url, data, token, logoutUser, -}: PutAuthRequestOptions) { +}: PutAuthRequestOptions) { return new Promise((resolve, reject) => { const lang = localStorage.getItem('language') || 'en'; (async () => {