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

Allow the user to create recurring donations per campaign #1243

Merged
merged 9 commits into from
Jan 8, 2023
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@

## Initial setup

# for Ubuntu users:

# make sure cmdtest is not installed, it has a different yarn command

# for installing node.js: https://github.com/nodesource/distributions

# if you have newer node version, you can use this to downgrade:

# > sudo npm install -g n

# > sudo n stable

```shell
git clone [email protected]:podkrepi-bg/frontend.git
cd frontend
Expand Down
3 changes: 2 additions & 1 deletion public/locales/bg/one-time-donation.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
"owner": "Сдружение Подкрепи БГ",
"bank": "Уникредит Булбанк",
"reason-donation": "Като основание за превод въведете:",
"message-warning": "Ако не въведете точно основанието, може да не успеем да разпределим парите към предназначената кампания."
"message-warning": "Ако не въведете точно основанието, може да не успеем да разпределим парите към предназначената кампания.",
"recurring-donation": "Дарявай повторно всеки месец тази сума до края на кампанията! Може да се откажете по всяко време."
},
"alerts": {
"success": "Дарението е направено успешно!",
Expand Down
21 changes: 18 additions & 3 deletions public/locales/bg/recurring-donation.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,41 @@
"edit-form-heading": "Редактирай",
"recurring-donations": "Всички повтарящи се дарения",
"recurring-donation": "Повтарящи се дарения",
"extSubscriptionId": "Абонамент",
"extSubscriptionId": "Външен абонамент",
"extCustomerId": "ID на клиент",
"campaign": "Кампания",
"currency": "Валута",
"amount": "Налични средства",
"amount": "Сума",
"status": "Статус",
"startDate": "Начална дата",
"personId": "ID на потребител",
"person": "Потребител",
"vaultId": "ID на трезор",
"vault": "Трезор",
"deleteTitle": "Сигурни ли сте?",
"deleteContent": "Това действие ще изтрие елемента завинаги!",
"actions": "Действия",
"alerts": {
"create": "Записът беше създаден успешно!",
"edit": "Записът беше редактиран успешно!",
"delete": "Записът беше изтрит успешно!",
"cancel": "Дарението беше отказано!",
"cancel-confirm": "Сигурни ли сте, че искате да откажете дарението?",
"error": "Възникна грешка! Моля опитайте отново по-късно."
},
"statuses": {
"active": "Активно",
"incomplete": "Непълно",
"incompleteExpired": "Непълно/изтекло",
"pastDue": "Изтекло",
"canceled": "Отказано",
"trailing": "Изоставащо",
"unpaid": "Неплатено"
},
"cta": {
"add": "Добави",
"confirm": "Потвърди",
"cancel": "Отказ",
"cancel": "Откажи",
"delete": "Изтрий",
"edit": "Редактирай",
"details": "Детайли",
Expand Down
3 changes: 2 additions & 1 deletion public/locales/en/one-time-donation.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
"owner": "Association Podkrepi BG",
"bank": "Unicredit Bulbank",
"reason-donation": "For payment reference use:",
"message-warning": "If you don't enter the exact reference we may not be able to assign the money to the desired campaign."
"message-warning": "If you don't enter the exact reference we may not be able to assign the money to the desired campaign.",
"recurring-donation": "Donate the same amount every month until the end of the campaign! Cancel anytime."
},
"alerts": {
"success": "Donation was processed successfully!",
Expand Down
45 changes: 45 additions & 0 deletions public/locales/en/recurring-donation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"form-heading": "Add",
"edit-form-heading": "Edit",
"recurring-donations": "All recurring donations",
"recurring-donation": "Recurring donations",
"extSubscriptionId": "External subscription ID",
"extCustomerId": "External customer ID",
"campaign": "Campaign",
"currency": "Currency",
"amount": "Amount",
"status": "Status",
"startDate": "Start date",
"personId": "Person ID",
"person": "Person",
"vaultId": "Vault ID",
"vault": "Vault",
"deleteTitle": "Are you sure?",
"deleteContent": "Are you sure you want to delete this recurring donation?",
"actions": "Actions",
"alerts": {
"create": "Recurring donation created successfully",
"edit": "Recurring donation edited successfully",
"delete": "Recurring donation deleted successfully",
"cancel": "Recurring donation cancelled successfully",
"error": "Error while processing your request. Please try again later."
},
"statuses": {
"active": "Active",
"incomplete": "Incomplete",
"incompleteExpired": "Expired",
"pastDue": "Past due",
"canceled": "Canceled",
"trailing": "Trailing",
"unpaid": "Unpaid"
},
"cta": {
"add": "Add",
"confirm": "Confirm",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"details": "Details",
"submit": "Submit"
}
}
2 changes: 1 addition & 1 deletion src/common/hooks/campaigns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function useCampaignAdminList() {
export const useGetUserCampaigns = () => {
const { data: session } = useSession()
return useQuery<AdminCampaignResponse[]>(
[endpoints.campaign.getUserCamapaigns.url],
[endpoints.campaign.getUserDonatedToCampaigns.url],
authQueryFnFactory<AdminCampaignResponse[]>(session?.accessToken),
)
}
Expand Down
4 changes: 1 addition & 3 deletions src/common/hooks/donation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ export function usePriceList() {
export function useSinglePriceList() {
return useQuery<DonationPrice[]>([endpoints.donation.singlePrices.url])
}
export function useRecurringPriceList() {
return useQuery<DonationPrice[]>([endpoints.donation.recurringPrices.url])
}

export function useDonationSession() {
const { t } = useTranslation()
const mutation = useMutation<
Expand Down
20 changes: 14 additions & 6 deletions src/common/hooks/recurringDonation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,27 @@ import { endpoints } from 'service/apiEndpoints'
import { authQueryFnFactory } from 'service/restRequests'
import { RecurringDonationResponse } from 'gql/recurring-donation'

export function useRecurringDonationList() {
export function useRecurringDonation(id: string) {
const { data: session } = useSession()
return useQuery<RecurringDonationResponse>(
[endpoints.recurringDonation.getRecurringDonation(id).url],
authQueryFnFactory<RecurringDonationResponse>(session?.accessToken),
)
}

export const useAllRecurringDonations = () => {
const { data: session } = useSession()
return useQuery<RecurringDonationResponse[]>(
[endpoints.recurringDonation.recurringDonation.url],
[endpoints.recurringDonation.list.url],
authQueryFnFactory<RecurringDonationResponse[]>(session?.accessToken),
)
}

export function useRecurringDonation(id: string) {
export const useGetUserRecurringDonations = () => {
const { data: session } = useSession()
return useQuery<RecurringDonationResponse>(
[endpoints.recurringDonation.getRecurringDonation(id).url],
authQueryFnFactory<RecurringDonationResponse>(session?.accessToken),
return useQuery<RecurringDonationResponse[]>(
[endpoints.recurringDonation.getUserRecurringDonations.url],
authQueryFnFactory<RecurringDonationResponse[]>(session?.accessToken),
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/admin/navigation/adminMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const menuPayments = [
{ label: 'Прехвърляния', icon: MoveUp, href: routes.admin.transfer.index },
{ label: 'Разходи', icon: Paid, href: routes.admin.expenses.index },
{
label: 'Повтарящо се дарение',
label: 'Повтарящи се дарения',
icon: VolunteerActivism,
href: routes.admin.recurringDonation.index,
},
Expand Down
26 changes: 25 additions & 1 deletion src/components/auth/profile/DonationTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import { useTranslation } from 'next-i18next'
import { moneyPublic } from 'common/util/money'
import { useUserDonations } from 'common/hooks/donation'
import { getCurrentPerson } from 'common/util/useCurrentPerson'
import { useGetUserRecurringDonations } from 'common/hooks/recurringDonation'
import { useRouter } from 'next/router'

import { ProfileTabs } from './tabs'
import ProfileTab from './ProfileTab'
import DonationTable from './DonationTable'
import { DonationStatus, PaymentProvider } from 'gql/donations.enums'
import { RecurringDonationStatus } from 'gql/recurring-donation-status.d'
import { RecurringDonationResponse } from 'gql/recurring-donation'
import MyRecurringCampaignsTable from './MyRecurringCampaignsTable'

const PREFIX = 'DonationTab'

Expand Down Expand Up @@ -75,16 +79,30 @@ const Root = styled('div')(({ theme }) => ({
},
}))

//Sum the active donations
function recurreningDonationsSum(donations: RecurringDonationResponse[] | undefined) {
slavcho marked this conversation as resolved.
Show resolved Hide resolved
slavcho marked this conversation as resolved.
Show resolved Hide resolved
if (!donations) {
return 0.0
}

return donations
.filter((donation) => donation.status === RecurringDonationStatus.active)
.reduce((sum, donation) => sum + donation.amount, 0.0)
}

export default function DonationTab() {
const router = useRouter()
const { t } = useTranslation()

const { data: user } = getCurrentPerson(!!router.query?.register)

if (router.query?.register) {
delete router.query.register
router.replace({ pathname: router.pathname, query: router.query }, undefined, { shallow: true })
}
const { data: userDonations, isLoading: isUserDonationLoading } = useUserDonations()
const { data: recurringDonations } = useGetUserRecurringDonations()

return (
<Root>
<Box className={classes.boxTitle}>
Expand Down Expand Up @@ -112,7 +130,7 @@ export default function DonationTab() {
{/* <Typography>Я, Ф, М, А 2022</Typography> */}
</Box>
<Typography fontWeight="medium" variant="h6">
0,00 лв.
{moneyPublic(recurreningDonationsSum(recurringDonations))}
</Typography>
</Box>
<Box className={classes.donationsBoxRow}>
Expand Down Expand Up @@ -162,6 +180,12 @@ export default function DonationTab() {
<ProfileTab name={ProfileTabs.donations}>
<DonationTable donations={userDonations?.donations} />
</ProfileTab>
<Box className={classes.boxTitle}>
<Typography className={classes.h3}>{t('profile:donations.recurringDonations')}</Typography>
</Box>
<ProfileTab name={ProfileTabs.myCampaigns}>
<MyRecurringCampaignsTable />
</ProfileTab>
</Root>
)
}
46 changes: 7 additions & 39 deletions src/components/auth/profile/DonationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,66 +36,34 @@ function DonationTable({ donations }: DonationTableProps) {
const { t, i18n } = useTranslation()
const [fromDate, setFromDate] = React.useState<Date | null>(null)
const [toDate, setToDate] = React.useState<Date | null>(null)
const [monthly, setMonthly] = React.useState(true)
const [oneTime, setOneTime] = React.useState(true)
const filteredByTypeDonations = useMemo(() => {
if (monthly && oneTime) {
return donations
}
if (!monthly && !oneTime) {
return []
}
if (monthly) {
return donations?.filter((d) => d.type !== 'donation')
}
if (oneTime) {
return donations?.filter((d) => d.type === 'donation')
}
return donations
}, [donations, monthly, oneTime])

const filteredDonations = useMemo(() => {
if (!fromDate && !toDate) {
return filteredByTypeDonations
return donations
}
if (fromDate && toDate) {
return filteredByTypeDonations?.filter((d) => {
return donations?.filter((d) => {
const createdAtDate = parseISO(d.createdAt)
return isAfter(createdAtDate, fromDate) && isBefore(createdAtDate, toDate)
})
}
if (fromDate) {
return filteredByTypeDonations?.filter((d) => {
return donations?.filter((d) => {
const createdAtDate = parseISO(d.createdAt)
return isAfter(createdAtDate, fromDate)
})
}
if (toDate) {
return filteredByTypeDonations?.filter((d) => {
return donations?.filter((d) => {
const createdAtDate = parseISO(d.createdAt)
return isBefore(createdAtDate, toDate)
})
}
}, [filteredByTypeDonations, fromDate, toDate])
}, [donations, fromDate, toDate])

return (
<Card sx={{ padding: theme.spacing(2), boxShadow: theme.shadows[0] }}>
<Grid container alignItems={'flex-start'} spacing={theme.spacing(2)}>
<Grid item xs={6} sm={3}>
<CheckboxLabel>{t('profile:donations.oneTime')}</CheckboxLabel>
<Checkbox
onChange={(e, checked) => setOneTime(checked)}
checked={oneTime}
name="oneTime"
/>
</Grid>
{/* TODO: pending implementation on recuring donations
<Grid item xs={6} sm={3}>
<CheckboxLabel>{t('profile:donations.monthly')}</CheckboxLabel>
<Checkbox
onChange={(e, checked) => setMonthly(checked)}
checked={monthly}
name="monthly"
/>
</Grid> */}
<LocalizationProvider
adapterLocale={i18n.language === 'bg' ? bg : enUS}
dateAdapter={AdapterDateFns}>
Expand Down
1 change: 1 addition & 0 deletions src/components/auth/profile/MyDonatedToCampaignsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default function MyDonatedToCampaignTable() {
width: 100,
headerAlign: 'left',
}

const columns: GridColumns = [
{
field: 'state',
Expand Down
Loading