-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
717 additions
and
310 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { useState } from 'react'; | ||
|
||
import { InfoIcon } from 'lucide-react'; | ||
import { isAddress } from 'viem'; | ||
|
||
import { Button } from '@ui/components/ui/button'; | ||
import { Input } from '@ui/components/ui/input'; | ||
|
||
export function DelegateView() { | ||
const [delegateAddress, setDelegateAddress] = useState(''); | ||
const isValidAddress = delegateAddress ? isAddress(delegateAddress) : false; | ||
|
||
return ( | ||
<div className="flex flex-col gap-y-2 py-2 px-3"> | ||
<p>Delegate Address</p> | ||
<Input | ||
placeholder="0x..." | ||
onChange={(e) => setDelegateAddress(e.target.value)} | ||
className={!isValidAddress && delegateAddress ? 'border-red-500' : ''} | ||
/> | ||
<div className="border border-yellow-200 text-yellow-200 text-xs flex items-center gap-3 rounded-md py-2.5 px-4 mt-2"> | ||
<InfoIcon className="h-5 w-5 flex-shrink-0" /> | ||
<span> | ||
You may delegate your voting power to any user, without transferring | ||
the tokens. You may revoke it, but the user will still be able to vote | ||
until the end of the current voting period. | ||
</span> | ||
</div> | ||
<Button | ||
className="w-full bg-accent text-black mt-4" | ||
disabled={!isValidAddress} | ||
> | ||
Delegate veION | ||
</Button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import { useState, useEffect, useMemo } from 'react'; | ||
|
||
import { format, addDays } from 'date-fns'; | ||
import { Calendar as CalendarIcon } from 'lucide-react'; | ||
|
||
import { Button } from '@ui/components/ui/button'; | ||
import { Calendar } from '@ui/components/ui/calendar'; | ||
import { | ||
Popover, | ||
PopoverContent, | ||
PopoverTrigger | ||
} from '@ui/components/ui/popover'; | ||
import { Separator } from '@ui/components/ui/separator'; | ||
import { Slider } from '@ui/components/ui/slider'; | ||
|
||
import AutoLock from './AutoLock'; | ||
import CustomTooltip from '../CustomTooltip'; | ||
|
||
export function ExtendView() { | ||
const [autoLock, setAutoLock] = useState(false); | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const [lockDuration, setLockDuration] = useState<string>('180'); | ||
const [lockDate, setLockDate] = useState<Date>(() => | ||
addDays(new Date(), 180) | ||
); | ||
const [selectedDuration, setSelectedDuration] = useState<number>(180); | ||
const [isCalendarOpen, setIsCalendarOpen] = useState(false); | ||
|
||
// Calculate the valid date range for the calendar | ||
const dateRange = useMemo(() => { | ||
const today = new Date(); | ||
return { | ||
minDate: addDays(today, 180), // Minimum 180 days from today | ||
maxDate: addDays(today, 730) // Maximum 730 days from today | ||
}; | ||
}, []); | ||
|
||
const durationLabels = { | ||
180: '180d', | ||
365: '1y', | ||
547: '1.5y', | ||
730: '2y' | ||
}; | ||
|
||
useEffect(() => { | ||
const newDate = addDays(new Date(), selectedDuration); | ||
setLockDate(newDate); | ||
setLockDuration(selectedDuration.toString()); | ||
}, [selectedDuration]); | ||
|
||
const handleDurationChange = (val: number[]) => { | ||
const duration = val[0]; | ||
setSelectedDuration(duration); | ||
}; | ||
|
||
const handleDateSelect = (date: Date | undefined) => { | ||
if (date) { | ||
setLockDate(date); | ||
// Calculate duration in days | ||
const durationInDays = Math.round( | ||
(date.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24) | ||
); | ||
|
||
// Clamp the duration between 180 and 730 days | ||
const clampedDuration = Math.max(180, Math.min(730, durationInDays)); | ||
setSelectedDuration(clampedDuration); | ||
setLockDuration(clampedDuration.toString()); | ||
setIsCalendarOpen(false); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col gap-y-2 py-2 px-3"> | ||
<div className="space-y-2"> | ||
<div className="flex items-center gap-2 text-xs text-white/60 tracking-wider mb-2"> | ||
<p>LOCK UNTIL</p> | ||
<CustomTooltip content="A longer lock period gives you more veION for the same amount of LPs, which means a higher voting power." /> | ||
</div> | ||
<div className="flex items-center justify-between"> | ||
<div className="text-sm text-white/60"> | ||
{format(lockDate, 'dd. MM. yyyy')} | ||
</div> | ||
<Popover | ||
open={isCalendarOpen} | ||
onOpenChange={setIsCalendarOpen} | ||
> | ||
<PopoverTrigger asChild> | ||
<Button | ||
variant="ghost" | ||
className="p-0 hover:bg-transparent" | ||
> | ||
<CalendarIcon className="h-4 w-4 text-white/60" /> | ||
</Button> | ||
</PopoverTrigger> | ||
<PopoverContent | ||
className="w-auto p-0 bg-grayUnselect border-white/10" | ||
sideOffset={5} | ||
> | ||
<Calendar | ||
mode="single" | ||
selected={lockDate} | ||
onSelect={handleDateSelect} | ||
disabled={{ | ||
before: dateRange.minDate, | ||
after: dateRange.maxDate | ||
}} | ||
defaultMonth={dateRange.minDate} | ||
/> | ||
</PopoverContent> | ||
</Popover> | ||
</div> | ||
<Slider | ||
value={[selectedDuration]} | ||
onValueChange={handleDurationChange} | ||
max={730} | ||
min={180} | ||
step={1} | ||
className="[&_[role=slider]]:bg-accent [&_[role=slider]]:border-0" | ||
/> | ||
<div className="w-full flex justify-between text-xs text-white/60"> | ||
{Object.entries(durationLabels).map(([days, label]) => ( | ||
<span | ||
key={days} | ||
className={selectedDuration >= Number(days) ? 'text-accent' : ''} | ||
> | ||
{label} | ||
</span> | ||
))} | ||
</div> | ||
</div> | ||
|
||
<AutoLock | ||
autoLock={autoLock} | ||
setAutoLock={setAutoLock} | ||
/> | ||
|
||
<Separator className="bg-white/10 my-4" /> | ||
|
||
<div className="flex w-full items-center justify-between text-xs text-white/50"> | ||
<div className="flex items-center gap-2"> | ||
VOTING POWER | ||
<CustomTooltip content="Your voting power diminishes each day closer to the end of the token lock period." /> | ||
</div> | ||
<p>0.00 veIon</p> | ||
</div> | ||
|
||
<div className="flex w-full items-center justify-between text-xs text-white/50"> | ||
LOCKED Until | ||
<p>28 Aug 2023 → {format(lockDate, 'dd MMM yyyy')}</p> | ||
</div> | ||
|
||
<Button className="w-full bg-accent text-black mt-4">Extend Lock</Button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { useState, useEffect } from 'react'; | ||
|
||
import { Button } from '@ui/components/ui/button'; | ||
import { Separator } from '@ui/components/ui/separator'; | ||
import { Slider } from '@ui/components/ui/slider'; | ||
import { getToken } from '@ui/utils/getStakingTokens'; | ||
|
||
import CustomTooltip from '../CustomTooltip'; | ||
import MaxDeposit from '../stake/MaxDeposit'; | ||
|
||
type IncreaseViewProps = { | ||
chain: string; | ||
}; | ||
|
||
export function IncreaseView({ chain }: IncreaseViewProps) { | ||
const utilizationMarks = [0, 25, 50, 75, 100]; | ||
const [veionAmount, setVeIonAmount] = useState(0); | ||
const [sliderValue, setSliderValue] = useState(0); | ||
const maxtoken = '1000'; | ||
|
||
useEffect(() => { | ||
const newSliderValue = (veionAmount / Number(maxtoken)) * 100; | ||
setSliderValue(newSliderValue); | ||
}, [veionAmount, maxtoken]); | ||
|
||
const handleInputChange = (val?: string) => { | ||
if (val !== undefined) { | ||
setVeIonAmount(Number(val)); | ||
} | ||
}; | ||
|
||
const handleSliderChange = (val: number[]) => { | ||
const newVal = val[0]; | ||
setSliderValue(newVal); | ||
const veionval = (newVal / 100) * Number(maxtoken); | ||
setVeIonAmount(veionval); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col gap-y-2 py-2 px-3"> | ||
<MaxDeposit | ||
headerText={'Lock Amount'} | ||
max={maxtoken} | ||
amount={String(veionAmount)} | ||
tokenName={'ion/eth LP'} | ||
token={getToken(+chain)} | ||
handleInput={handleInputChange} | ||
chain={+chain} | ||
/> | ||
<div className="w-full mx-auto mt-3 mb-5"> | ||
<div className="w-full mb-2 text-xs flex justify-between text-white/25"> | ||
{utilizationMarks.map((mark) => ( | ||
<span | ||
key={mark} | ||
className={sliderValue >= mark ? 'text-accent' : ''} | ||
> | ||
{mark}% | ||
</span> | ||
))} | ||
</div> | ||
<Slider | ||
value={[sliderValue]} | ||
onValueChange={handleSliderChange} | ||
max={100} | ||
step={1} | ||
className="[&_[role=slider]]:bg-accent [&_[role=slider]]:border-0" | ||
/> | ||
</div> | ||
<Separator className="bg-white/10 my-4" /> | ||
|
||
<div className="flex w-full items-center justify-between text-xs text-white/50"> | ||
<div className="flex items-center gap-2"> | ||
VOTING POWER | ||
<CustomTooltip content="Your voting power diminishes each day closer to the end of the token lock period." /> | ||
</div> | ||
<p>0.00 veIon</p> | ||
</div> | ||
<div className="flex w-full items-center justify-between text-xs text-white/50"> | ||
<div className="flex items-center gap-2"> | ||
LP <CustomTooltip content="Info regarding the locked BLP." /> | ||
</div> | ||
<p>67.90 veIon</p> | ||
</div> | ||
<Button className="w-full bg-accent text-black mt-4"> | ||
Increase Locked Amount | ||
</Button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import Image from 'next/image'; | ||
|
||
import type { InfoBlock } from '@ui/constants/mock'; | ||
|
||
import CustomTooltip from '../CustomTooltip'; | ||
|
||
interface InfoBlockProps { | ||
block: InfoBlock; | ||
} | ||
|
||
const InfoBlockComponent: React.FC<InfoBlockProps> = ({ block }) => ( | ||
<div className="flex flex-col gap-1 mt-3"> | ||
<div className="text-white/60 text-xs flex items-center"> | ||
{block.label} | ||
<CustomTooltip content={block.infoContent} /> | ||
</div> | ||
<div className="text-white/60 text-xs flex items-center"> | ||
{block.icon && ( | ||
<Image | ||
alt={`${block.label} icon`} | ||
className="w-6 h-6 inline-block" | ||
src={block.icon} | ||
width={24} | ||
height={24} | ||
/> | ||
)} | ||
<span className="text-white text-sm ml-1">{block.value}</span> | ||
</div> | ||
</div> | ||
); | ||
|
||
export default InfoBlockComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.