-
Notifications
You must be signed in to change notification settings - Fork 1
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
1 parent
a6bc0e2
commit 77fd361
Showing
16 changed files
with
930 additions
and
1,009 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,27 @@ | ||
import { retrieveProjectData } from "../_services/buildProjectHome"; | ||
import { StrategyCard } from "../_components/StrategyCard"; | ||
import Markdown from "react-markdown"; | ||
import rehypeRaw from "rehype-raw"; | ||
import { retrieveProjectData } from '../_services/buildProjectHome'; | ||
import { StrategyCard } from '../_components/StrategyCard'; | ||
import Markdown from 'react-markdown'; | ||
import rehypeRaw from 'rehype-raw'; | ||
|
||
interface homeProps { | ||
params: { | ||
projectName: string; | ||
}; | ||
params: { | ||
projectName: string; | ||
}; | ||
} | ||
|
||
export default async function ProjectHome({ params }: homeProps) { | ||
const projectData = await retrieveProjectData(params.projectName); | ||
const projectData = await retrieveProjectData(params.projectName); | ||
|
||
return ( | ||
<div className="flex flex-col lg:grid grid-cols-4 xl:grid-cols-5 flex-grow w-full"> | ||
<div className="col-span-2 prose p-8 h-full"> | ||
<Markdown rehypePlugins={[rehypeRaw]}> | ||
{projectData.webappMDText} | ||
</Markdown> | ||
</div> | ||
<div className="flex flex-col gap-y-4 col-span-2 xl:col-span-3 justify-start bg-gray-50 p-8 border-lg border-gray-100"> | ||
{projectData.yamlDatas.map((data) => ( | ||
<StrategyCard data={data} /> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
return ( | ||
<div className="flex flex-col lg:grid grid-cols-4 xl:grid-cols-5 flex-grow w-full"> | ||
<div className="col-span-2 prose p-8 h-full"> | ||
<Markdown rehypePlugins={[rehypeRaw]}>{projectData.webappMDText}</Markdown> | ||
</div> | ||
<div className="flex flex-col gap-y-4 col-span-2 xl:col-span-3 justify-start bg-gray-50 p-8 border-lg border-gray-100"> | ||
{projectData.yamlDatas.map((data, i) => ( | ||
<StrategyCard key={i} data={data} /> | ||
))} | ||
</div> | ||
</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 |
---|---|---|
@@ -1,31 +1,31 @@ | ||
"use client"; | ||
'use client'; | ||
|
||
import { useRouter } from "nextjs-toploader/app"; | ||
import { Button } from "flowbite-react"; | ||
import { YamlData } from "../_types/yamlData"; | ||
import { useRouter } from 'nextjs-toploader/app'; | ||
import { Button } from 'flowbite-react'; | ||
import { YamlData } from '../_types/yamlData'; | ||
|
||
export const DeploymentCard = ({ | ||
deployment, | ||
slug, | ||
deployment, | ||
slug | ||
}: { | ||
deployment: YamlData["gui"]["deployments"][0]; | ||
slug: string; | ||
deployment: YamlData['gui']['deployments'][0]; | ||
slug: string; | ||
}) => { | ||
const router = useRouter(); | ||
const currentHostname = window.location.hostname; | ||
const handleClick = () => { | ||
router.push(`${slug}/${deployment.deployment}`); | ||
}; | ||
const router = useRouter(); | ||
|
||
return ( | ||
<div className="border rounded-lg p-4 flex flex-col gap-y-8 bg-white justify-between"> | ||
<div className="flex flex-col gap-y-4"> | ||
<div className="text-lg font-semibold">{deployment.name}</div> | ||
<div className="text-gray-500">{deployment.description}</div> | ||
</div> | ||
<Button color="primary" size="sm" onClick={handleClick}> | ||
Deploy | ||
</Button> | ||
</div> | ||
); | ||
const handleClick = () => { | ||
router.push(`${slug}/${deployment.deployment}`); | ||
}; | ||
|
||
return ( | ||
<div className="border rounded-lg p-4 flex flex-col gap-y-8 bg-white justify-between"> | ||
<div className="flex flex-col gap-y-4"> | ||
<div className="text-lg font-semibold">{deployment.name}</div> | ||
<div className="text-gray-500">{deployment.description}</div> | ||
</div> | ||
<Button color="primary" size="sm" onClick={handleClick}> | ||
Deploy | ||
</Button> | ||
</div> | ||
); | ||
}; |
Large diffs are not rendered by default.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,158 +1,154 @@ | ||
"use client"; | ||
import { useForm } from "react-hook-form"; | ||
import { z } from "zod"; | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { Button } from "@/components/ui/button"; | ||
'use client'; | ||
import { useForm } from 'react-hook-form'; | ||
import { z } from 'zod'; | ||
import { zodResolver } from '@hookform/resolvers/zod'; | ||
import { Button } from '@/components/ui/button'; | ||
import { | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
} from "@/components/ui/form"; | ||
import { Input } from "@/components/ui/input"; | ||
import { useEffect, useState } from "react"; | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage | ||
} from '@/components/ui/form'; | ||
import { Input } from '@/components/ui/input'; | ||
import { useEffect, useState } from 'react'; | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@/components/ui/dialog"; | ||
import { useWriteContract } from "wagmi"; | ||
import { orderBookJson } from "@/public/_abis/OrderBook"; | ||
import { parseUnits, formatUnits } from "viem"; | ||
Dialog, | ||
DialogContent, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger | ||
} from '@/components/ui/dialog'; | ||
import { useWriteContract } from 'wagmi'; | ||
import { orderBookJson } from '@/public/_abis/OrderBook'; | ||
import { parseUnits, formatUnits } from 'viem'; | ||
|
||
const formSchema = z.object({ | ||
withdrawalAmount: z.preprocess( | ||
(value) => Number(value), | ||
z.number().min(0, "Amount must be a positive number") | ||
), | ||
withdrawalAmount: z.preprocess( | ||
(value) => Number(value), | ||
z.number().min(0, 'Amount must be a positive number') | ||
) | ||
}); | ||
|
||
interface Vault { | ||
token: any; | ||
vaultId: any; | ||
balance: any; | ||
orderbook: any; | ||
token: any; | ||
vaultId: any; | ||
balance: any; | ||
orderbook: any; | ||
} | ||
|
||
interface WithdrawalModalProps { | ||
vault: Vault; | ||
vault: Vault; | ||
} | ||
|
||
export const WithdrawalModal = ({ vault }: WithdrawalModalProps) => { | ||
const { writeContractAsync } = useWriteContract(); | ||
const [open, setOpen] = useState(false); | ||
const [rawAmount, setRawAmount] = useState<string>("0"); // Store the raw 18-decimal amount | ||
const { writeContractAsync } = useWriteContract(); | ||
const [open, setOpen] = useState(false); | ||
const [rawAmount, setRawAmount] = useState<string>('0'); // Store the raw 18-decimal amount | ||
|
||
const [error, setError] = useState<string | null>(null); | ||
const [error, setError] = useState<string | null>(null); | ||
|
||
useEffect(() => { | ||
setError(null); | ||
if (BigInt(rawAmount) > BigInt(vault.balance)) { | ||
setError("Amount exceeds vault balance"); | ||
} | ||
}, [rawAmount, vault.balance]); | ||
useEffect(() => { | ||
setError(null); | ||
if (BigInt(rawAmount) > BigInt(vault.balance)) { | ||
setError('Amount exceeds vault balance'); | ||
} | ||
}, [rawAmount, vault.balance]); | ||
|
||
// Vault balance in human-readable format (i.e., converted from 18 decimals) | ||
const readableBalance = formatUnits(vault.balance, vault.token.decimals); | ||
// Vault balance in human-readable format (i.e., converted from 18 decimals) | ||
const readableBalance = formatUnits(vault.balance, vault.token.decimals); | ||
|
||
// Define your form. | ||
const form = useForm<z.infer<typeof formSchema>>({ | ||
resolver: zodResolver(formSchema), | ||
defaultValues: { | ||
withdrawalAmount: 0, | ||
}, | ||
}); | ||
// Define your form. | ||
const form = useForm<z.infer<typeof formSchema>>({ | ||
resolver: zodResolver(formSchema), | ||
defaultValues: { | ||
withdrawalAmount: 0 | ||
} | ||
}); | ||
|
||
const withdraw = async (amount: string) => { | ||
// Send raw value to the contract (no conversion needed here) | ||
await writeContractAsync({ | ||
abi: orderBookJson.abi, | ||
address: vault.orderbook.id, | ||
functionName: "withdraw2", | ||
args: [vault.token.address, BigInt(vault.vaultId), BigInt(amount), []], | ||
}); | ||
}; | ||
const withdraw = async (amount: string) => { | ||
// Send raw value to the contract (no conversion needed here) | ||
await writeContractAsync({ | ||
abi: orderBookJson.abi, | ||
address: vault.orderbook.id, | ||
functionName: 'withdraw2', | ||
args: [vault.token.address, BigInt(vault.vaultId), BigInt(amount), []] | ||
}); | ||
}; | ||
|
||
const handleMaxClick = () => { | ||
// Set the form field to the readable max balance for display | ||
form.setValue("withdrawalAmount", parseFloat(readableBalance)); | ||
// Set the raw balance directly | ||
setRawAmount(vault.balance); // Use raw vault balance directly | ||
form.setFocus("withdrawalAmount"); // Optional: focus the field after setting value | ||
}; | ||
const handleMaxClick = () => { | ||
// Set the form field to the readable max balance for display | ||
form.setValue('withdrawalAmount', parseFloat(readableBalance)); | ||
// Set the raw balance directly | ||
setRawAmount(vault.balance); // Use raw vault balance directly | ||
form.setFocus('withdrawalAmount'); // Optional: focus the field after setting value | ||
}; | ||
|
||
const handleUserChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
const userInput = e.target.value; | ||
form.setValue("withdrawalAmount", parseFloat(userInput)); | ||
const handleUserChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
const userInput = e.target.value; | ||
form.setValue('withdrawalAmount', parseFloat(userInput)); | ||
|
||
// Update the raw amount based on the user input (convert back to raw value) | ||
if (userInput) { | ||
try { | ||
const parsedRawAmount = parseUnits( | ||
userInput, | ||
vault.token.decimals | ||
).toString(); | ||
setRawAmount(parsedRawAmount); // Update raw amount on every user change | ||
} catch (err) { | ||
setRawAmount("0"); // Fallback to 0 if input is invalid | ||
} | ||
} else { | ||
setRawAmount("0"); // Fallback to 0 if input is empty | ||
} | ||
}; | ||
// Update the raw amount based on the user input (convert back to raw value) | ||
if (userInput) { | ||
try { | ||
const parsedRawAmount = parseUnits(userInput, vault.token.decimals).toString(); | ||
setRawAmount(parsedRawAmount); // Update raw amount on every user change | ||
} catch { | ||
setRawAmount('0'); // Fallback to 0 if input is invalid | ||
} | ||
} else { | ||
setRawAmount('0'); // Fallback to 0 if input is empty | ||
} | ||
}; | ||
|
||
return ( | ||
<Dialog open={open} onOpenChange={setOpen}> | ||
<DialogTrigger> | ||
<Button>Withdraw</Button> | ||
</DialogTrigger> | ||
<DialogContent className="bg-white"> | ||
<DialogHeader> | ||
<DialogTitle>Withdraw</DialogTitle> | ||
<Form {...form}> | ||
<form | ||
onSubmit={form.handleSubmit(async () => { | ||
// Always submit the raw amount stored in state | ||
await withdraw(rawAmount); | ||
setOpen(false); | ||
})} | ||
className="space-y-8" | ||
> | ||
<FormField | ||
control={form.control} | ||
name="withdrawalAmount" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Amount</FormLabel> | ||
<FormControl> | ||
{/* Use onChange to listen to user typing */} | ||
<Input | ||
placeholder="0" | ||
{...field} | ||
type="number" | ||
step="0.000000000000000001" // 18 decimals | ||
onChange={handleUserChange} // Listen for user typing | ||
/> | ||
</FormControl> | ||
<FormMessage>{error}</FormMessage> | ||
<Button size="sm" type="button" onClick={handleMaxClick}> | ||
Max | ||
</Button> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<Button type="submit" disabled={!!error}> | ||
Submit | ||
</Button> | ||
</form> | ||
</Form> | ||
</DialogHeader> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
return ( | ||
<Dialog open={open} onOpenChange={setOpen}> | ||
<DialogTrigger> | ||
<Button>Withdraw</Button> | ||
</DialogTrigger> | ||
<DialogContent className="bg-white"> | ||
<DialogHeader> | ||
<DialogTitle>Withdraw</DialogTitle> | ||
<Form {...form}> | ||
<form | ||
onSubmit={form.handleSubmit(async () => { | ||
// Always submit the raw amount stored in state | ||
await withdraw(rawAmount); | ||
setOpen(false); | ||
})} | ||
className="space-y-8"> | ||
<FormField | ||
control={form.control} | ||
name="withdrawalAmount" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Amount</FormLabel> | ||
<FormControl> | ||
{/* Use onChange to listen to user typing */} | ||
<Input | ||
placeholder="0" | ||
{...field} | ||
type="number" | ||
step="0.000000000000000001" // 18 decimals | ||
onChange={handleUserChange} // Listen for user typing | ||
/> | ||
</FormControl> | ||
<FormMessage>{error}</FormMessage> | ||
<Button size="sm" type="button" onClick={handleMaxClick}> | ||
Max | ||
</Button> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<Button type="submit" disabled={!!error}> | ||
Submit | ||
</Button> | ||
</form> | ||
</Form> | ||
</DialogHeader> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
}; |
Oops, something went wrong.