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

adds feed table #62

Merged
merged 2 commits into from
Dec 12, 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
6 changes: 4 additions & 2 deletions app/pufflings/family/[id]/child/[childId]/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use server';

import FeedChart from '@/app/ui/charts/feedChart';
import DeleteButton from '@/app/ui/deleteButton';
import Recents from '@/app/ui/recents';
import { getChild } from '@/lib/child';
Expand All @@ -23,14 +24,15 @@ const Dashboard = async ({
const childInfo = await getChild(parseInt(childId));

return (
<>
<div className='flex flex-col gap-10'>
<Recents
familyId={id}
childId={childId}
lastFeed={lastFeed as LastFeed}
lastSleep={lastSleep as LastSleep}
lastDiaper={lastDiaper as LastDiaper}
/>
<FeedChart childId={childId} />
<div className='mt-10 flex flex-row place-self-center'>
<Link
href={`/pufflings/family/${id}/child/${childId}/profile`}
Expand All @@ -40,7 +42,7 @@ const Dashboard = async ({
</Link>
<DeleteButton childId={childId} familyId={id} />
</div>
</>
</div>
);
};

Expand Down
112 changes: 112 additions & 0 deletions app/ui/charts/feedChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
'use client';

import { useEffect, useState } from 'react';
import { ResponsiveLine, Line } from '@nivo/line';
import { getFeedChart } from '@/lib/feed';
import { Radio, RadioGroup } from '@headlessui/react';
import Loading from '@/app/loading';
import { Spinner } from '@nextui-org/spinner';

const filterOptions = [
{ name: 'Last 7 days', value: 7 },
{ name: 'Last 30 days', value: 30 },
{ name: 'All-time', value: 100000 },
];

const FeedChart = ({ childId }: { childId: string }) => {
const [isLoading, setIsLoading] = useState(true);
const [feedChartData, setFeedChartData] = useState();
const [filter, setFilter] = useState(filterOptions[2]);

useEffect(() => {
fetchFeedChart();
}, [filter]);

const getFilterDate = () => {
const days = filter.value;
const date = new Date();
date.setDate(date.getDate() - days);
return date.toISOString();
};

const fetchFeedChart = async () => {
const feedData = await getFeedChart(childId, getFilterDate());
setFeedChartData(feedData as any);
setIsLoading(false);
};

const updateTable = async (filter: any) => {
setIsLoading(true);
setFilter(filter);
};

if (!feedChartData) {
return <Loading />;
}

return (
<div className='overflow-hidden rounded-lg bg-white shadow'>
<div className='px-4 py-5 sm:px-6'>
<div>
<div className='flex flex-wrap items-center gap-6 px-4 sm:flex-nowrap sm:px-6 lg:px-8'>
<h1 className='text-3xl font-semibold'>Feed Chart</h1>
<RadioGroup
value={filter}
onChange={updateTable}
className='order-last mt-2 flex grid w-full grid-cols-3 gap-3 gap-x-8 text-sm/6 font-semibold sm:order-none sm:w-auto sm:grid-cols-6 sm:border-l sm:border-gray-200 sm:pl-6 sm:text-sm/7'
>
{filterOptions.map((option) => (
<Radio
key={option.name}
value={option}
className={
'flex cursor-pointer items-center justify-center rounded-md bg-white px-2 py-3 text-sm font-semibold uppercase text-gray-900 ring-1 ring-gray-300 hover:bg-gray-50 focus:outline-none data-[checked]:bg-indigo-600 data-[checked]:text-white data-[checked]:ring-0 data-[focus]:data-[checked]:ring-2 data-[focus]:ring-2 data-[focus]:ring-indigo-600 data-[focus]:ring-offset-2 data-[checked]:hover:bg-indigo-500 sm:flex-1 [&:not([data-focus])]:[&:not([data-checked])]:ring-inset'
}
>
{isLoading && option.name == filter.name ? (
<Spinner color='white' size='sm' />
) : (
option.name
)}
</Radio>
))}
</RadioGroup>
</div>
</div>
</div>
<div className='h-64 bg-gray-50'>
<ResponsiveLine
curve='monotoneX'
data={feedChartData}
margin={{ top: 50, right: 50, bottom: 50, left: 60 }}
xScale={{
type: 'time',
min: 'auto',
max: 'auto',
}}
enablePoints={false}
axisLeft={{
legendOffset: 12,
}}
xFormat={'time:%b %d'}
pointLabel='data.yFormatted'
enableTouchCrosshair={true}
useMesh={true}
axisTop={null}
axisRight={null}
axisBottom={{
tickSize: 5,
tickPadding: 5,
tickRotation: 40,
legendOffset: 36,
legendPosition: 'middle',
truncateTickAt: 4,
format: '%b %d',
}}
/>
</div>
</div>
);
};

export default FeedChart;
28 changes: 28 additions & 0 deletions lib/feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,31 @@ export const getLastFeed = async (childId: number) => {
take: 1,
});
};

export const getFeedChart = async (childId: string, filter: string) => {
const results = await prisma.feed.findMany({
where: {
child_id: parseInt(childId),
start_time: { gte: new Date(filter) },
},
orderBy: {
start_time: 'asc',
},
select: {
start_time: true,
amount: true,
},
});

return [
{
id: 'feed',
data: results.map((result) => {
return {
x: result.start_time,
y: result.amount?.toNumber(),
};
}),
},
];
};
131 changes: 131 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
"@fortawesome/free-regular-svg-icons": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
"@headlessui/react": "^2.2.0",
"@heroicons/react": "^2.2.0",
"@nextui-org/dropdown": "^2.1.31",
"@nextui-org/system": "^2.2.6",
"@nextui-org/theme": "^2.2.11",
"@nivo/bar": "^0.88.0",
"@nivo/core": "^0.88.0",
"@nivo/line": "^0.88.0",
"@prisma/client": "^5.18.0",
Expand Down
Loading