Skip to content
Open
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
25 changes: 13 additions & 12 deletions ui/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import clsx from 'clsx';
import {ComponentProps} from 'react';

import {
ArrowLeftStartOnRectangleIcon, // ArrowTrendingUpIcon,
ArrowLeftStartOnRectangleIcon,
ArrowTrendingUpIcon,
PlusIcon,
UserIcon,
UsersIcon,
Expand Down Expand Up @@ -81,17 +82,17 @@ export default function Sidebar(props: ComponentProps<'div'>) {
<UserIcon className="size-5" />
<div className="text-sm font-medium">Friends</div>
</Link>
{/*<Link*/}
{/* to="/activity"*/}
{/* className={clsx(*/}
{/* 'flex items-center gap-x-3.5 rounded-md px-3 py-2 text-gray-600 transition-colors',*/}
{/* 'hover:bg-gray-100 hover:text-gray-800',*/}
{/* '[&.active]:bg-brand-50 [&.active]:text-brand-700 [&.active]:ring-1 [&.active]:ring-brand-200'*/}
{/* )}*/}
{/*>*/}
{/* <ArrowTrendingUpIcon className="size-5" />*/}
{/* <div className="text-sm font-medium">Activity</div>*/}
{/*</Link>*/}
<Link
to="/activity"
className={clsx(
'flex items-center gap-x-3.5 rounded-md px-3 py-2 text-gray-600 transition-colors',
'hover:bg-gray-100 hover:text-gray-800',
'[&.active]:bg-brand-50 [&.active]:text-brand-700 [&.active]:ring-1 [&.active]:ring-brand-200'
)}
>
<ArrowTrendingUpIcon className="size-5" />
<div className="text-sm font-medium">Activity</div>
</Link>
</div>

<div className="space-y-1">
Expand Down
11 changes: 11 additions & 0 deletions ui/src/components/common/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ const button = tv({
// Base
'border-red-400 data-[hovered]:border-red-500 data-[hovered]:bg-red-50',

// Icon
'[--btn-icon:theme(colors.red.500)] data-[hovered]:[--btn-icon:theme(colors.red.600)]',
],
},
{
color: 'danger',
variant: 'plain',
class: [
// Base
'data-[hovered]:bg-red-50 data-[pressed]:bg-red-100',

// Icon
'[--btn-icon:theme(colors.red.500)] data-[hovered]:[--btn-icon:theme(colors.red.600)]',
],
Expand Down
23 changes: 11 additions & 12 deletions ui/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Route as AuthLoginImport } from './routes/auth/login'
import { Route as AuthForgetPassImport } from './routes/auth/forget-pass'
import { Route as DashboardGroupsImport } from './routes/_dashboard/groups'
import { Route as DashboardFriendsImport } from './routes/_dashboard/friends'
import { Route as DashboardActivityIndexImport } from './routes/_dashboard/activity/index'
import { Route as DashboardActivityImport } from './routes/_dashboard/activity'
import { Route as DashboardProfileMeImport } from './routes/_dashboard/profile/me'
import { Route as DashboardGroupsGroupImport } from './routes/_dashboard/groups/$group'
import { Route as DashboardFriendsFriendImport } from './routes/_dashboard/friends/$friend'
Expand Down Expand Up @@ -55,8 +55,8 @@ const DashboardFriendsRoute = DashboardFriendsImport.update({
getParentRoute: () => DashboardRoute,
} as any)

const DashboardActivityIndexRoute = DashboardActivityIndexImport.update({
path: '/activity/',
const DashboardActivityRoute = DashboardActivityImport.update({
path: '/activity',
getParentRoute: () => DashboardRoute,
} as any)

Expand All @@ -76,8 +76,8 @@ const DashboardFriendsFriendRoute = DashboardFriendsFriendImport.update({
} as any)

const DashboardActivityActivityRoute = DashboardActivityActivityImport.update({
path: '/activity/$activity',
getParentRoute: () => DashboardRoute,
path: '/$activity',
getParentRoute: () => DashboardActivityRoute,
} as any)

// Populate the FileRoutesByPath interface
Expand All @@ -92,6 +92,10 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DashboardImport
parentRoute: typeof rootRoute
}
'/_dashboard/activity': {
preLoaderRoute: typeof DashboardActivityImport
parentRoute: typeof DashboardImport
}
'/_dashboard/friends': {
preLoaderRoute: typeof DashboardFriendsImport
parentRoute: typeof DashboardImport
Expand All @@ -110,7 +114,7 @@ declare module '@tanstack/react-router' {
}
'/_dashboard/activity/$activity': {
preLoaderRoute: typeof DashboardActivityActivityImport
parentRoute: typeof DashboardImport
parentRoute: typeof DashboardActivityImport
}
'/_dashboard/friends/$friend': {
preLoaderRoute: typeof DashboardFriendsFriendImport
Expand All @@ -124,10 +128,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DashboardProfileMeImport
parentRoute: typeof DashboardImport
}
'/_dashboard/activity/': {
preLoaderRoute: typeof DashboardActivityIndexImport
parentRoute: typeof DashboardImport
}
}
}

Expand All @@ -136,11 +136,10 @@ declare module '@tanstack/react-router' {
export const routeTree = rootRoute.addChildren([
IndexRoute,
DashboardRoute.addChildren([
DashboardActivityRoute.addChildren([DashboardActivityActivityRoute]),
DashboardFriendsRoute.addChildren([DashboardFriendsFriendRoute]),
DashboardGroupsRoute.addChildren([DashboardGroupsGroupRoute]),
DashboardActivityActivityRoute,
DashboardProfileMeRoute,
DashboardActivityIndexRoute,
]),
AuthForgetPassRoute,
AuthLoginRoute,
Expand Down
178 changes: 178 additions & 0 deletions ui/src/routes/_dashboard/activity.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import clsx from 'clsx';
import {DialogTrigger} from 'react-aria-components';

import {MagnifyingGlassIcon} from '@heroicons/react/24/outline';
import {Outlet, ScrollRestoration, createFileRoute, useMatchRoute} from '@tanstack/react-router';
import groupBy from 'just-group-by';

import {Button} from '@/components/common';
import ActivityListItem from '@/routes/_dashboard/activity/-components/ActivityListItem.tsx';

export const Route = createFileRoute('/_dashboard/activity')({
component: ActivityLayout,
});

function ActivityLayout() {
const matchRoute = useMatchRoute();
const isRootLayout = matchRoute({to: '/activity'});

// const {data} = useApiQuery(ApiRoutes.ACTIVITY_LIST);
const data = {
results: [
{
uid: 'activity-1',
urn: 'urn:activity:1',
user: {
uid: 'user-1',
urn: 'urn:user:1',
fullName: 'John Doe',
isActive: true,
},
group: {
uid: 'group-1',
urn: 'urn:group:1',
name: 'Apartment Buddies',
},
template: 'Dinner',
description: 'Dinner at Pizza Palace',
target: {
uid: 'target-1',
urn: 'urn:target:1',
value: '35.75',
},
createdAt: '2024-03-23T18:00:00Z',
},
{
uid: 'activity-2',
urn: 'urn:activity:2',
user: {
uid: 'user-2',
urn: 'urn:user:2',
fullName: 'Jane Smith',
isActive: true,
},
group: {
uid: 'group-2',
urn: 'urn:group:2',
name: 'Weekend Getaway',
members: ['user-1', 'user-2', 'user-3'],
},
template: 'Groceries',
description: 'Shared groceries for the trip',
target: {
uid: 'target-2',
urn: 'urn:target:2',
value: '82.40',
},
createdAt: '2024-03-22T15:30:00Z',
},
{
uid: 'activity-3',
urn: 'urn:activity:3',
user: {
uid: 'user-1',
urn: 'urn:user:1',
fullName: 'John Doe',
isActive: true,
},
group: {
uid: 'group-1',
urn: 'urn:group:1',
name: 'Apartment Buddies',
},
template: 'Utilities',
description: 'Electricity bill for March',
target: {
uid: 'target-3',
urn: 'urn:target:3',
value: '120.00',
},
createdAt: '2024-03-20T10:00:00Z',
},
],
};
const formatDate = (dateString: string) => {
const [month, year] = dateString.split('/');

const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
const monthName = months[parseInt(month, 10) - 1];

return `${monthName} ${year}`;
};

return (
<>
<div
className={clsx(
'bg-white',
!isRootLayout &&
'fixed inset-y-0 left-60 hidden w-96 overflow-auto border-e border-gray-200 xl:block',
isRootLayout &&
'xl:fixed xl:inset-y-0 xl:left-60 xl:w-96 xl:overflow-auto xl:border-e xl:border-gray-200'
)}
>
<div className="absolute inset-y-0 right-0 w-px bg-gray-100" />
<div className="sticky top-0 z-40 flex items-center gap-x-2 bg-white py-6 pl-6 pr-3">
<div className="flex-1">
<h2 className="text-lg font-medium text-gray-900">Activity</h2>
</div>
<div>
<DialogTrigger>
<Button
size="large"
className="whitespace-nowrap text-brand-600"
variant="plain"
>
<MagnifyingGlassIcon className="size-6" />
</Button>
</DialogTrigger>
</div>
</div>
<div className="-space-y-px">
{Object.entries(
groupBy(data?.results ?? [], (activity) => {
const dateObj = new Date(activity.createdAt ?? '');
return dateObj.toLocaleDateString('en-US', {year: 'numeric', month: 'numeric'});
})
)
.sort((a, b) => (a[0] < b[0] ? -1 : +1))
.map(([date, activities]) => (
<div
key={date}
className="relative -space-y-px"
>
<div className="sticky top-[96px] z-20 border-b border-t border-gray-200 bg-gray-50 px-6 py-1 text-sm font-medium text-gray-500">
<h3 className="uppercase">{formatDate(date)}</h3>
</div>
<div className="-space-y-px">
{activities.map((activity) => (
<ActivityListItem
key={activity.uid}
{...activity}
/>
))}
</div>
</div>
))}
</div>
<ScrollRestoration />
</div>
<div className="xl:ms-96">
<Outlet />
</div>
</>
);
}
Loading