-
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.
feat(solidr-front-next): migrate members tab components
- Loading branch information
Teddy CHAMBARD
committed
Aug 20, 2024
1 parent
fd01361
commit d068e7a
Showing
17 changed files
with
917 additions
and
77 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
104 changes: 104 additions & 0 deletions
104
...onts/solidr-front-next/src/app/sessions/[sessionId]/components/SessionAddMemberDialog.tsx
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,104 @@ | ||
import React, { Suspense, useState } from 'react'; | ||
import { useForm } from 'react-hook-form-mui'; | ||
import { DialogTitle } from '@headlessui/react'; | ||
import { useRecoilValue } from 'recoil'; | ||
import { useAnchorWallet } from '@solana/wallet-adapter-react'; | ||
import { Wallet } from '@coral-xyz/anchor'; | ||
import { sessionCurrentState } from '@/store/sessions'; | ||
import { PublicKey } from '@solana/web3.js'; | ||
import { useTranslations } from 'next-intl'; | ||
import Dialog from '@/components/Dialog'; | ||
import { useSolidrClient } from '@/providers/solidr/SolidrClientContext'; | ||
|
||
interface IAddMemberDialogProps { | ||
dialogVisible: boolean; | ||
setDialogVisible: React.Dispatch<React.SetStateAction<boolean>>; | ||
} | ||
|
||
interface IRegisterMemberParams { | ||
address: string; | ||
memberName: string; | ||
} | ||
|
||
export default ({ dialogVisible, setDialogVisible }: IAddMemberDialogProps) => { | ||
|
||
const t = useTranslations(); | ||
|
||
const anchorWallet = useAnchorWallet() as Wallet; | ||
const solidrClient = useSolidrClient(); | ||
const { session } = useRecoilValue(sessionCurrentState); | ||
|
||
const [formData, setFormData] = useState<Partial<IRegisterMemberParams>>({}); | ||
|
||
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm({ | ||
defaultValues: formData, | ||
}); | ||
|
||
const onSubmit = async (data: Partial<IRegisterMemberParams>) => { | ||
if (!solidrClient || !session || !data.address || !data.memberName) return; | ||
setFormData(data); | ||
await solidrClient.addSessionMember(anchorWallet, session.sessionId, new PublicKey(data.address), data.memberName); | ||
setDialogVisible(false); | ||
}; | ||
|
||
if (!anchorWallet || !solidrClient || !session) return <Suspense />; | ||
|
||
return ( | ||
<Dialog isOpen={dialogVisible} onClose={() => setDialogVisible(false)}> | ||
<div className="sm:flex sm:items-start"> | ||
<div className="mt-3 text-center sm:mt-0 sm:text-center"> | ||
<DialogTitle as="h3" className="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200"> | ||
{t('session.members.add.title')} | ||
</DialogTitle> | ||
</div> | ||
<hr className="my-4 border-gray-300 dark:border-gray-700" /> | ||
</div> | ||
<div className="mt-5 sm:mt-4"> | ||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4 sm:space-y-6"> | ||
<div> | ||
<label className="block text-gray-900 dark:text-white mb-1" htmlFor="address"> | ||
{t('session.members.add.form.address.label')} | ||
</label> | ||
<input | ||
type="text" | ||
id="address" | ||
{...register('address', { required: true })} | ||
className="w-full px-4 py-2 text-gray-900 dark:text-white bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-customBlue focus:outline-none" | ||
/> | ||
{errors.address && <span className="text-red-500 text-sm">{t('session.members.add.form.address.required')}</span>} | ||
</div> | ||
|
||
<div> | ||
<label className="block text-gray-900 dark:text-white mb-1" htmlFor="memberName"> | ||
{t('session.members.add.form.memberName.label')} | ||
</label> | ||
<input | ||
type="text" | ||
id="memberName" | ||
{...register('memberName', { required: true })} | ||
className="w-full px-4 py-2 text-gray-900 dark:text-white bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-customBlue focus:outline-none" | ||
/> | ||
{errors.memberName && <span className="text-red-500 text-sm">{t('session.member.add.form.memberName.required')}</span>} | ||
</div> | ||
|
||
<div className="flex space-x-4 pt-4"> | ||
<button | ||
type="submit" | ||
disabled={isSubmitting} | ||
className="w-full px-4 py-2 bg-customBlue hover:bg-customBlueLight text-white font-semibold rounded-lg focus:ring-2 focus:ring-customBlue focus:outline-none" | ||
> | ||
{t('common.submit')} > | ||
</button> | ||
<button | ||
type="button" | ||
className="px-4 py-2 text-customBlue hover:text-customBlueLight font-semibold focus:outline-none" | ||
onClick={() => setDialogVisible(false)} | ||
> | ||
{t('common.cancel')} | ||
</button> | ||
</div> | ||
</form> | ||
</div> | ||
</Dialog> | ||
); | ||
}; |
115 changes: 115 additions & 0 deletions
115
packages/fronts/solidr-front-next/src/app/sessions/[sessionId]/components/SessionBalance.tsx
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,115 @@ | ||
"use client"; | ||
|
||
import { useRecoilValue } from 'recoil'; | ||
import { sessionCurrentState } from '@/store/sessions'; | ||
import { Bar } from 'react-chartjs-2'; | ||
import { BarElement, CategoryScale, Chart as ChartJS, LinearScale, Tooltip as ChartTooltip, ChartOptions } from 'chart.js/auto'; | ||
import { hexToRgba, stringToColor } from '@/services/colors'; | ||
import { useTheme } from 'next-themes'; | ||
|
||
ChartJS.register(BarElement, CategoryScale, LinearScale, ChartTooltip); | ||
|
||
export default () => { | ||
const { theme } = useTheme(); | ||
const sessionCurrent = useRecoilValue(sessionCurrentState); | ||
|
||
const sortedBalances = Object.values(sessionCurrent.balances).sort((a, b) => { | ||
// Sort in descending order, with positive balances first, then negative balances | ||
if (a.balance >= 0 && b.balance >= 0) { | ||
return b.balance - a.balance; | ||
} else if (a.balance < 0 && b.balance < 0) { | ||
return a.balance - b.balance; | ||
} else { | ||
return b.balance >= 0 ? -1 : 1; | ||
} | ||
}); | ||
|
||
return <Bar | ||
data={{ | ||
labels: sortedBalances.map((balance) => sessionCurrent.members[balance.owner.toString()].name), | ||
datasets: [ | ||
{ | ||
data: sortedBalances.map((balance) => balance.balance), | ||
backgroundColor: sortedBalances.map((balance) => hexToRgba(stringToColor(balance.owner.toString()), 1).toString()), | ||
borderColor: sortedBalances.map((balance) => stringToColor(balance.owner.toString())), | ||
hoverBackgroundColor: sortedBalances.map((balance) => hexToRgba(stringToColor(balance.owner.toString()), 0.5).toString()), | ||
barPercentage: 0.9, | ||
borderWidth: 1, | ||
}, | ||
], | ||
}} | ||
options={{ | ||
plugins: { | ||
title: { | ||
display: false, | ||
text: 'balance of costs', | ||
position: 'bottom' as const, | ||
}, | ||
legend: { | ||
display: false, | ||
}, | ||
customLabels: { | ||
font: { | ||
size: 12, | ||
weight: 'bold', | ||
}, | ||
}, | ||
} as any, | ||
scales: { | ||
x: { | ||
display: false, // Hide x-axis completely | ||
}, | ||
y: { | ||
display: true, // Hide y-axis labels and ticks | ||
beginAtZero: true, | ||
grid: { | ||
drawBorder: false, | ||
color: (context: any) => { | ||
if (context.tick.value === 0) { | ||
return theme === 'light' ? 'rgba(0, 0, 0, 0.1)' : 'rgba(255, 255, 255, 0.1)'; // Color of the zero line | ||
} | ||
return 'rgba(0, 0, 0, 0)'; // Transparent color for other grid lines | ||
}, | ||
} as any, | ||
ticks: { | ||
display: false, | ||
}, | ||
border: { | ||
display: false, | ||
}, | ||
}, | ||
}, | ||
layout: { | ||
padding: { | ||
top: 40, | ||
right: 40, | ||
bottom: 40, | ||
left: 40, | ||
}, | ||
}, | ||
maintainAspectRatio: false, // Set this to false to allow the chart to resize freely | ||
responsive: true, // Set this to true to make the chart responsive | ||
}} | ||
plugins={[{ | ||
id: 'customLabels', | ||
afterDatasetsDraw(chart, args, pluginOptions) { | ||
const { ctx, data, scales } = chart; | ||
|
||
ctx.save(); | ||
ctx.font = `${pluginOptions?.font.weight} ${pluginOptions?.font.size}px sans-serif`; | ||
ctx.textAlign = 'center'; | ||
|
||
data.datasets[0].data.forEach((value, index) => { | ||
const x = scales.x.getPixelForValue(index); | ||
const y = scales.y.getPixelForValue(Number(value)); | ||
|
||
ctx.fillStyle = Number(value) >= 0 ? '#1dc17d' : '#e36f6f'; | ||
const yPos = Number(value) >= 0 ? y - 10 : y + 20; | ||
ctx.fillText(`${Number(value).toFixed(2)}$`, x, yPos); | ||
}); | ||
|
||
ctx.restore(); | ||
}, | ||
}]} | ||
/>; | ||
}; |
Oops, something went wrong.