Skip to content

Commit

Permalink
Merge pull request #62 from kmchandler/feedchart
Browse files Browse the repository at this point in the history
adds feed table
  • Loading branch information
rechandler authored Dec 12, 2024
2 parents 8ee1dec + 8799f8f commit 356103a
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 2 deletions.
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

0 comments on commit 356103a

Please sign in to comment.