Skip to content

Commit

Permalink
1683 imporved stamp card (passportxyz#1706)
Browse files Browse the repository at this point in the history
* feat(app): style default view of new card

* fix(app): prettier fixes

* feat(app): styled default card state

* fix(app): prettier fix class sorting

* feat(app): wip styling scored stamp

* feat(app): style verified state for card

* feat(app): sort cards based on verification status

* feat(app): show possible and points earned

* feat(app): sorting cards by possible and earned points

* feat(app): loading state

* chore(app): test and clean up PlatformCard and Cardlist

* fix(app): rgb hover effect on boxShadow

* fix(app): set default values for scored points and fix tests

* fix(app): update score logic for build
  • Loading branch information
tim-schultz authored Sep 23, 2023
1 parent 73638d1 commit 3e001e8
Show file tree
Hide file tree
Showing 21 changed files with 306 additions and 161 deletions.
62 changes: 59 additions & 3 deletions app/__test-fixtures__/contextTestHelpers.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { UserContext, UserContextState } from "../context/userContext";
import { ScorerContext, ScorerContextState } from "../context/scorerContext";
import { CeramicContext, CeramicContextState, IsLoadingPassportState } from "../context/ceramicContext";
import { ProviderSpec, STAMP_PROVIDERS } from "../config/providers";
import { mockAddress, mockWallet } from "./onboardHookValues";
Expand Down Expand Up @@ -144,15 +145,70 @@ export const makeTestCeramicContext = (initialState?: Partial<CeramicContextStat
};
};

export const scorerContext = {
scoredPlatforms: [
{
icon: "./assets/gtcStakingLogoIcon.svg",
platform: "GtcStaking",
name: "GTC Staking",
description: "Connect to passport to verify your staking amount.",
connectMessage: "Verify amount",
isEVM: true,
possiblePoints: 7.4399999999999995,
earnedPoints: 0,
},
{
icon: "./assets/gtcGrantsLightIcon.svg",
platform: "Gitcoin",
name: "Gitcoin",
description: "Connect with Github to verify with your Gitcoin account.",
connectMessage: "Connect Account",
isEVM: true,
possiblePoints: 12.93,
earnedPoints: 0,
},
{
icon: "./assets/twitterStampIcon.svg",
platform: "Twitter",
name: "Twitter",
description: "Connect your existing Twitter account to verify.",
connectMessage: "Connect Account",
possiblePoints: 3.63,
earnedPoints: 3.63,
},
{
icon: "./assets/discordStampIcon.svg",
platform: "Discord",
name: "Discord",
description: "Connect your existing Discord account to verify.",
connectMessage: "Connect Account",
possiblePoints: 0.689,
earnedPoints: 0,
},
{
icon: "./assets/googleStampIcon.svg",
platform: "Google",
name: "Google",
description: "Connect your existing Google Account to verify",
connectMessage: "Connect Account",
possiblePoints: 2.25,
earnedPoints: 1,
},
],
rawScore: 0,
} as unknown as ScorerContextState;

export const renderWithContext = (
userContext: UserContextState,
ceramicContext: CeramicContextState,
ui: React.ReactElement<any, string | React.JSXElementConstructor<any>>
) =>
render(
<UserContext.Provider value={userContext}>
<CeramicContext.Provider value={ceramicContext}>{ui}</CeramicContext.Provider>
</UserContext.Provider>
<ScorerContext.Provider value={scorerContext}>
<UserContext.Provider value={userContext}>
<CeramicContext.Provider value={ceramicContext}>{ui}</CeramicContext.Provider>
</UserContext.Provider>
</ScorerContext.Provider>
);

export const testOnChainContextState = (initialState?: Partial<OnChainContextState>): OnChainContextState => {
Expand Down
24 changes: 24 additions & 0 deletions app/__tests__/components/CardList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import {
makeTestCeramicContext,
makeTestUserContext,
renderWithContext,
scorerContext,
} from "../../__test-fixtures__/contextTestHelpers";
import { CeramicContextState } from "../../context/ceramicContext";
import { ScorerContextState } from "../../context/scorerContext";

jest.mock("../../utils/onboard.ts");

Expand Down Expand Up @@ -53,4 +55,26 @@ describe("<CardList />", () => {

expect(screen.getAllByTestId("loading-card"));
});

it("renders cards by verification status and possible points", () => {
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
const possiblePoints = screen.getAllByTestId("platform-name").map((el) => el.textContent);
expect(possiblePoints).toEqual(["Gitcoin", "GTC Staking", "Discord", "Google", "Twitter"]);
});
it("should indicate on card whether or not it has been verified", () => {
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
const verifiedBtnCnt = screen
.getAllByTestId("connect-button")
.map((el) => el.textContent)
.filter((text) => text === "Verified").length;
expect(verifiedBtnCnt).toBeGreaterThan(0);
expect(verifiedBtnCnt).toEqual(
scorerContext.scoredPlatforms.filter((platform) => platform.earnedPoints > 0).length
);
});
it("should render available points", () => {
renderWithContext(mockUserContext, mockCeramicContext, <CardList {...cardListProps} />);
const availablePnts = screen.getAllByTestId("available-points").map((el) => el.textContent);
expect(availablePnts).toEqual(["12.93", "7.44", "0.69", "1.25", "0.00"]);
});
});
2 changes: 2 additions & 0 deletions app/__tests__/pages/Dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jest.mock("../../utils/onboard.ts", () => ({
chains: [],
}));

jest.mock("../../components/CardList", () => ({ CardList: () => <div>Card List</div> }));

jest.mock("../../components/SyncToChainButton", () => <div>Sync to Chain</div>);

jest.mock("@self.id/framework", () => {
Expand Down
29 changes: 24 additions & 5 deletions app/components/CardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { PLATFORM_ID, PROVIDER_ID } from "@gitcoin/passport-types";
import { CeramicContext } from "../context/ceramicContext";
import { PlatformCard } from "./PlatformCard";
import PageWidthGrid from "../components/PageWidthGrid";
import { PlatformScoreSpec, ScorerContext } from "../context/scorerContext";

export type CardListProps = {
isLoading?: boolean;
Expand All @@ -28,8 +29,17 @@ const cardClassName = "col-span-2 md:col-span-3 lg:col-span-2 xl:col-span-3";

type SelectedProviders = Record<PLATFORM_ID, PROVIDER_ID[]>;

export const getStampProviderIds = (platform: PLATFORM_ID): PROVIDER_ID[] => {
return (
STAMP_PROVIDERS[platform]?.reduce((all, stamp) => {
return all.concat(stamp.providers?.map((provider) => provider.name as PROVIDER_ID));
}, [] as PROVIDER_ID[]) || []
);
};

export const CardList = ({ className, isLoading = false }: CardListProps): JSX.Element => {
const { allProvidersState, allPlatforms } = useContext(CeramicContext);
const { scoredPlatforms } = useContext(ScorerContext);
const { isOpen, onOpen, onClose } = useDisclosure();
const btnRef = useRef();
const [currentPlatform, setCurrentPlatform] = useState<PlatformSpec | undefined>();
Expand All @@ -40,10 +50,7 @@ export const CardList = ({ className, isLoading = false }: CardListProps): JSX.E
const [selectedProviders, setSelectedProviders] = useState<SelectedProviders>(
PLATFORMS.reduce((plaforms, platform) => {
// get all providerIds for this platform
const providerIds =
STAMP_PROVIDERS[platform.platform]?.reduce((all, stamp) => {
return all.concat(stamp.providers?.map((provider) => provider.name as PROVIDER_ID));
}, [] as PROVIDER_ID[]) || [];
const providerIds = getStampProviderIds(platform.platform);
// default to empty array for each platform
plaforms[platform.platform] = providerIds.filter(
(providerId) => typeof allProvidersState[providerId]?.stamp?.credential !== "undefined"
Expand Down Expand Up @@ -112,10 +119,22 @@ export const CardList = ({ className, isLoading = false }: CardListProps): JSX.E
}
}, [currentPlatform]);

const [verified, unverified] = scoredPlatforms.reduce(
([verified, unverified], platform): [PlatformScoreSpec[], PlatformScoreSpec[]] => {
return platform.earnedPoints === 0
? [verified, [...unverified, platform]]
: [[...verified, platform], unverified];
},
[[], []] as [PlatformScoreSpec[], PlatformScoreSpec[]]
);

return (
<>
<PageWidthGrid className={className}>
{PLATFORMS.map((platform, i) => {
{[
...unverified.sort((a, b) => b.possiblePoints - a.possiblePoints),
...verified.sort((platform) => platform.earnedPoints - platform.possiblePoints),
].map((platform, i) => {
return isLoading ? (
<LoadingCard key={i} className={cardClassName} />
) : (
Expand Down
15 changes: 7 additions & 8 deletions app/components/LoadingCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,22 @@ import React from "react";
export const LoadingCard = ({ className }: { className?: string }): JSX.Element => {
return (
<div className={className} data-testid="loading-card">
<div className="relative flex animate-pulse flex-col border border-accent-2 bg-background-2 p-0 xl:p-2">
<div className="relative flex animate-pulse flex-col rounded-lg border border-foreground-4 bg-gradient-to-b from-background to-[#06153D] p-0 xl:p-2">
<div className="flex flex-row p-6">
<div className="flex h-10 w-10 flex-grow justify-center md:justify-start">
<div className="h-12 w-12 rounded-full bg-accent-2"></div>
<div className="h-12 w-12 rounded-full bg-foreground-3"></div>
</div>
</div>
<div className="mt-2 flex p-2 px-4">
<div className="mx-auto mb-4 h-4 w-1/3 rounded-lg bg-accent-2 md:mx-0 md:mb-0 xl:mb-2"></div>
<div className="mx-auto mb-4 h-4 w-1/3 rounded-lg bg-foreground-3 md:mx-0 md:mb-0 xl:mb-2"></div>
</div>
<div className="mb-4 hidden grid-cols-12 gap-4 p-2 px-4 md:grid xl:mb-6">
<div className="col-span-3 h-3 rounded-md bg-accent-2"></div>
<div className="col-span-2 h-3 rounded-md bg-accent-2"></div>
<div className="col-span-3 h-3 rounded-md bg-foreground-3"></div>
<div className="col-span-2 h-3 rounded-md bg-foreground-3"></div>
</div>

<div className="mt-auto flex h-12 w-full flex-row items-center justify-center border-t border-accent-2">
<div className="mr-2 h-3 w-1/5 rounded-md bg-accent-2"></div>
<div className="ml-2 h-3 w-1/5 rounded-md bg-accent-2"></div>
<div className="ml-4 mt-auto flex h-12 w-full flex-row items-center justify-start">
<div className="mr-2 h-3 w-1/4 rounded-md bg-foreground-3"></div>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 3e001e8

Please sign in to comment.