Skip to content

Commit

Permalink
Merge dev into master (#48)
Browse files Browse the repository at this point in the history
* fixed bug

* email required

* set min date

* fixed style

* change modal style

* change modal large size

* fixed error displaying

* end date condition

* fixed bug

* fixed reading winners from contract

* fixed bug

* edit export wallets

* fixed variable names

* fixed typo

* use find instead filter

* change variable name

* change variable name

* create export button

* disable token tap & gas tap button

* remove contribution hub main page layout

* remove context from prizeTap content

* new page and layout for create raffle

* create show detail rout

* create route for display rejection reason

* change button name "Raffle is being processed"

* fixed bug

* fixed style

* change discord validation

* set export btn

* display winner count

* get user raffle server side

* add new routes

* remove signal from get user raffle api

* fixed bug - get user token balance

* fixed style

* use create & detail & verification route

* edit style

* clean code

* remove comment

* fixed fadeInOut animation duration

* token tap & refactor prizeTap components

* refactor error handling

* fixed display number of nfts bug

* remove log

* remove comments

* implementing gas tap route

* add new style

* add new image and remove dead code

* fixed bug

* add gastap contribution

* refactor requirement

* search chain input

* edit text

* set check constraint params validation

* check contract address function

* Separate validation function

* edit url address

* fixed gastap components

* added donation amount helper text

* added 404 page

* get user Distribution token tap

* add distribution apis

* add use token distribution type

* add create distribution functions

* create user distribution card

* remove logs

* create token tap timer component

* create csvFileInput component

* fixed twitter in send to api

* token tap form new style

* get token tap valid chain

* token tap send transaction

* added prevent navigation hook

* fixed error

* added edit button to user profile page

* fixed wallet winners modal

* send data in form data

* fixed api calling

* fixed reversed constraints api

* remove dead code

* add constraint file type to requirement prop

* refactor context to use new requirement

* using new requirement

* refactor sending to api

* refactor to use new requirement

* duplicate

* fixed bug

* refactor using constraint details modal

* change functionality

* remove extra files

* fixed bugs

* fixed gastap login not fetching data, bright id connection not showing sometimes

* fixed build error

* fixed bright id meet verified modal in gastap

* fixed gastap tooltip, fixed bright id connection status

* moved prize-tap components into app dir

* fixed winners modal functionality, added enrollments list

* fixed namings

* fixed build errors

---------

Co-authored-by: abbasnosrati <[email protected]>
  • Loading branch information
alimaktabi and abbasnosrati authored Jan 23, 2024
1 parent 86ce529 commit 413ca25
Show file tree
Hide file tree
Showing 94 changed files with 3,237 additions and 1,330 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"cSpell.words": ["Solana", "unitap"],
"cSpell.words": ["Solana", "unitap", "prizetap", "gastap", "tokentap"],
"tailwindCSS.includeLanguages": {
"typescript": "javascript",
"typescriptreact": "javascript"
Expand Down
107 changes: 107 additions & 0 deletions app/contribution-hub/ChainList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import Icon from "@/components/ui/Icon";
import { Chain } from "@/types/gastap";
import { useOutsideClick } from "@/utils/hooks/dom";
import React, { useEffect, useRef, useState } from "react";

interface Props {
setRequirementParamsList: any;
requirementParamsList: any;
allChainList: Chain[] | undefined;
}

const ChainList = ({
setRequirementParamsList,
requirementParamsList,
allChainList,
}: Props) => {
const [selectedChain, setSelectedChain] = useState<Chain | undefined>();

const handleSelectChain = (chian: Chain) => {
setSelectedChain(chian);
setRequirementParamsList({
...requirementParamsList,
["CHAIN"]: chian.pk,
});
setShowItems(false);
setChainName(chian.chainName);
};

const [chainName, setChainName] = useState<string | undefined>();

const [filterChainName, setFilterChainName] = useState<Chain[] | undefined>(
allChainList
);

const [showItems, setShowItems] = useState<boolean>(false);

const ref = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!requirementParamsList || !allChainList) return;
if (!requirementParamsList.CHAIN) return;
const chain = allChainList!.find(
(item) => item.pk === requirementParamsList.CHAIN
);
setSelectedChain(chain);
}, [requirementParamsList]);

useOutsideClick(ref, () => {
if (showItems) setShowItems(false);
});

const handleSearch = (e: string) => {
setSelectedChain(undefined);
setChainName(e);
setShowItems(true);
setFilterChainName(
allChainList?.filter(
(chain) =>
chain.chainName.toLocaleLowerCase().includes(e) ||
chain.chainId.includes(e)
)
);
};

return (
<div className="relative" ref={ref}>
<div
onClick={() => setShowItems(!showItems)}
className="flex items-center gap-2 justify-between cursor-pointer h-[43px] bg-gray40 border-gray50 rounded-xl px-3"
>
{selectedChain && (
<Icon iconSrc={selectedChain.logoUrl} height="24px" width="24px" />
)}
<input
className="h-full w-full bg-inherit"
placeholder="Please select chain..."
value={chainName ?? ""}
onChange={(e) => handleSearch(e.target.value)}
/>

<Icon
iconSrc="/assets/images/fund/arrow-down.png"
height="8px"
width="14px"
/>
</div>
{showItems && (
<div className="absolute bg-gray40 z-10 w-full border border-gray50 overflow-x-hidden overflow-y-scroll max-h-[200px] rounded-lg ">
{filterChainName?.map((chain) => (
<div
onClick={() => handleSelectChain(chain)}
key={chain.chainPk}
className="p-2 cursor-pointer hover:bg-gray70 rounded-lg"
>
<div className="flex items-center gap-2 text-white">
<Icon iconSrc={chain.logoUrl} height="24px" width="24px" />
{chain.chainName}
</div>
</div>
))}
</div>
)}
</div>
);
};

export default ChainList;
273 changes: 273 additions & 0 deletions app/contribution-hub/ConstraintDetailsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
"use client";

import { useEffect, useState } from "react";
import { RequirementProps, ConstraintProps, Chain } from "@/types";
import useAddRequirement from "@/components/containers/provider-dashboard/hooks/useAddRequirement";
import Icon from "@/components/ui/Icon";
import ChainList from "@/app/contribution-hub/ChainList";
import SelectMethodInput from "@/app/contribution-hub/SelectMethodInput";
import { useWalletProvider } from "@/utils/wallet";
import { isAddress } from "viem";
import { checkCollectionAddress } from "@/components/containers/provider-dashboard/helpers/checkCollectionAddress";
import CsvFileInput from "./CsvFileInput";

interface CreateModalParam {
constraint: ConstraintProps;
setRequirementParamsList: any;
requirementParamsList: any;
constraintFile: any;
allChainList: Chain[];
setConstraintFile: (item: any) => void;
}

interface DetailsModal {
constraint: ConstraintProps;
handleBackToConstraintListModal: any;
requirementList: RequirementProps[];
insertRequirement: any;
updateRequirement: any;
allChainList: Chain[];
}

const ConstraintDetailsModal = ({
constraint,
handleBackToConstraintListModal,
requirementList,
insertRequirement,
updateRequirement,
allChainList,
}: DetailsModal) => {
const provider = useWalletProvider();

const addRequirements = useAddRequirement(
handleBackToConstraintListModal,
insertRequirement,
updateRequirement
);

const [existRequirement, setExistRequirement] =
useState<RequirementProps | null>(null);

const [requirementParamsList, setRequirementParamsList] = useState<any>();

const [isNotSatisfy, setIsNotSatisfy] = useState<boolean>(false);

const [constraintFile, setConstraintFile] = useState<any>();

const createRequirementParamsList = () => {
if (constraint.params.length > 0) {
setRequirementParamsList(
constraint.params.reduce((obj: any, item: any, index: any) => {
obj[item] = "";
return obj;
}, {})
);
}
};

const [errorMessage, setErrorMessage] = useState<string | null>();

useEffect(() => {
const requirement = requirementList.find(
(item) => item.pk == constraint.pk
);

setExistRequirement(requirement ? requirement : null);

if (requirement) {
setIsNotSatisfy(requirement.isNotSatisfy);
setRequirementParamsList(requirement.params);
} else {
createRequirementParamsList();
}
}, []);

const checkingParamsValidation = async () => {
if (!requirementParamsList) return false;
if (
!requirementParamsList.COLLECTION_ADDRESS ||
!requirementParamsList.CHAIN ||
!requirementParamsList.MINIMUM
) {
!requirementParamsList.COLLECTION_ADDRESS
? setErrorMessage("Please enter collection address.")
: !requirementParamsList.CHAIN
? setErrorMessage("Please select chain.")
: setErrorMessage("Please select minimum amount.");
return false;
}

if (requirementParamsList.COLLECTION_ADDRESS) {
const step2Check = isAddress(requirementParamsList.COLLECTION_ADDRESS);
const chain = allChainList?.find(
(item) => Number(item.pk) === Number(requirementParamsList.CHAIN)
);

if (!chain) return false;

const res = await checkCollectionAddress(
provider,
requirementParamsList.COLLECTION_ADDRESS,
Number(chain.chainId)
);

(!step2Check || !res) && setErrorMessage("Invalid contract address.");
return step2Check && res;
}
};

const checkCsvFileUploadedValidation = () => {
console.log(requirementParamsList, requirementParamsList.CSV_FILE);
if (!requirementParamsList) return false;
if (!requirementParamsList.CSV_FILE) {
setErrorMessage("Please upload a csv file.");
return false;
}
return true;
};

const handleAddRequirement = async () => {
if (constraint.name === "core.HasNFTVerification") {
const res = await checkingParamsValidation();
if (!res) return;
}

if (constraint.name === "core.AllowListVerification") {
const res = checkCsvFileUploadedValidation();
if (!res) return;
}

addRequirements(
existRequirement,
constraint.pk,
constraint.name,
constraint.title,
isNotSatisfy,
requirementParamsList,
constraintFile
);
};

const handleSelectNotSatisfy = (isSatisfy: boolean) => {
setIsNotSatisfy(isSatisfy);
};

return (
<div className="flex flex-col gap-2 mt-5 relative">
<div
className="absolute -top-14 cursor-pointer z-[999]"
onClick={handleBackToConstraintListModal}
>
<Icon
iconSrc="/assets/images/provider-dashboard/arrow-left.svg"
className="cursor-pointer z-[999999]"
/>
</div>
<div className="w-full flex gap-4 h-[32px] mb-2">
<div
onClick={() => handleSelectNotSatisfy(false)}
className={`w-full flex items-center justify-center rounded-lg h-full cursor-pointer text-white relative overflow-hidden`}
>
<div
className={`${
!isNotSatisfy ? "bg-dark-space-green opacity-30" : "bg-gray50"
} absolute w-full h-full`}
></div>
<p className="absolute text-white">Should satisfy</p>
</div>
<div
onClick={() => handleSelectNotSatisfy(true)}
className={`w-full flex items-center justify-center rounded-lg h-full cursor-pointer text-white relative overflow-hidden`}
>
<div
className={`${
isNotSatisfy ? "bg-error opacity-50" : "bg-gray50"
} absolute w-full h-full `}
></div>
<p className="absolute text-white">Should not satisfy</p>
</div>
</div>
<CreateParams
constraint={constraint}
setRequirementParamsList={setRequirementParamsList}
requirementParamsList={requirementParamsList}
constraintFile={constraintFile}
setConstraintFile={setConstraintFile}
allChainList={allChainList}
/>
<div className="mb-4">{constraint.description}</div>
<div className="text-error text-[10px] min-h-[15px]">{errorMessage}</div>
<div
onClick={handleAddRequirement}
className="flex cursor-pointer bg-gray40 text-[14px] font-semibold text-white h-[44px] border-2 border-gray70 rounded-xl items-center justify-center mb-2"
>
Add Requirement
</div>
</div>
);
};

const CreateParams = ({
constraint,
setRequirementParamsList,
requirementParamsList,
constraintFile,
setConstraintFile,
allChainList,
}: CreateModalParam) => {
const [reqNftAddress, setReqNftAddress] = useState("");

useEffect(() => {
if (!requirementParamsList) return;
setReqNftAddress(requirementParamsList.COLLECTION_ADDRESS);
}, [requirementParamsList]);

const handleChangeCollection = (address: string) => {
setReqNftAddress(address);
setRequirementParamsList({
...requirementParamsList,
["COLLECTION_ADDRESS"]: address,
});
};

if (constraint.params.length === 0) return;

if (constraint.name === "core.HasNFTVerification") {
return (
<div className="flex flex-col gap-3">
<ChainList
setRequirementParamsList={setRequirementParamsList}
requirementParamsList={requirementParamsList}
allChainList={allChainList}
/>
<div className="nftAddress_requirement_input overflow-hidden pl-4 flex rounded-2xl bg-gray40 border items-center h-[43px] border-gray50">
<input
name="nftAddressRequirement"
placeholder="Paste NFT address"
className="bg-inherit w-full h-full"
value={reqNftAddress ?? ""}
onChange={(e) => handleChangeCollection(e.target.value)}
/>
</div>
<SelectMethodInput
setRequirementParamsList={setRequirementParamsList}
requirementParamsList={requirementParamsList}
/>
</div>
);
}

if (constraint.name === "core.AllowListVerification") {
return (
<CsvFileInput
setRequirementParamsList={setRequirementParamsList}
requirementParamsList={requirementParamsList}
setConstraintFile={setConstraintFile}
constraintFile={constraintFile}
/>
);
}
return <></>;
};

export default ConstraintDetailsModal;
Loading

0 comments on commit 413ca25

Please sign in to comment.