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

feat(app): adding low score alert for onchain push #2802

Merged
merged 5 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 24 additions & 1 deletion app/__tests__/components/SyncToChainButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,34 @@ describe("SyncToChainButton component", () => {
},
<ChakraProvider>
<SyncToChainButton onChainStatus={OnChainStatus.NOT_MOVED} chain={chainWithEas} />
</ChakraProvider>
</ChakraProvider>,
{},
{ threshold: 10, rawScore: 20 }
);
const btn = screen.getByTestId("sync-to-chain-button");
fireEvent.click(btn);

await screen.findByText("Passport submitted to chain.");
});

it("should prompt user if score is low", async () => {
renderWithContext(
{
...mockCeramicContext,
passport: { ...mockCeramicContext.passport, stamps: [{ id: "test" } as any] },
},
<ChakraProvider>
<SyncToChainButton onChainStatus={OnChainStatus.NOT_MOVED} chain={chainWithEas} />
</ChakraProvider>,
{},
{ threshold: 15, rawScore: 10 }
);
const btn = screen.getByTestId("sync-to-chain-button");
fireEvent.click(btn);

await screen.findByText(
`While some benefits might be available with a lower score, many partners require a score of 15 or higher.`,
{ exact: false }
);
});
});
105 changes: 105 additions & 0 deletions app/components/ActionOrCancelModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from "react";
import { LoadButton } from "./LoadButton";
import { Button } from "./Button";
import { Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter } from "@chakra-ui/react";

// Modal with an action button and a cancel button
// Pass the body content as children
export const ActionOrCancelModal = ({
title,
buttonText,
onButtonClick,
buttonLoading,
buttonDisabled,
isOpen,
onClose,
children,
}: {
title: React.ReactNode;
buttonText: string;
onButtonClick: () => void;
isOpen: boolean;
onClose: () => void;
buttonLoading?: boolean;
buttonDisabled?: boolean;
children: React.ReactNode;
}) => {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay width="100%" height="100%" />
<ModalContent
rounded={"8px"}
padding={"28px"}
paddingBottom={"12px"}
maxW={"380px"}
border={"rgb(var(--color-foreground-5)) 1px solid"}
background={"linear-gradient(180deg, rgb(var(--color-background)) 0%, rgb(var(--color-foreground-5)) 100%)"}
>
<ModalHeader padding={0} fontWeight={"normal"} className="text-xl font-heading leading-tight text-focus my-4">
{title}
</ModalHeader>
<ModalBody padding={0}>{children}</ModalBody>
<ModalFooter padding={0} className="mt-8 flex font-medium flex-col items-center">
<LoadButton className="w-full" onClick={onButtonClick} isLoading={buttonLoading} disabled={buttonDisabled}>
{buttonText}
</LoadButton>
<Button variant="custom" className="mt-4 px-8" onClick={onClose}>
Cancel
</Button>
</ModalFooter>
</ModalContent>
</Modal>
// Headless UI version, doesn't work with Chakra modals
// <>
// <Transition appear show={isOpen} as={Fragment}>
// <Dialog as="div" className="relative z-100" onClose={onClose}>
// <Transition.Child
// enter="ease-out duration-300"
// enterFrom="opacity-0"
// enterTo="opacity-100"
// leave="ease-in duration-200"
// leaveFrom="opacity-100"
// leaveTo="opacity-0"
// >
// <Backdrop />
// </Transition.Child>

// <div className="fixed inset-0 overflow-y-auto">
// <div className="flex min-h-full items-center justify-center p-4 text-center">
// <Transition.Child
// as={Fragment}
// enter="ease-out duration-300"
// enterFrom="opacity-0 scale-95"
// enterTo="opacity-100 scale-100"
// leave="ease-in duration-200"
// leaveFrom="opacity-100 scale-100"
// leaveTo="opacity-0 scale-95"
// >
// <Dialog.Panel className="w-full max-w-sm overflow-hidden transition-all">
// <div className="p-7 text-base text-left text-color-1 align-middle w-full rounded-lg border border-foreground-5 bg-gradient-to-b from-background to-foreground-5">
// <Dialog.Title className="text-xl font-heading leading-tight text-focus my-4">{title}</Dialog.Title>
// <div>{children}</div>

// <div className="mt-4 flex font-medium flex-col items-center">
// <LoadButton
// className="w-full"
// onClick={onButtonClick}
// isLoading={buttonLoading}
// disabled={buttonDisabled}
// >
// {buttonText}
// </LoadButton>
// <Button variant="custom" className="mt-4 px-8" onClick={onClose}>
// Cancel
// </Button>
// </div>
// </div>
// </Dialog.Panel>
// </Transition.Child>
// </div>
// </div>
// </Dialog>
// </Transition>
// </>
);
};
1 change: 1 addition & 0 deletions app/components/CustomDashboardPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const DynamicCustomDashboardPanel = ({ className }: { className: string }
window.open(body.action.url, "_blank");
}
};

return (
<CustomDashboardPanel className={className} logo={logo}>
{body.displayInfoTooltip && body.displayInfoTooltip.shouldDisplay && body.displayInfoTooltip.text ? (
Expand Down
27 changes: 27 additions & 0 deletions app/components/LowScoreAlertModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import { ActionOrCancelModal } from "../components/ActionOrCancelModal";

export const LowScoreAlertModal = ({
isOpen,
onProceed,
onCancel,
threshold,
}: {
isOpen: boolean;
onProceed: () => void;
onCancel: () => void;
threshold: number;
}) => (
<ActionOrCancelModal
title="Try building up a higher score?"
buttonText="Proceed with mint"
isOpen={isOpen}
onButtonClick={onProceed}
onClose={onCancel}
>
While some benefits might be available with a lower score, many partners require a score of {threshold} or higher.
<br />
<br />
Do you still wish to proceed?
</ActionOrCancelModal>
);
9 changes: 4 additions & 5 deletions app/components/PlatformDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const PlatformJsonButton = ({
const { handleDeleteStamps } = useContext(CeramicContext);
const customization = useCustomization();
const [stampDetailsModal, setStampDetailsModal] = useState(false);
const [removeStampModal, setRemoveStampModal] = useState(false);
const [showRemoveStampModal, setShowRemoveStampModal] = useState(false);
const [referenceElement, setReferenceElement] = useState(null);

const providerIds = getStampProviderIds(platform.platform, customStampProviders(customization));
Expand Down Expand Up @@ -62,7 +62,7 @@ const PlatformJsonButton = ({
<button onClick={() => setStampDetailsModal(true)} className="w-full text-left">
Stamp Details
</button>
<button className="w-full text-left text-color-7" onClick={() => setRemoveStampModal(true)}>
<button className="w-full text-left text-color-7" onClick={() => setShowRemoveStampModal(true)}>
Remove Stamp
</button>
</Popover.Panel>
Expand All @@ -77,13 +77,12 @@ const PlatformJsonButton = ({
jsonOutput={platformPassportData}
/>
<RemoveStampModal
isOpen={removeStampModal}
onClose={onClose}
isOpen={showRemoveStampModal}
onClose={() => setShowRemoveStampModal(false)}
title={`Remove ${platform.name} Stamp`}
body={"This stamp will be removed from your Passport. You can still re-verify your stamp in the future."}
stampsToBeDeleted={providerIds}
handleDeleteStamps={onRemoveStamps}
platformId={platform.name as PLATFORM_ID}
/>
</>
);
Expand Down
57 changes: 12 additions & 45 deletions app/components/RemoveStampModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,29 @@
import React, { useState } from "react";

// --- Chakra Elements
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
useToast,
} from "@chakra-ui/react";
import { useToast } from "@chakra-ui/react";
import { PLATFORM_ID, PROVIDER_ID } from "@gitcoin/passport-types";
import { Button } from "./Button";
import { LoadButton } from "./LoadButton";

// --- Style Components
import { DoneToastContent } from "./DoneToastContent";
import { ActionOrCancelModal } from "./ActionOrCancelModal";

export type RemoveStampModalProps = {
isOpen: boolean;
onClose: () => void;
title: string;
body: string;
closeButtonText?: string;
stampsToBeDeleted?: PROVIDER_ID[];
handleDeleteStamps: Function;
platformId: PLATFORM_ID;
};

export const RemoveStampModal = ({
isOpen,
onClose,
title,
body,
closeButtonText,
stampsToBeDeleted,
handleDeleteStamps,
platformId,
}: RemoveStampModalProps): JSX.Element => {
const [isLoading, setIsLoading] = useState(false);
const toast = useToast();
Expand Down Expand Up @@ -78,35 +65,15 @@ export const RemoveStampModal = ({
};

return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay width="100%" height="100%" />
<ModalContent
rounded={"none"}
padding={5}
maxW={{
sm: "100%",
md: "600px",
}}
maxH="80%"
>
<ModalHeader>
<img alt="shield alert" src="../assets/shield-alert.svg" className="m-auto mb-4 w-10" />
<p className="text-center">{title}</p>
</ModalHeader>
<ModalCloseButton />
<ModalBody color="#757087" className="mb-10 overflow-auto text-center">
{body}
</ModalBody>

<div className="grid grid-cols-2 gap-4">
<Button data-testid="button-stamp-removal-cancel" variant="secondary" onClick={onClose}>
Cancel
</Button>
<LoadButton data-testid="button-stamp-removal" onClick={handleStampRemoval} isLoading={isLoading}>
{isLoading ? "Removing..." : closeButtonText || "Remove Stamp"}
</LoadButton>
</div>
</ModalContent>
</Modal>
<ActionOrCancelModal
title={title}
buttonText={isLoading ? "Removing..." : "Remove Stamp"}
onButtonClick={handleStampRemoval}
isOpen={isOpen}
onClose={onClose}
buttonLoading={isLoading}
>
{body}
</ActionOrCancelModal>
);
};
3 changes: 0 additions & 3 deletions app/components/SideBarContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import { PLATFORM_ID, PROVIDER_ID } from "@gitcoin/passport-types";
import { StampSelector } from "./StampSelector";
import { PlatformDetails } from "./PlatformDetails";
import { PlatformScoreSpec } from "../context/scorerContext";
import { RemoveStampModal } from "./RemoveStampModal";
import { STAMP_PROVIDERS } from "../config/providers";
import { CeramicContext } from "../context/ceramicContext";

export type SideBarContentProps = {
currentPlatform: PlatformScoreSpec | undefined;
Expand Down
Loading
Loading