Skip to content

Instantly share code, notes, and snippets.

@jdaly13
Created March 17, 2022 03:23
Show Gist options
  • Save jdaly13/b4d78c438c96cd89e5c8b4e31867d660 to your computer and use it in GitHub Desktop.
Save jdaly13/b4d78c438c96cd89e5c8b4e31867d660 to your computer and use it in GitHub Desktop.
search params bounties
import React, { Fragment } from "react";
import { Menu, Transition } from "@headlessui/react";
import { ContentfulBounty } from "~/types";
import { ChevronDown16 } from "@carbon/icons-react";
import { capitalize, startCase, toLower } from "lodash";
import { getBountyStatus } from "~/utils/helpers";
const allLevels = "All Levels";
const allProjects = "All Projects";
const allDrops = "All Drops";
interface Level {
[allLevels]?: ContentfulBounty[];
beginner?: ContentfulBounty[];
intermediate?: ContentfulBounty[];
advanced?: ContentfulBounty[];
}
interface Status {
[allDrops]?: ContentfulBounty[];
live?: ContentfulBounty[];
upcoming?: ContentfulBounty[];
ended?: ContentfulBounty[];
}
interface DynamicCategory {
[key: string]: ContentfulBounty[];
}
interface FilterType {
name: string;
available: number;
}
interface Availability {
[key: string]: number;
}
function classNames(...classes: string[]) {
return classes.filter(Boolean).join(" ");
}
function mapDifficulty(difficulty: string, currentLevelName: string) {
if (difficulty === "Easy" && currentLevelName === "beginner") {
return true;
}
if ((difficulty === "Medium" || difficulty === "Hard") && currentLevelName === "intermediate") {
return true;
}
if (difficulty === "Elite" && currentLevelName === "advanced") {
return true;
}
}
function sortDrops(drops: ContentfulBounty[]) {
const statusOrder: {
live: number;
upcoming: number;
ended: number;
} = { live: 0, upcoming: 1, ended: 2 };
drops.sort((a, b) => {
if (statusOrder[getBountyStatus(a)] < statusOrder[getBountyStatus(b)]) {
return -1;
}
if (statusOrder[getBountyStatus(a)] > statusOrder[getBountyStatus(b)]) {
return 1;
}
if (a.campaign?.project.name < b.campaign?.project.name) {
return -1;
}
if (a.campaign?.project.name > b.campaign?.project.name) {
return 1;
}
return 0;
});
}
export function DropsDropDown({
drops,
setDrops,
projectUrlParam,
}: {
drops: Array<ContentfulBounty>;
setDrops: (b: Array<ContentfulBounty>) => void;
projectUrlParam: string | null;
}) {
const projectObj: DynamicCategory = {};
const statusObj: Status = {
[allDrops]: undefined,
live: undefined,
upcoming: undefined,
ended: undefined,
};
const levelObj: Level = {
[allLevels]: undefined,
beginner: undefined,
intermediate: undefined,
advanced: undefined,
};
const defaultDropProject: FilterType = {
name: "All Projects",
available: drops.length,
};
const defaultDropLevel: FilterType = {
name: allLevels,
available: drops.length,
};
const defaultDropStatus: FilterType = {
name: "All Drops",
available: drops.length,
};
drops.forEach((drop) => {
if (drop.difficulty === "Easy") {
if (!levelObj.beginner) {
levelObj.beginner = [];
}
levelObj.beginner.push(drop);
} else if (drop.difficulty === "Medium" || drop.difficulty === "Hard") {
if (!levelObj.intermediate) {
levelObj.intermediate = [];
}
levelObj.intermediate.push(drop);
} else if (drop.difficulty === "Elite") {
if (!levelObj.advanced) {
levelObj.advanced = [];
}
levelObj.advanced.push(drop);
}
if (!projectObj[drop.campaign?.project.name]) {
projectObj[drop.campaign?.project.name] = [];
}
projectObj[drop.campaign?.project.name]?.push(drop);
const status = getBountyStatus(drop);
if (!statusObj[status as keyof Status]) {
statusObj[status as keyof Status] = [];
}
statusObj[status as keyof Status]?.push(drop);
});
levelObj[allLevels] = drops;
projectObj[allProjects] = drops;
statusObj[allDrops] = drops;
const [totalProjects, setDropProjects] = React.useState(
Object.keys(projectObj).map((val) => {
return {
name: val,
available: projectObj[val]?.length ?? 0,
};
})
);
const [totalLevels, setDropLevels] = React.useState(
Object.keys(levelObj).map((val) => {
return {
name: val,
available: levelObj[val as keyof Level]?.length ?? 0,
};
})
);
const [totalStatus, setDropStatuses] = React.useState(
Object.keys(statusObj).map((val) => {
return {
name: val,
available: statusObj[val as keyof Status]?.length ?? 0,
};
})
);
const [currentProject, setCurrentProject] = React.useState(defaultDropProject);
const [currentLevel, setCurrentLevel] = React.useState(defaultDropLevel);
const [currentStatus, setCurrentStatus] = React.useState(defaultDropStatus);
const createAvailabilityObj = (array: string[]) => {
const obj: Availability = {};
array.forEach((val) => {
obj[val] = (obj[val] || 0) + 1;
});
return obj;
};
React.useEffect(() => {
if (projectUrlParam) {
if (projectObj[capitalize(projectUrlParam)]) {
//valid project
filterForProjects({
name: capitalize(projectUrlParam),
available: projectObj[capitalize(projectUrlParam)]?.length ?? 0,
});
} else {
window.location.replace(window.location.origin);
}
} else {
sortDrops(drops);
setDrops(drops);
}
}, []);
const renderDropDownItems = (whichFilter: FilterType[], whichFunction: (a: FilterType) => void) => {
const available = whichFilter.map((data: FilterType, index: number) => {
if (data.available) {
return (
<Menu.Item key={index}>
{({ active }) => (
<li
className={classNames(
active ? "bg-[#21262E]" : "text-white block pl-6 py-2 text-md",
"block pl-6 py-2 text-lg"
)}
onClick={() => {
whichFunction(data);
}}
>
{startCase(toLower(data.name))} ({data.available})
</li>
)}
</Menu.Item>
);
} else {
return (
<Menu.Item disabled key={index}>
{({ active }) => (
<li
key={index}
className={classNames(
active ? "bg-[#21262E]" : "text-white block pl-6 py-2 text-md",
"block pl-6 py-2 text-lg text-gray-400"
)}
>
{startCase(toLower(data.name))} ({data.available})
</li>
)}
</Menu.Item>
);
}
});
return available;
};
const filterforLevels = (dropLevel: FilterType) => {
const filteredDrops: ContentfulBounty[] = [];
const availabilityPerProject: string[] = [];
const availabilityPerStatus: string[] = [];
(levelObj[dropLevel.name as keyof Level] as ContentfulBounty[]).forEach((lev: ContentfulBounty) => {
totalProjects.forEach((proj) => {
if (
proj.name === currentProject.name &&
(lev.campaign?.project.name === currentProject.name || proj.name === allProjects)
) {
if (currentStatus.name !== allDrops) {
if (currentStatus.name === getBountyStatus(lev)) {
filteredDrops.push(lev);
}
} else {
filteredDrops.push(lev);
}
}
// Filter how many by project type based on level chosen
// e.g. you choose beginner
if (proj.name === lev.campaign?.project.name || proj.name === allProjects) {
if (currentStatus.name === allDrops) {
availabilityPerProject.push(proj.name);
} else {
totalStatus.forEach((status) => {
if (getBountyStatus(lev) === status.name && currentStatus.name === getBountyStatus(lev)) {
availabilityPerProject.push(proj.name);
}
});
}
}
});
totalStatus.forEach((st) => {
if (st.name === getBountyStatus(lev) || st.name === allDrops) {
if (currentProject.name === allProjects) {
availabilityPerStatus.push(st.name);
} else {
totalProjects.forEach((proj) => {
if (lev.campaign?.project.name === proj.name && currentProject.name === lev.campaign?.project.name) {
availabilityPerStatus.push(st.name);
}
});
}
}
});
});
const totalForEachProject = createAvailabilityObj(availabilityPerProject);
setDropProjects(
totalProjects.map((proj) => {
const available = totalForEachProject[proj.name];
if (available) {
return { ...proj, available };
} else {
return { ...proj, available: 0 };
}
})
);
const claimableCounts = createAvailabilityObj(availabilityPerStatus);
setDropStatuses(
totalStatus.map((stat) => {
const available = claimableCounts[stat.name];
if (available) {
return { ...stat, available };
} else {
return { ...stat, available: 0 };
}
})
);
sortDrops(filteredDrops);
setDrops(filteredDrops);
setCurrentLevel(dropLevel);
};
const filterForProjects = (dropLevel: FilterType) => {
const filteredDrops: ContentfulBounty[] = [];
const availabilityPerLevel: string[] = [];
const availabilityPerStatus: string[] = [];
projectObj[dropLevel.name]?.forEach((protocol: ContentfulBounty) => {
totalLevels.forEach((hierarchy) => {
if (
hierarchy.name === currentLevel.name &&
(mapDifficulty(protocol.difficulty, currentLevel.name) || hierarchy.name === allLevels)
) {
if (currentStatus.name !== allDrops) {
if (currentStatus.name === getBountyStatus(protocol)) {
filteredDrops.push(protocol);
}
} else {
filteredDrops.push(protocol);
}
}
if (mapDifficulty(protocol.difficulty, hierarchy.name) || hierarchy.name === allLevels) {
if (currentStatus.name === allDrops) {
availabilityPerLevel.push(hierarchy.name);
} else {
totalStatus.forEach((status) => {
if (getBountyStatus(protocol) === status.name && currentStatus.name === getBountyStatus(protocol)) {
availabilityPerLevel.push(hierarchy.name);
}
});
}
}
});
totalStatus.forEach((st) => {
if (st.name === getBountyStatus(protocol) || st.name === allDrops) {
if (currentLevel.name === allLevels) {
availabilityPerStatus.push(st.name);
} else {
totalLevels.forEach((lev) => {
if (
mapDifficulty(protocol.difficulty, lev.name) &&
mapDifficulty(protocol.difficulty, currentLevel.name)
) {
availabilityPerStatus.push(st.name);
}
});
}
}
});
});
const totalForEachLevel = createAvailabilityObj(availabilityPerLevel);
setDropLevels(
totalLevels.map((lev) => {
const available = totalForEachLevel[lev.name];
if (available) {
return { ...lev, available };
} else {
return { ...lev, available: 0 };
}
})
);
const claimableCounts = createAvailabilityObj(availabilityPerStatus);
setDropStatuses(
totalStatus.map((stat) => {
const available = claimableCounts[stat.name];
if (available) {
return { ...stat, available };
} else {
return { ...stat, available: 0 };
}
})
);
sortDrops(filteredDrops);
setDrops(filteredDrops);
setCurrentProject(dropLevel);
};
const filterForStatus = (dropLevel: FilterType) => {
const filteredDrops: ContentfulBounty[] = [];
const availabilityPerLevel: string[] = [];
const availabilityPerProject: string[] = [];
(statusObj[dropLevel.name as keyof Status] as ContentfulBounty[]).forEach((status: ContentfulBounty) => {
totalProjects.forEach((proj) => {
// FILTERED DROPS BASED ON OPTIONS
if (
proj.name === currentProject.name &&
(status.campaign?.project.name === currentProject.name || proj.name === allProjects)
) {
if (currentLevel.name !== allLevels) {
if (mapDifficulty(status.difficulty, currentLevel.name)) {
filteredDrops.push(status);
}
} else {
filteredDrops.push(status);
}
}
if (proj.name === status.campaign?.project.name || proj.name === allProjects) {
if (currentLevel.name === allLevels) {
availabilityPerProject.push(proj.name);
} else {
totalLevels.forEach((level) => {
if (mapDifficulty(status.difficulty, level.name) && mapDifficulty(status.difficulty, currentLevel.name)) {
availabilityPerProject.push(proj.name);
}
});
}
}
});
totalLevels.forEach((level) => {
if (mapDifficulty(status.difficulty, level.name) || level.name === allLevels) {
if (currentProject.name === allProjects) {
availabilityPerLevel.push(level.name);
} else {
totalProjects.forEach((proj) => {
if (
status.campaign?.project.name === proj.name &&
currentProject.name === status.campaign?.project.name
) {
availabilityPerLevel.push(level.name);
}
});
}
}
});
});
const totalForEachProject = createAvailabilityObj(availabilityPerProject);
setDropProjects(
totalProjects.map((proj) => {
const available = totalForEachProject[proj.name];
if (available) {
return { ...proj, available };
} else {
return { ...proj, available: 0 };
}
})
);
const totalForEachLevel = createAvailabilityObj(availabilityPerLevel);
setDropLevels(
totalLevels.map((lev) => {
const available = totalForEachLevel[lev.name];
if (available) {
return { ...lev, available };
} else {
return { ...lev, available: 0 };
}
})
);
setDrops(filteredDrops);
setCurrentStatus(dropLevel);
sortDrops(filteredDrops);
};
const resetAll = () => {
setDropStatuses(
totalStatus.map((stat) => {
return { ...stat, available: statusObj[stat.name as keyof Status]?.length ?? 0 };
})
);
setCurrentStatus({ name: allDrops, available: statusObj[allDrops]?.length ?? 0 });
setDropLevels(
totalLevels.map((level) => {
return { ...level, available: levelObj[level.name as keyof Level]?.length ?? 0 };
})
);
setCurrentLevel({ name: allLevels, available: levelObj[allLevels]?.length ?? 0 });
setDropProjects(
totalProjects.map((proj) => {
return { ...proj, available: projectObj[proj.name]?.length ?? 0 };
})
);
setCurrentProject({ name: allProjects, available: projectObj[allProjects]?.length ?? 0 });
sortDrops(drops);
setDrops(drops);
};
return (
<div className="flex justify-center dropdown">
<p className="invisible ml-8">reset all filters</p>
<Menu as="div" className="relative inline-block text-left mr-4">
<div>
<Menu.Button className="inline-flex px-6 justify-between rounded-2xl bg-[#11151A] border border-[#454F5B] w-[180px] p-[10px] text-lg font-semibold text-white-700 focus:outline-none">
<span>{startCase(toLower(currentStatus.name))}</span>
<ChevronDown16 className="-mr-1 ml-2 h-5 w-5 mt-1" aria-hidden="true" />
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="origin-top-right absolute right-0 w-[180px] z-50 shadow-lg bg-[#11151A] text-lg text-white-700 rounded-2xl border border-[#454F5B]">
<div className="py-1">{renderDropDownItems(totalStatus, filterForStatus)}</div>
</Menu.Items>
</Transition>
</Menu>
<Menu as="div" className="relative inline-block text-left mr-4">
<div>
<Menu.Button className="inline-flex px-6 justify-between rounded-2xl bg-[#11151A] border border-[#454F5B] w-[180px] p-[10px] text-lg font-semibold text-white-700 focus:outline-none">
{startCase(toLower(currentLevel.name))}
<ChevronDown16 className="-mr-1 ml-2 h-5 w-5 mt-1" aria-hidden="true" />
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="origin-top-right absolute right-0 w-[180px] z-50 shadow-lg bg-[#11151A] text-lg text-white-700 rounded-2xl border border-[#454F5B]">
<div className="py-1">{renderDropDownItems(totalLevels, filterforLevels)}</div>
</Menu.Items>
</Transition>
</Menu>
<Menu as="div" className="relative inline-block text-left">
<div>
<Menu.Button className="inline-flex px-6 justify-between rounded-2xl bg-[#11151A] border border-[#454F5B] w-[180px] p-[10px] text-lg font-semibold text-white-700 focus:outline-none">
{startCase(toLower(currentProject.name))}
<ChevronDown16 className="-mr-1 ml-2 h-5 w-5 mt-1" aria-hidden="true" />
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="origin-top-right absolute right-0 w-[180px] z-50 shadow-lg bg-[#11151A] text-lg text-white-700 rounded-2xl border border-[#454F5B]">
<div className="py-1">{renderDropDownItems(totalProjects, filterForProjects)}</div>
</Menu.Items>
</Transition>
</Menu>
<p className="relative inline-block cursor-pointer ml-8 self-center" onClick={resetAll}>
{" "}
reset all filters
</p>
</div>
);
}
import React from "react";
import { useLoaderData, MetaFunction, useFetcher } from "remix";
import { Hero } from "~/components/hero";
import { metaTagHelper } from "~/utils/meta-tags";
import { getCurrentUser } from "~/auth.server";
import { DropsGrid } from "~/components/drops-grid";
import { listActiveBounties } from "~/services/bounties.server";
import { getBountyClaimCounts, getBountyUserContexts } from "~/services/claims.server";
import { useCurrentUser } from "~/utils/use-current-user";
import { useInterval } from "react-use";
import { marked } from "marked";
import { DiscordButton } from "~/components/discord-button";
import { canClaimDifficulty } from "~/utils/helpers";
import { DataFunctionArgs } from "@remix-run/server-runtime";
import { DropsDropDown } from "~/components/drops-dropdowns";
import { ContentfulBounty } from "~/types";
export const loader = async ({ request }: DataFunctionArgs) => {
let user = await getCurrentUser(request);
let bounties = await listActiveBounties();
let claimCountsLookup = await getBountyClaimCounts(bounties.map((b) => b.sys.id));
let bountyUserContexts = await getBountyUserContexts(user, bounties);
const url = new URL(request.url);
const search = new URLSearchParams(url.search);
const projectUrlParam = search.get("project");
bounties = bounties.map((bounty) => ({
...bounty,
description: marked(bounty.description ?? ""),
shortDescription: marked(bounty.shortDescription ?? ""),
}));
return { bounties, bountyUserContexts, claimCountsLookup, projectUrlParam };
};
type LoaderData = Awaited<ReturnType<typeof loader>>;
// https://remix.run/api/conventions#meta
export let meta: MetaFunction = () => {
return metaTagHelper({
title: "Learn. Earn. Repeat.",
description: "Get paid to learn about protocols & chains, and level up to become a crypto-SQL superstar!",
});
};
export default function Index() {
const user = useCurrentUser();
const initialData = useLoaderData<LoaderData>();
const liveData = useFetcher<LoaderData>();
useInterval(() => {
if (document.visibilityState === "visible") {
liveData.load("/");
}
}, 10000);
const data = liveData.data ?? initialData;
const getEasyBounties = (bounties: ContentfulBounty[]) => {
return bounties.filter((bounty) => bounty.difficulty === "Easy");
};
const getMediumHardBounties = (bounties: ContentfulBounty[]) => {
return bounties.filter((bounty) => bounty.difficulty === "Medium" || bounty.difficulty === "Hard");
};
const getEliteBounties = (bounties: ContentfulBounty[]) => {
return bounties.filter((bounty) => bounty.difficulty === "Elite");
};
const [activedrops, setActiveDrops] = React.useState(data.bounties);
const [easyBounties, setEasyBounties] = React.useState(getEasyBounties(data.bounties));
const [mediumBounties, setMediumBounties] = React.useState(getMediumHardBounties(data.bounties));
const [advancedBounties, setAdvancedBounties] = React.useState(getEliteBounties(data.bounties));
React.useEffect(() => {
if (activedrops) {
setEasyBounties(getEasyBounties(activedrops));
setMediumBounties(getMediumHardBounties(activedrops));
setAdvancedBounties(getEliteBounties(activedrops));
}
}, [activedrops]);
return (
<div data-test-id="route-index">
<Hero className="bg-black bg-center bg-no-repeat bg-cover sm:bg-contain bg-[url('/images/bg/hero-mobile.png')] sm:bg-[url('/images/bg/hero.png')]">
<main className="py-56 space-y-3 text-center index__splash ">
<h2 className="max-w-lg mx-auto font-normal text-center text-7xl">Learn. Earn. Repeat.</h2>
<p className="max-w-md mx-auto text-lg text-center">
Get paid to learn about protocols and chains, and level up to become a
<span className="font-bold font-syneBold"> crypto-SQL superstar!</span>
</p>
</main>
</Hero>
<h1 className="text-center text-5xl py-16">Bounties and Scavenger Hunts</h1>
<section className="text-center bg-darkbg/95 static md:sticky top-0 z-30">
<div className="mx-auto container py-4">
<DropsDropDown
drops={data.bounties}
setDrops={setActiveDrops}
projectUrlParam={initialData.projectUrlParam}
/>
</div>
</section>
<section className="py-8 text-center bg-darkbg">
<div className="container mx-auto divide-y divide-zinc-700">
<section className="py-16">
<header className="flex flex-col items-center space-y-8 mb-8">
{!canClaimDifficulty(user, "Easy") && <LockIcon />}
<h3 className="text-center text-5xl font-syneBold">Beginner</h3>
<p className="text-gray-400 line-clamp-4 w-7/12 mx-auto mb-6 text-center">
Beginner bounties and scavenger hunts are designed for those who are just getting started with
Community-Enabled Analytics or are new to a particular ecosystem. These bounties are open to all users,
regardless of experience or ability level.
</p>
{!user ? (
<DiscordButton className="border-gradient" showLogo={false}>
Unlock Level
</DiscordButton>
) : null}
</header>
<DropsGrid
bounties={easyBounties}
bountyUserContexts={data.bountyUserContexts}
claimCounts={data.claimCountsLookup}
/>
</section>
<section className="py-16">
<header className="flex flex-col items-center space-y-8 mb-8">
{!canClaimDifficulty(user, "Medium") && <LockIcon />}
<h3 className="text-center text-5xl font-syneBold">Intermediate</h3>
<p className="text-gray-400 line-clamp-4 w-7/12 mx-auto mb-6 text-center">
Intermediate bounties are intended to offer a more challenging experience than Beginner bounties — often
with a higher potential reward. These bounties are open to users that have successfully completed at
least three Beginner bounties.
</p>
{!user ? (
<DiscordButton className="border-gradient" showLogo={false}>
Unlock Level
</DiscordButton>
) : !canClaimDifficulty(user, "Medium") ? (
<div className="rounded-full px-4 py-1 border-2 border-white/80 inline-flex text-center">
Must Complete Beginner Level
</div>
) : null}
</header>
<DropsGrid
bounties={mediumBounties}
bountyUserContexts={data.bountyUserContexts}
claimCounts={data.claimCountsLookup}
/>
</section>
<section className="py-16">
<header className="flex flex-col items-center space-y-8 mb-8">
{!canClaimDifficulty(user, "Elite") && <LockIcon />}
<h3 className="text-center text-5xl font-syneBold">Advanced</h3>
<p className="text-gray-400 w-7/12 text-center">
Advanced bounties are the most challenging and difficult bounty questions — and offer the largest
potential rewards too. These bounties are open to our most experienced and talented analysts — namely,
those that have completed at least 10 bounties and received at least one grand prize.
</p>
{!user ? (
<DiscordButton className="border-gradient" showLogo={false}>
Unlock Level
</DiscordButton>
) : !canClaimDifficulty(user, "Elite") ? (
<div className="rounded-full px-4 py-1 border-2 border-white/80 inline-flex text-center">
Must Complete Beginner &amp; Intermediate Levels
</div>
) : null}
</header>
<DropsGrid
bounties={advancedBounties}
bountyUserContexts={data.bountyUserContexts}
claimCounts={data.claimCountsLookup}
/>
</section>
</div>
</section>
</div>
);
}
function LockIcon() {
return (
<div className="h-10 w-10 rounded-full bg-white flex items-center justify-center">
<svg width="11" height="14" viewBox="0 0 11 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
className="fill-black"
fillRule="evenodd"
clipRule="evenodd"
d="M9.84231 5.91621H8.85709V2.96055C8.85709 1.28567 7.5763 0.00488281 5.90143 0.00488281C4.22655 0.00488281 2.94576 1.28567 2.94576 2.96055V5.91621H1.96054C1.36941 5.91621 0.975318 6.3103 0.975318 6.90143V12.8128C0.975318 13.4039 1.36941 13.798 1.96054 13.798H9.84231C10.4334 13.798 10.8275 13.4039 10.8275 12.8128V6.90143C10.8275 6.3103 10.4334 5.91621 9.84231 5.91621ZM3.93098 2.96055C3.93098 1.8768 4.81768 0.990104 5.90143 0.990104C6.98517 0.990104 7.87187 1.8768 7.87187 2.96055V5.91621H3.93098V2.96055Z"
fill="#11151A"
/>
</svg>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment