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

Merge use-real-data into main #153

Merged
merged 17 commits into from
Oct 29, 2023
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
4 changes: 2 additions & 2 deletions packages/nextjs/components/SearchProjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import Autosuggest from "react-autosuggest";
import useSWR from "swr";
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { ListDocument } from "~~/models/List";
import { ProjectDocument } from "~~/models/Project";
import { IProject } from "~~/models/Project";
import { fetcher } from "~~/utils/fetcher";

interface SearchResult {
searchData: ProjectDocument[] | ListDocument[];
searchData: IProject[] | ListDocument[];
}

const SearchProjects: React.FC = () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/components/ballot/AllBallots.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const AllBallots = () => {
newAllocation = !Number.isNaN(newAllocation) && newAllocation > 0 ? newAllocation : 0;

// Deduct the current project's allocation, since we're editing it
const currentProjectAllocation = state.projects.find(p => p.id === projectId)?.allocation || 0;
const currentProjectAllocation = state.projects.find(p => p._id === projectId)?.allocation || 0;
currentTotalAllocation -= currentProjectAllocation;

const projectedTotal = newAllocation + currentTotalAllocation;
Expand Down
10 changes: 7 additions & 3 deletions packages/nextjs/components/lists/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { Address } from "../scaffold-eth";
import { useAccount } from "wagmi";
import { HeartIcon as HeartFilledIcon } from "@heroicons/react/20/solid";
import { HeartIcon } from "@heroicons/react/24/outline";
import { ProjectDocument } from "~~/models/Project";
import { IProject } from "~~/models/Project";
import { IList } from "~~/types/list";
import { humanize } from "~~/utils/humanize";

const Card = ({ list, onLike, isLoading, loadingList }: any) => {
const { address } = useAccount();
Expand All @@ -23,7 +24,7 @@ const Card = ({ list, onLike, isLoading, loadingList }: any) => {
const _populatedSharedProjects = [];
for (let i = 0; i < list.projects.length; i++) {
const projectId = list.projects[i].project;
const [p] = _projects.filter((project: ProjectDocument) => project._id === projectId);
const [p] = _projects.filter((project: IProject) => project._id === projectId);
const projectAllocation = list.projects[i].allocation;
_sharedProject = {
id: p._id,
Expand Down Expand Up @@ -121,7 +122,10 @@ const Card = ({ list, onLike, isLoading, loadingList }: any) => {
<div className="flex items-center justify-between py-2">
{tags && tags.length > 0 ? (
<div className="flex">
<span className="px-2 py-1 text-sm text-customGray bg-customWhite rounded-md mr-2"> {tags[0]} </span>
<span className="px-2 py-1 text-sm text-customGray bg-customWhite rounded-md mr-2">
{" "}
{humanize(tags[0])}{" "}
</span>
{tags.length > 1 && (
<span className="px-2 py-1 text-sm text-customGray bg-customWhite rounded-md mr-2">
+{tags.length - 1}
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/components/lists/CreateList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const CreateList: React.FC<Props> = ({ isOpen, onClose }) => {
impactEvaluation,
tags,
projects: state.projects.map(project => ({
project: project.id,
project: project._id,
allocation: project.allocation,
})),
};
Expand Down
3 changes: 2 additions & 1 deletion packages/nextjs/components/lists/ListsPageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react";
import { ArrowsUpDownIcon, HeartIcon, ListBulletIcon, Squares2X2Icon } from "@heroicons/react/24/outline";
import { humanize } from "~~/utils/humanize";
import { shuffle } from "~~/utils/shuffle";

type CategoryInfo = {
Expand Down Expand Up @@ -121,7 +122,7 @@ function ListsPageHeader({ displayList, titleHeader, display, onCategoryChange,
active == `${category.category}` ? "bg-[#FF0520] text-white" : "bg-customWhite text-customGrayBtn"
}`}
>
{category.category}
{humanize(category.category)}
<span className="px-2 py-1 bg-white text-black font-bold rounded ml-2 ">{category.projectsCount}</span>
</button>
))}
Expand Down
41 changes: 28 additions & 13 deletions packages/nextjs/components/lists/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,64 @@ interface IPagination {
}

const Pagination: React.FC<IPagination> = ({ currentPage, totalPages, onPageChange }) => {
const range = (from: number, to: number) => {
return Array.from({ length: to - from + 1 }, (_, i) => from + i);
};

const renderPaginationItems = () => {
const pageRange = 5; // Number of pages to display at a time
const halfRange = Math.floor(pageRange / 2);
const startPage = Math.max(1, currentPage - halfRange);
const endPage = Math.min(totalPages, startPage + pageRange - 1);

const prevPage = currentPage > 1 ? currentPage - 1 : null;
const nextPage = currentPage < totalPages ? currentPage + 1 : null;

const pages = range(1, totalPages);

const pages = Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i);
return (
<>
{currentPage > 1 && (
<button
className="px-4 py-2 rounded-md font-normal text-base leading-6 font-inter bg-customWhite text-lightBlack hover:bg-customWhite"
onClick={() => onPageChange(1)}
>
First
</button>
)}
{prevPage && (
<button
className="px-4 py-2 rounded-md font-normal text-base leading-6 font-inter bg-customWhite text-lightBlack hover:bg-customWhite"
className="px-4 py-2 rounded-md font-normal text-base leading-6 font-inter bg-customWhite text-lightBlack hover:bg-customWhite"
onClick={() => onPageChange(prevPage)}
>
Previous
</button>
)}

{pages.map(page => (
<button
key={page}
className={`px-4 py-2 rounded-md font-normal text-base leading-6 font-inter ${
className={`px-4 py-2 rounded-md font-normal text-base leading-6 font-inter ${
currentPage === page
? "bg-[#FF0520] text-white"
: "border border-gray-300 bg-base-100 hover:bg-customWhite"
: "border border-gray-300 bg-base-100 hover:bg-customWhite"
}`}
onClick={() => onPageChange(page)}
>
{page}
</button>
))}

{currentPage < totalPages && (
<button
className="px-4 py-2 rounded-md font-normal text-base leading-6 font-inter bg-customWhite text-lightBlack hover:bg-customWhite"
onClick={() => onPageChange(totalPages)}
>
Last
</button>
)}

{totalPages > 1 && (
<button
disabled={!nextPage}
className={`px-4 py-2 rounded-md font-normal text-base leading-6 font-inter border border-gray-300 ${
!nextPage
? "bg-gray-300 dark:text-white cursor-not-allowed hover:bg-gray-300 hover:text-gray-500"
: " bg-base-100 hover:bg-customWhite"
? "bg-gray-300 dark:text-white cursor-not-allowed hover:bg-gray-300 hover:text-gray-500"
: "bg-base-100 hover:bg-customWhite"
}`}
onClick={() => onPageChange(nextPage ? nextPage : 1)}
>
Expand All @@ -58,7 +74,6 @@ const Pagination: React.FC<IPagination> = ({ currentPage, totalPages, onPageChan
</>
);
};

return <div className="flex space-x-2 py-16 px-4 justify-end">{renderPaginationItems()}</div>;
};

Expand Down
133 changes: 11 additions & 122 deletions packages/nextjs/components/op/btn/AddProjectButton.tsx
Original file line number Diff line number Diff line change
@@ -1,119 +1,20 @@
import React, { useEffect, useState } from "react";
import { FolderIcon } from "@heroicons/react/24/outline";
import { CheckBadgeIcon } from "@heroicons/react/24/solid";
import LoadingModal from "~~/components/op/modals/LoadingModal";
import SuccessModal from "~~/components/op/modals/SuccessModal";
import VoteModal from "~~/components/op/modals/VoteModal";
import { useBallot } from "~~/context/BallotContext";
import { Project as IProject } from "~~/context/BallotContext";
import { ProjectDocument } from "~~/models/Project";
import { isAddedToBallot } from "~~/utils/isAddedToBallot";

interface IAddProjectButton {
project: IProject & ProjectDocument;
interface IAddProjectButtonProps {
disabled?: boolean;
toggleEditModal?: boolean;
setEditBallotVote: (value: boolean) => void;
customClass?: string;
isAdded?: boolean;
newAllocation: number;
}

const AddProjectButton: React.FC<IAddProjectButton> = ({ disabled, project, toggleEditModal, customClass }) => {
const [isAdded, setIsAdded] = useState(false);
const { state, dispatch } = useBallot();
const [editBallotVote, setEditBallotVote] = useState(false);
const [isAllocationError, setIsAllocationError] = useState(false);

const [prevProjectAllocation] = state.projects.filter(item => item.id === project._id);
const [newAllocation, setNewAllocation] = useState<number>(prevProjectAllocation?.allocation ?? 0);

const [loadingMessage, setLoadingMessage] = useState("");
const [successMessage, setSuccessMessage] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [toggleInitialized, setToggleInitialized] = useState<boolean | undefined>(undefined);
// const modalRef = useRef(null);

useEffect(() => {
if (!state) return;
setIsAdded(false);
const isProjectInBallot = isAddedToBallot(state, project);
setIsAdded(isProjectInBallot);
}, [project, state]);

useEffect(() => {
if (toggleEditModal === undefined) return;
if (toggleInitialized) {
setEditBallotVote(true);
}
setToggleInitialized(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [toggleEditModal]);

const addProjectToBallot = () => {
const _name = project.name as string;
setNewAllocation(!Number.isNaN(newAllocation) && newAllocation > 0 ? newAllocation : 0);
dispatch({
type: "ADD_PROJECT",
project: {
id: project._id,
name: _name,
allocation: !Number.isNaN(newAllocation) && newAllocation > 0 ? newAllocation : 0,
},
});
};

const handleAllocationChange = (value: any) => {
setIsAllocationError(false);
let currentTotalAllocation = state.projects.reduce((sum, p) => sum + p.allocation, 0);
const currentProjectId = project._id;
// Ensure value is a number
value = Number(value);

if (isNaN(value)) {
value = Number.isNaN(newAllocation) ? 0 : newAllocation;
}

// Deduct the current project's allocation, since we're editing it
const currentProjectAllocation = state.projects.find(p => p.id === currentProjectId)?.allocation || 0;
currentTotalAllocation -= currentProjectAllocation;

const projectedTotal = value + currentTotalAllocation;

if (projectedTotal > state.totalTokens) {
value = state.totalTokens - currentTotalAllocation;
setIsAllocationError(true);
}

setNewAllocation(value);
};

const handleEditBallot = () => {
let message = "Saving distribution";
let completedMessage = "Distribution changed successfully";
if (!isAdded) {
message = "Adding project to ballot";
completedMessage = "Successfully added project";
addProjectToBallot();
} else {
dispatch({
type: "UPDATE_ALLOCATION",
projectId: project._id,
newAllocation,
});
}
setLoadingMessage(message);
setEditBallotVote(false);
setIsLoading(true);
// using setTimeout on loading and success modals for better UX
setTimeout(() => {
setIsLoading(false);
setIsSuccess(true);
setTimeout(() => {
setIsSuccess(false);
}, 2000);
}, 1000);
setSuccessMessage(completedMessage);
};

const AddProjectButton: React.FC<IAddProjectButtonProps> = ({
disabled,
setEditBallotVote,
customClass,
isAdded,
newAllocation,
}) => {
return (
<>
<button
Expand All @@ -136,18 +37,6 @@ const AddProjectButton: React.FC<IAddProjectButton> = ({ disabled, project, togg
? "0 OP allocated"
: "Add to Ballot"}
</button>
{editBallotVote && (
<VoteModal
project={project}
onClose={() => setEditBallotVote(false)}
allocation={newAllocation}
handleAddBallot={() => handleEditBallot()}
handleAllocationChange={handleAllocationChange}
isAllocationError={isAllocationError}
/>
)}
{isLoading && <LoadingModal message={loadingMessage} />}
{isSuccess && <SuccessModal message={successMessage} onClose={() => setIsSuccess(false)} />}
</>
);
};
Expand Down
4 changes: 2 additions & 2 deletions packages/nextjs/components/op/modals/AddListToBallotModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Import required modules and components
import React from "react";
import { IProjectData } from "../../../types/list";
import { IProjectList } from "../../../types/list";
// Import a custom button component
import CustomProjectButton from "../btn/CustomProjectButton";
import ProjectListCard from "../projects/ProjectListCard";
Expand All @@ -14,7 +14,7 @@ interface IAddListToBallotModal {
handleAddBallot: () => void;
listName: string;
userTotal: number;
projectList: IProjectData[];
projectList: IProjectList[];
edit: () => void;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Import required modules and components
import React from "react";
import { IProjectData } from "../../../types/list";
import { IProjectList } from "../../../types/list";
// Import a custom button component
import CustomProjectButton from "../btn/CustomProjectButton";
import ProjectListCardEditable from "../projects/ProjectListCardEditable";
Expand All @@ -12,7 +12,7 @@ import { ExclamationCircleIcon } from "@heroicons/react/24/outline";
interface IAlreadyOnBallotConflictModal {
onClose: () => void; // A function to be called when the modal is closed
handleAddBallot: () => void;
projectList: IProjectData[];
projectList: IProjectList[];
edit: () => void;
}

Expand Down
Loading