Skip to content

Commit 7604f9a

Browse files
feat: show direct donations on donation history page (#3568)
* feat: check if user chain id is same as project chainid when donating * feat: add switchNetwork modal * fix: tests * feat: show direct donations in donation history page * feat: getDonationsByDonorAddress query * chore: update tests * feat: update donation table ui * feat: update direct donations table
1 parent f10db35 commit 7604f9a

File tree

13 files changed

+402
-101
lines changed

13 files changed

+402
-101
lines changed

packages/common/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ export type RoundPayoutTypeNew =
347347
| "allov2.MicroGrantsGovStrategy"
348348
| "allov2.DirectGrantsSimpleStrategy"
349349
| "allov2.DirectGrantsLiteStrategy"
350+
| "allov2.DirectAllocationStrategy"
350351
| ""; // This is to handle the cases where the strategyName is not set in a round, mostly spam rounds
351352

352353
export type RoundStrategyType = "QuadraticFunding" | "DirectGrants";

packages/data-layer/src/data-layer.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,9 +792,17 @@ export class DataLayer {
792792
);
793793

794794
return response.donations.filter((donation) => {
795-
return (
796-
donation.application !== null && donation.application?.project !== null
797-
);
795+
if (donation.round.strategyName !== "allov2.DirectAllocationStrategy") {
796+
return (
797+
donation.application !== null &&
798+
donation.application?.project !== null
799+
);
800+
} else {
801+
return (
802+
// DirectAllocationStrategy donations are not linked to applications
803+
donation.application === null
804+
);
805+
}
798806
});
799807
}
800808

packages/data-layer/src/data.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type RoundPayoutType =
77
| "allov2.DirectGrantsSimpleStrategy"
88
| "allov2.DirectGrantsLiteStrategy"
99
| "allov2.DonationVotingMerkleDistributionDirectTransferStrategy"
10+
| "allov2.DirectAllocationStrategy"
1011
| ""; // This is to handle the cases where the strategyName is not set in a round, mostly spam rounds
1112
export type RoundVisibilityType = "public" | "private";
1213

@@ -772,6 +773,7 @@ export type Contribution = {
772773
roundMetadata: RoundMetadata;
773774
donationsStartTime: string;
774775
donationsEndTime: string;
776+
strategyName: RoundPayoutType;
775777
};
776778
application: {
777779
project: {

packages/data-layer/src/queries.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,7 @@ export const getDonationsByDonorAddress = gql`
801801
roundMetadata
802802
donationsStartTime
803803
donationsEndTime
804+
strategyName
804805
}
805806
application {
806807
project: canonicalProject {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// --- Chakra Elements
2+
import {
3+
Modal,
4+
ModalOverlay,
5+
ModalContent,
6+
ModalHeader,
7+
ModalCloseButton,
8+
ModalBody,
9+
} from "@chakra-ui/react";
10+
11+
export type ToggleModalProps = {
12+
isOpen: boolean;
13+
onClose: () => void;
14+
};
15+
16+
export type BaseModalProps = ToggleModalProps & {
17+
children?: JSX.Element;
18+
title?: string;
19+
size?: string;
20+
footer?: JSX.Element;
21+
closeOnOverlayClick?: boolean;
22+
hideCloseButton?: boolean;
23+
};
24+
25+
export function BaseModal({
26+
isOpen,
27+
onClose,
28+
children,
29+
size,
30+
title,
31+
footer,
32+
closeOnOverlayClick,
33+
hideCloseButton,
34+
}: BaseModalProps): JSX.Element {
35+
return (
36+
<Modal
37+
isOpen={isOpen}
38+
onClose={onClose}
39+
closeOnOverlayClick={closeOnOverlayClick ?? true}
40+
size={size || "xl"}
41+
isCentered
42+
>
43+
<ModalOverlay />
44+
<ModalContent>
45+
<>
46+
{title && (
47+
<ModalHeader px={8} pb={1} pt={6}>
48+
{title}
49+
</ModalHeader>
50+
)}
51+
{(hideCloseButton === undefined || hideCloseButton === false) && (
52+
<ModalCloseButton mr={2} />
53+
)}
54+
<ModalBody p={0}>
55+
<div className="p-6">
56+
{/* RSX Element passed in to show desired stamp output */}
57+
{children}
58+
</div>
59+
</ModalBody>
60+
61+
{footer && <div>{footer}</div>}
62+
</>
63+
</ModalContent>
64+
</Modal>
65+
);
66+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { useNavigate } from "react-router-dom";
2+
3+
export enum ButtonVariants {
4+
primary = "primary",
5+
secondary = "secondary",
6+
outline = "outline",
7+
danger = "danger",
8+
outlineDanger = "danger-outline",
9+
}
10+
11+
interface ButtonProps {
12+
onClick?: () => void;
13+
path?: string;
14+
children: React.ReactNode;
15+
variant: ButtonVariants;
16+
disabled?: boolean;
17+
styles?: string[];
18+
dataTrackEvent?: string;
19+
}
20+
21+
function Button({
22+
onClick,
23+
path,
24+
children,
25+
variant,
26+
disabled,
27+
styles,
28+
dataTrackEvent,
29+
}: ButtonProps) {
30+
const navigate = useNavigate();
31+
32+
const clickHandler = () => {
33+
if (onClick === undefined && path !== undefined) {
34+
navigate(path);
35+
}
36+
if (onClick) onClick();
37+
};
38+
39+
return (
40+
<button
41+
disabled={disabled}
42+
onClick={clickHandler}
43+
className={`base-btn ${variant} ${styles?.join(" ")}`}
44+
type="button"
45+
data-track-event={dataTrackEvent}
46+
>
47+
{children}
48+
</button>
49+
);
50+
}
51+
52+
export default Button;
Lines changed: 52 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,60 @@
1-
import { Dialog, Transition } from "@headlessui/react";
2-
import { Button } from "common/src/styles";
3-
import React, { Fragment, ReactNode, useRef } from "react";
1+
import { BaseModal } from "./BaseModal";
2+
import Button, { ButtonVariants } from "./Button";
43

5-
interface ModalProps {
6-
title?: string;
7-
body?: JSX.Element;
8-
confirmButtonText?: string;
4+
function SwitchNetworkModal({
5+
networkName,
6+
onSwitchNetwork,
7+
action,
8+
isOpen,
9+
setIsOpen,
10+
}: {
11+
networkName: string;
12+
onSwitchNetwork: () => void;
13+
action?: string;
914
isOpen: boolean;
1015
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
11-
confirmButtonAction: () => void;
12-
cancelButtonAction?: () => void;
13-
children?: ReactNode;
14-
}
15-
16-
export default function SwitchNetworkModal({
17-
title = "Please Confirm Decision",
18-
isOpen = false,
19-
setIsOpen = () => {
20-
/**/
21-
},
22-
confirmButtonText = "Confirm",
23-
cancelButtonAction = () => setIsOpen(false),
24-
children,
25-
...props
26-
}: ModalProps) {
27-
const cancelButtonRef = useRef(null);
28-
16+
}) {
2917
return (
30-
<Transition.Root show={isOpen} as={Fragment}>
31-
<Dialog
32-
as="div"
33-
className="relative z-10"
34-
initialFocus={cancelButtonRef}
35-
onClose={setIsOpen}
36-
data-testid="confirm-modal"
37-
>
38-
<Transition.Child
39-
as={Fragment}
40-
enter="ease-out duration-300"
41-
enterFrom="opacity-0"
42-
enterTo="opacity-100"
43-
leave="ease-in duration-200"
44-
leaveFrom="opacity-100"
45-
leaveTo="opacity-0"
46-
>
47-
<div className="fixed inset-0 bg-grey-400 bg-opacity-75 transition-opacity" />
48-
</Transition.Child>
49-
50-
<div className="fixed z-10 inset-0 overflow-y-auto">
51-
<div className="flex items-end sm:items-center justify-center min-h-full p-4 text-center sm:p-0">
52-
<Transition.Child
53-
as={Fragment}
54-
enter="ease-out duration-300"
55-
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
56-
enterTo="opacity-100 translate-y-0 sm:scale-100"
57-
leave="ease-in duration-200"
58-
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
59-
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
60-
>
61-
<Dialog.Panel className="relative bg-white px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:max-w-md sm:w-full sm:p-6">
62-
<div className="sm:items-start">
63-
<div className="mt-3 text-center sm:mt-0 sm:text-left">
64-
<Dialog.Title
65-
as="h3"
66-
className="text-base leading-6 font-semibold text-grey-500"
67-
>
68-
{title}
69-
</Dialog.Title>
70-
<div className="mt-2">{props.body}</div>
71-
</div>
72-
</div>
73-
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
74-
<Button
75-
type="button"
76-
className="w-full inline-flex text-sm sm:ml-3 sm:w-auto"
77-
onClick={props.confirmButtonAction}
78-
data-testid={"confirm-continue"}
79-
>
80-
{confirmButtonText}
81-
</Button>
82-
<Button
83-
type="button"
84-
$variant="outline"
85-
className="w-full inline-flex text-sm sm:ml-3 sm:w-auto"
86-
onClick={cancelButtonAction}
87-
ref={cancelButtonRef}
88-
data-testid={"confirm-cancel"}
89-
>
90-
Cancel
91-
</Button>
92-
</div>
93-
</Dialog.Panel>
94-
</Transition.Child>
18+
// eslint-disable-next-line @typescript-eslint/no-empty-function
19+
<BaseModal isOpen={isOpen} onClose={() => {}} hideCloseButton>
20+
<>
21+
<div data-testid="switch-networks-modal" className="flex">
22+
<div className="text-center">
23+
<div data-testid="switch-networks-modal-title">
24+
<p className="text-primary-text text-[18px] flex justify-center p-2">
25+
Switch Networks to Continue
26+
</p>
27+
<p className="text-gitcoin-grey-400 text-[16px] flex justify-center p-2">
28+
To {action || "donate"}, you need to switch the network on your
29+
wallet to {networkName}.
30+
</p>
31+
</div>
9532
</div>
9633
</div>
97-
{children}
98-
</Dialog>
99-
</Transition.Root>
34+
<div
35+
data-testid="switch-networks-modal-button"
36+
className="w-full justify-center text-center grid grid-cols-2 gap-3"
37+
>
38+
<Button
39+
variant={ButtonVariants.outline}
40+
onClick={() => setIsOpen(false)}
41+
styles={["cancel-button"]}
42+
>
43+
<span className="inline-flex flex-1 justify-center items-center">
44+
Cancel
45+
</span>
46+
</Button>
47+
<Button
48+
styles={["p-3", "justify-center"]}
49+
onClick={onSwitchNetwork}
50+
variant={ButtonVariants.outline}
51+
>
52+
Switch Network
53+
</Button>
54+
</div>
55+
</>
56+
</BaseModal>
10057
);
10158
}
59+
60+
export default SwitchNetworkModal;

0 commit comments

Comments
 (0)