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

Feature/allocation #12

Merged
merged 16 commits into from
Oct 14, 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
126 changes: 126 additions & 0 deletions app/allocation/components/CategoryAllocation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import debounce from 'lodash.debounce';
import Image from 'next/image';
import { ChangeEventHandler, FC, useEffect, useRef } from 'react';
import { UnlockIcon } from '@/public/assets/icon-components/Unlock';
import { LockIcon } from '@/public/assets/icon-components/Lock';
import { roundFractions } from '../utils';

export interface Category {
id: number
imageSrc: string
title: string
description: string
projectCount: number
}

interface CategoryAllocationProps extends Category {
allocationPercentage: number
onDelegate: () => void
onScore: () => void
onLockClick: () => void
locked: boolean
onPercentageChange: (value: number) => void
}

const CategoryAllocation: FC<CategoryAllocationProps> = ({
imageSrc,
title,
description,
projectCount,
allocationPercentage,
onDelegate,
onScore,
onLockClick,
locked,
onPercentageChange,
}) => {
const inputRef = useRef<HTMLInputElement>(null);
const handleInputChange: ChangeEventHandler<HTMLInputElement> = debounce((event) => {
const value = event.target.value;
onPercentageChange(roundFractions(Number(value), 2));
}, 1500);

const handlePlus = debounce(() => {
const value = allocationPercentage;
onPercentageChange(Number(Math.min(value + 1, 100)));
}, 150);

const handleMinus = debounce(() => {
const value = allocationPercentage;
onPercentageChange(Math.max(Number(value - 1), 0));
}, 150);

useEffect(() => {
if (inputRef.current?.value) {
inputRef.current.value = `${allocationPercentage}`;
}
}, [allocationPercentage]);

return (
<div className="flex justify-between rounded-lg border p-4">
<div className="flex max-w-[75%] space-x-4">
<div className=" rounded-lg">
<Image src={imageSrc} alt={title} width={96} height={96} />
</div>
<div className="max-w-[70%] space-y-2">
<h3 className="text-lg font-semibold">{title}</h3>
<p className="text-sm text-gray-600">{description}</p>
<p className="mt-1 w-fit rounded-lg bg-gray-100 p-2 text-xs text-gray-800">
{projectCount}
{' '}
projects
</p>
</div>
</div>
<div className="flex w-fit flex-col gap-2">
<div className="flex items-center space-x-2">
<div className="flex justify-center gap-6 border px-10 py-2">
<button onClick={handleMinus} className="font-bold text-gray-500">-</button>
<div className="flex gap-0 rounded bg-white">
<input
onChange={handleInputChange}
ref={inputRef}
className="w-12 text-center font-semibold outline-none"
type="number"
defaultValue={allocationPercentage}
/>
<span> % </span>
</div>
<button onClick={handlePlus} className="font-bold text-gray-500">+</button>
</div>
<button onClick={onLockClick} className="text-gray-500">
{locked
? (
<LockIcon />
)
: (
<UnlockIcon />
)}
</button>
</div>
<div className="w-fit border bg-gray-50 px-[53px] py-2 text-sm text-gray-500">
{(allocationPercentage * 100000).toLocaleString()}
{' '}
OP
</div>
<div className="my-2 flex gap-2">
<button
onClick={onScore}
className="whitespace-nowrap rounded-md bg-primary px-4 py-2 text-sm font-medium text-white"
>
Score Projects
</button>
<button
onClick={onDelegate}
className="rounded-md border px-4 py-2 text-sm font-medium text-gray-700"
>
Delegate
</button>
</div>

</div>
</div>
);
};

export default CategoryAllocation;
63 changes: 63 additions & 0 deletions app/allocation/components/ConnectBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import Image from 'next/image';
import { WorldIdIcon } from '@/public/assets/icon-components/WorldIdIcon';
import { XIcon } from '@/public/assets/icon-components/XIcon';
import { WarpcastIcon } from '@/public/assets/icon-components/WarpcastIcon';

interface ConnectBoxProps {
onConnectWorldID: () => void
onConnectTwitter: () => void
onConnectFarcaster: () => void
}

const ConnectBox: React.FC<ConnectBoxProps> = ({
onConnectWorldID,
onConnectTwitter,
onConnectFarcaster,
}) => {
return (
<div className="max-w-md rounded-lg border bg-white p-6">
<h2 className="mb-4 w-full border-b pb-2 text-2xl font-medium">Your voting power</h2>

<div className="mb-2">
<h3 className="mb-2 text-lg font-semibold">Your badges</h3>
<button>
<Image src="/assets/images/badges.svg" alt="Badges" width={64} height={16} />
</button>
</div>

<p className="mb-4">Increase your voting power by connecting to WorldID</p>

<button
onClick={onConnectWorldID}
className="mb-4 flex w-full items-center justify-center gap-2 rounded-md bg-gray-100 px-4 py-2 text-gray-800"
>
<WorldIdIcon />
Connect with WorldID
</button>

<p className="mb-4 w-full border-t pt-4">
Check who delegated their voting power
to you? Connect your socials to know more.
</p>

<button
onClick={onConnectTwitter}
className="mb-2 flex w-full items-center justify-center gap-2 rounded-md bg-gray-100 px-4 py-2 text-gray-800"
>
<XIcon />
Connect with X (Twitter)
</button>

<button
onClick={onConnectFarcaster}
className="flex w-full items-center justify-center gap-2 rounded-md bg-gray-100 px-4 py-2 text-gray-800"
>
<WarpcastIcon />
Connect with Farcaster
</button>
</div>
);
};

export default ConnectBox;
50 changes: 50 additions & 0 deletions app/allocation/components/Slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as React from 'react';
import Slider, { SliderProps } from '@mui/material/Slider';
import { styled } from '@mui/material/styles';

const StyledSlider = styled(Slider)({
'color': '#c0c0c0',
'height': 8,
'& .MuiSlider-track': {
border: 'none',
},
'& .MuiSlider-thumb': {
'height': 24,
'width': 24,
'backgroundColor': '#fff',
'border': '2px solid #323232',
'&:focus, &:hover, &.Mui-active, &.Mui-focusVisible': {
boxShadow: 'inherit',
},
'&::before': {
display: 'none',
},
},
'& .MuiSlider-valueLabel': {
'lineHeight': 1.2,
'fontSize': 12,
'background': 'unset',
'padding': 0,
'width': 32,
'height': 32,
'borderRadius': '50% 50% 50% 0',
'backgroundColor': '#52af77',
'transformOrigin': 'bottom left',
'transform': 'translate(50%, -100%) rotate(-45deg) scale(0)',
'&::before': { display: 'none' },
'&.MuiSlider-valueLabelOpen': {
transform: 'translate(50%, -100%) rotate(-45deg) scale(1)',
},
'& > *': {
transform: 'rotate(45deg)',
},
},
});

export const CustomizedSlider: React.FC<SliderProps> = (props) => {
return (
<StyledSlider
{...props}
/>
);
};
Loading