Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tax receipt/verification page #2378

Open
wants to merge 23 commits into
base: feature/tax-receipt
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3013443
feat: add DonationReceipt page
sunilsabatp Jan 21, 2025
e75accc
feat(UI): add DonationReceiptLayout component with header, data, and …
sunilsabatp Jan 21, 2025
0d08f4e
feat: implement DonationData component for displaying donation record…
sunilsabatp Jan 22, 2025
3329fc0
feat(UI): implement RecipientDetails component for displaying recipie…
sunilsabatp Jan 22, 2025
784e637
feat(UI) : add ReceiptActions(button's) component
sunilsabatp Jan 22, 2025
e28cf6d
fix: minor ui adjustment for mobile view
sunilsabatp Jan 22, 2025
4fd7bb5
feat(UI) : Introduce conditional logic to display a download button …
sunilsabatp Jan 22, 2025
c5fa70c
refactor: rename component to ReceiptListRedirect
sunilsabatp Jan 22, 2025
25dda11
feat(context): Add DonationReceiptContext with provider and custom hook
sunilsabatp Jan 23, 2025
acd07ad
feat(API) : fetch and update donation receipt data based on query par…
sunilsabatp Jan 23, 2025
3aba0e9
refactor: refactor receipt verification page
sunilsabatp Jan 24, 2025
48cef18
feat: change download button to link element with href for direct fil…
sunilsabatp Jan 24, 2025
adc116b
refactor: use verificationDate condition to render download button
sunilsabatp Jan 25, 2025
b39983b
feat: refactor ReceiptData handling and update DonationReceipt compon…
sunilsabatp Jan 27, 2025
b5ef8b2
feat: Implement `putRequest` function
sunilsabatp Jan 27, 2025
21360ae
refactor: move confirmDonorData logic from ReceiptActions to ReceiptD…
sunilsabatp Jan 27, 2025
51bc65b
refactor: rename recipientDetails to donorDetails
sunilsabatp Jan 27, 2025
60e1711
feat: add reusable SCSS mixin for flexible layout management
sunilsabatp Jan 28, 2025
fc5d5d4
refactor: replace donation term with donor
sunilsabatp Jan 28, 2025
9c6b64e
refactor : change the folder name to donor receipt
sunilsabatp Jan 28, 2025
188dcf9
feat(ui): right-align download button for mobile version
sunilsabatp Jan 28, 2025
98f0051
refactor: create a file to store donor receipt type
sunilsabatp Jan 28, 2025
4b7ba7d
feat(ui): minor padding adjustment for mobile view
sunilsabatp Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions pages/sites/[slug]/[locale]/verify-receipt-data.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import type {
GetStaticPaths,
GetStaticProps,
GetStaticPropsContext,
GetStaticPropsResult,
} from 'next';
import type { AbstractIntlMessages } from 'next-intl';
import type { Tenant } from '@planet-sdk/common/build/types/tenant';

import { useEffect } from 'react';
import { useRouter } from 'next/router';
import {
constructPathsForTenantSlug,
getTenantConfig,
} from '../../../../src/utils/multiTenancy/helpers';
import getMessagesForPage from '../../../../src/utils/language/getMessagesForPage';
import { defaultTenant } from '../../../../tenant.config';
import { useTenant } from '../../../../src/features/common/Layout/TenantContext';
import DonorReceiptLayout from '../../../../src/features/user/DonorReceipt/DonorReceiptLayout';
import { DonorReceiptProvider } from '../../../../src/features/common/Layout/DonorReceiptContext';

interface PageProps {
messages: AbstractIntlMessages;
tenantConfig: Tenant;
}

interface Props {
pageProps: PageProps;
}

export default function DonationReceipt({
pageProps: { tenantConfig },
}: Props) {
const router = useRouter();
const { setTenantConfig } = useTenant();

useEffect(() => {
if (router.isReady) setTenantConfig(tenantConfig);
}, [router.isReady]);

return (
<DonorReceiptProvider>
<DonorReceiptLayout />
</DonorReceiptProvider>
);
}

export const getStaticPaths: GetStaticPaths = async () => {
const subDomainPaths = await constructPathsForTenantSlug();

const paths =
subDomainPaths?.map((path) => {
return {
params: {
slug: path.params.slug,
locale: 'en',
},
};
}) ?? [];

return {
paths,
fallback: 'blocking',
};
};

export const getStaticProps: GetStaticProps<PageProps> = async (
context: GetStaticPropsContext
): Promise<GetStaticPropsResult<PageProps>> => {
const tenantConfig =
(await getTenantConfig(context.params?.slug as string)) ?? defaultTenant;

const messages = await getMessagesForPage({
locale: context.params?.locale as string,
filenames: ['common', 'me', 'country', 'donate'],
});

return {
props: {
messages,
tenantConfig,
},
};
};
17 changes: 16 additions & 1 deletion public/static/locales/en/donate.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@
"projectType": "Project Type",
"restoration": "Restoration",
"filters": "Filters",
"perM2": "per m²"
"perM2": "per m²",
"donationReceipt": {
"verifyTaxHeaderPrimary": "Verify your data to download tax receipt",
"verifyTaxHeaderSecondary": "once the data is verified, it can not be changed again for this receipt",
"downloadTaxReceipt": "Download tax receipt",
"referenceNumber": "Reference Number",
"amountDonated": "Amount Donated",
"paymentDate": "Payment Date",
"recipientInfoHeader": "Receipt will be issued to",
"taxIdentificationNumber": "Tax Identification Number (TIN)",
"modifyContactInformation": "Modify Contact Information",
"confirm": "Confirm",
"download": "Download",
"donationAmount": "{currency, select, EUR {€} USD {$} other {}} {amount}",
"name": "{type, select, individual {Name} organization {Company Name} other {}}"
}
}
}
54 changes: 54 additions & 0 deletions src/features/common/Layout/DonorReceiptContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { FC } from 'react';
import type {
ReceiptData,
ReceiptDataAPI,
} from '../../user/DonorReceipt/donorReceipt';

import { useMemo, useState, createContext, useContext } from 'react';
import { formatReceiptData } from '../../user/DonorReceipt/utils';

interface DonorReceiptContextInterface {
donorReceiptData: ReceiptData | null;
updateDonorReceiptData: (data: Partial<ReceiptDataAPI>) => void;
}

const DonorReceiptContext = createContext<DonorReceiptContextInterface | null>(
null
);

export const DonorReceiptProvider: FC = ({ children }) => {
const [donorReceiptData, setDonorReceiptData] = useState<ReceiptData | null>(
null
);

const updateDonorReceiptData = (data: Partial<ReceiptDataAPI>) => {
const formattedData = formatReceiptData(data);
setDonorReceiptData((prevState) => ({
...prevState,
...formattedData,
}));
};

const value: DonorReceiptContextInterface = useMemo(
() => ({
donorReceiptData,
updateDonorReceiptData,
}),
[updateDonorReceiptData, donorReceiptData]
);

return (
<DonorReceiptContext.Provider value={value}>
{children}
</DonorReceiptContext.Provider>
);
};

export const useDonorReceipt = (): DonorReceiptContextInterface => {
const context = useContext(DonorReceiptContext);
if (!context)
throw new Error(
'DonorReceiptContext must be used within DonorReceiptProvider'
);
return context;
};
74 changes: 74 additions & 0 deletions src/features/user/DonorReceipt/DonorReceiptLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { ReceiptDataAPI } from './donorReceipt';
import type { APIError } from '@planet-sdk/common';

import { useContext, useEffect, useState } from 'react';
import { handleError } from '@planet-sdk/common';
import Skeleton from 'react-loading-skeleton';
import 'react-loading-skeleton/dist/skeleton.css';
import { useRouter } from 'next/router';
import { useDonorReceipt } from '../../common/Layout/DonorReceiptContext';
import styles from './donationReceipt.module.scss';
import ReceiptDataSection from './microComponents/ReceiptDataSection';
import ReceiptVerificationHeader from './microComponents/ReceiptVerificationHeader';
import ReceiptListRedirect from './microComponents/ReceiptListRedirect';
import { useTenant } from '../../common/Layout/TenantContext';
import { getRequest } from '../../../utils/apiRequests/api';
import { ErrorHandlingContext } from '../../common/Layout/ErrorHandlingContext';

export const DonorReceiptLayout = () => {
const [isLoading, setIsLoading] = useState(false);
const { tenantConfig } = useTenant();
const { setErrors, redirect } = useContext(ErrorHandlingContext);
const router = useRouter();
const { dtn, year, challenge } = router.query;
const { updateDonorReceiptData, donorReceiptData } = useDonorReceipt();
const showReceipt = !isLoading && donorReceiptData !== null;

useEffect(() => {
if (!(dtn || year || challenge || router.isReady)) return;
if (
typeof dtn !== 'string' ||
typeof year !== 'string' ||
typeof challenge !== 'string'
)
return;
const fetchReceiptData = async () => {
setIsLoading(true);
try {
const data = await getRequest<ReceiptDataAPI>({
tenant: tenantConfig.id,
url: '/app/donationReceipt',
queryParams: {
dtn,
year,
challenge,
},
});
if (data) updateDonorReceiptData(data);
} catch (err) {
setErrors(handleError(err as APIError));
redirect('/');
} finally {
setIsLoading(false);
}
};

fetchReceiptData();
}, [dtn, year, challenge, router.isReady]);

return showReceipt ? (
<div className={styles.donorReceiptLayout}>
<div className={styles.donorReceiptContainer}>
<ReceiptVerificationHeader operation={donorReceiptData.operation} />
<ReceiptDataSection donorReceiptData={donorReceiptData} />
<ReceiptListRedirect />
</div>
</div>
) : (
<div className={styles.donorReceiptSkeleton}>
<Skeleton height={700} width={760} />
</div>
);
};

export default DonorReceiptLayout;
Loading