Skip to content

Commit

Permalink
Update today view
Browse files Browse the repository at this point in the history
  • Loading branch information
arjunkomath committed Jan 16, 2025
1 parent 7168a14 commit 43e28f9
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 226 deletions.
116 changes: 51 additions & 65 deletions app/(dashboard)/[tenant]/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { blob } from "@/drizzle/schema";
import { bytesToMegabytes } from "@/lib/blobStore";
import type { UserCustomData } from "@/lib/ops/auth";
import { database } from "@/lib/utils/useDatabase";
import { getTimezone } from "@/lib/utils/useOwner";
import { getLogtoContext } from "@logto/next/server-actions";
import { sql } from "drizzle-orm";
import { HardDrive, User2 } from "lucide-react";
Expand All @@ -23,97 +24,82 @@ export default async function Settings() {

const db = await database();

const [storage] = await Promise.all([
const [storage, timezone] = await Promise.all([
db
.select({
count: sql<number>`count(*)`,
usage: sql<number>`sum(${blob.contentSize})`,
})
.from(blob)
.get(),
getTimezone(),
]);

return (
<>
<PageTitle title="Settings" />

<PageSection topInset bottomMargin className="p-4">
<h2 className="flex items-center text-xl font-semibold leading-7 text-gray-900 dark:text-gray-200">
<PageSection topInset bottomMargin>
<h2 className="flex items-center text-xl font-semibold leading-7 text-gray-900 dark:text-gray-200 p-4">
<HardDrive className="mr-2 inline-block h-6 w-6" />
Storage
</h2>

<dl className="mt-6 space-y-6 divide-y divide-gray-100 text-sm leading-6 dark:divide-gray-800">
<div className="pt-6 sm:flex">
<dt className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Usage
</dt>
<dd className="mt-1 flex justify-between gap-x-6 sm:mt-0 sm:flex-auto">
<div className="text-gray-900 dark:text-gray-200">
{bytesToMegabytes(storage?.usage ?? 0)} MB{" "}
<p className="inline font-bold">/ 5 GB</p> ({storage?.count}{" "}
files)
</div>
</dd>
</div>
</dl>
<div className="p-4 sm:flex">
<dt className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Usage
</dt>
<dd className="mt-1 flex justify-between gap-x-6 sm:mt-0 sm:flex-auto">
<div className="text-gray-900 dark:text-gray-200">
{bytesToMegabytes(storage?.usage ?? 0)} MB{" "}
<p className="inline font-bold">/ 5 GB</p> ({storage?.count}{" "}
files)
</div>
</dd>
</div>
</PageSection>

{userInfo ? (
<PageSection className="p-4">
<h2 className="flex items-center text-xl font-semibold leading-7 text-gray-900 dark:text-gray-200">
<PageSection>
<h2 className="flex items-center text-xl font-semibold leading-7 text-gray-900 dark:text-gray-200 p-4">
<User2 className="mr-2 inline-block h-6 w-6" />
Profile ({userInfo.username})
</h2>

<dl className="mt-6 space-y-6 divide-y divide-gray-100 text-sm leading-6 dark:divide-gray-800">
<div className="pt-6 sm:flex">
<dt className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Name
</dt>
<dd className="mt-1 flex justify-between gap-x-6 sm:mt-0 sm:flex-auto">
<div className="text-gray-900 dark:text-gray-200">
<EditableValue
id={claims.sub}
name="name"
type="text"
value={userInfo.name ?? "-"}
action={updateUserData}
/>
</div>
</dd>
</div>
<div className="p-4 flex items-center">
<p className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Name
</p>
<EditableValue
id={claims.sub}
name="name"
type="text"
value={userInfo.name ?? "-"}
action={updateUserData}
/>
</div>

<div className="pt-6 sm:flex">
<dt className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Email address
</dt>
<dd className="mt-1 flex justify-between gap-x-6 sm:mt-0 sm:flex-auto">
<div className="text-gray-900 dark:text-gray-200">
<EditableValue
id={claims.sub}
name="primaryEmail"
type="text"
value={userInfo.email ?? "-"}
action={updateUserData}
/>
</div>
</dd>
</div>
<div className="p-4 flex items-center">
<dt className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Email address
</dt>
<EditableValue
id={claims.sub}
name="primaryEmail"
type="text"
value={userInfo.email ?? "-"}
action={updateUserData}
/>
</div>

{(userInfo.customData as UserCustomData)?.timezone ? (
<div className="pt-6 sm:flex">
<dt className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Timezone
</dt>
<dd className="mt-1 flex justify-between gap-x-6 sm:mt-0 sm:flex-auto">
<div className="text-gray-900 dark:text-gray-200">
{(userInfo.customData as UserCustomData)?.timezone}
</div>
</dd>
</div>
) : null}
</dl>
{timezone ? (
<div className="p-4 sm:flex">
<p className="font-semibold text-gray-900 dark:text-gray-200 sm:w-64 sm:flex-none sm:pr-6">
Timezone
</p>
<div className="text-gray-900 dark:text-gray-200">{timezone}</div>
</div>
) : null}
</PageSection>
) : null}
</>
Expand Down
141 changes: 93 additions & 48 deletions app/(dashboard)/[tenant]/today/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Greeting } from "@/components/core/greeting";
import PageSection from "@/components/core/section";
import PageTitle from "@/components/layout/page-title";
import { TaskItem } from "@/components/project/tasklist/task/task-item";
import { task } from "@/drizzle/schema";
import { calendarEvent, task } from "@/drizzle/schema";
import {
guessTimezone,
isSameDate,
toDateStringWithDay,
toDateTimeString,
Expand All @@ -13,59 +11,107 @@ import {
} from "@/lib/utils/date";
import { database } from "@/lib/utils/useDatabase";
import { getTimezone } from "@/lib/utils/useOwner";
import { and, asc, lte, ne } from "drizzle-orm";
import { AlertTriangleIcon, InfoIcon } from "lucide-react";
import { and, asc, lte } from "drizzle-orm";
import { AlertTriangleIcon, CalendarClockIcon, InfoIcon } from "lucide-react";
import { rrulestr } from "rrule";

export default async function Today() {
const db = await database();

const timezone = await getTimezone();
const today = toEndOfDay(toTimeZone(new Date(), timezone));
const today = toTimeZone(Date(), timezone);

const tasks = await db.query.task.findMany({
where: and(lte(task.dueDate, new Date(today)), ne(task.status, "done")),
orderBy: [asc(task.position)],
with: {
taskList: {
columns: {
projectId: true,
},
},
creator: {
columns: {
firstName: true,
imageUrl: true,
},
const [tasks, events] = await Promise.all([
db.query.task.findMany({
where: (task, { and, isNotNull, lte, ne }) =>
and(
lte(task.dueDate, toEndOfDay(today)),
ne(task.status, "done"),
isNotNull(task.dueDate),
),
orderBy: [asc(task.position)],
columns: {
name: true,
dueDate: true,
id: true,
},
assignee: {
columns: {
firstName: true,
imageUrl: true,
with: {
taskList: {
columns: {
status: true,
name: true,
},
with: {
project: {
columns: {
name: true,
},
},
},
},
},
},
});
}),
db.query.calendarEvent.findMany({
where: and(lte(calendarEvent.start, today)),
orderBy: [asc(calendarEvent.start)],
}),
]);

const dueToday = tasks
.filter((t) => !!t.dueDate)
.filter((t) => t.taskList.status !== "archived")
.filter((t) => isSameDate(t.dueDate!, new Date()));

const overDue = tasks
.filter((t) => !!t.dueDate)
.filter((t) => t.taskList.status !== "archived")
.filter((t) => t.dueDate! < new Date());

const summary = `You've got ${dueToday.length > 0 ? dueToday.length : "no"} tasks due today & ${overDue.length > 0 ? overDue.length : "no"} overdue tasks.`;
const summary = ` You've got ${dueToday.length > 0 ? dueToday.length : "no"} tasks due today, ${overDue.length > 0 ? overDue.length : "no"} overdue tasks and ${events.length > 0 ? events.length : "no"} events today.`;

return (
<>
<PageTitle title={toDateStringWithDay(today, timezone)} />

<PageSection topInset>
<p className="p-4 text-xl">
<Greeting />, {summary}
<Greeting /> {summary}
</p>
</PageSection>

{events.length ? (
<PageSection>
<p className="flex items-center p-4 text-xl font-medium text-primary">
<CalendarClockIcon className="w-6 h-6 inline-block mr-1" />
Events
</p>
{events.map((event) => (
<div key={event.id} className="px-4 py-2">
<div className="flex flex-col md:flex-row md:items-center md:space-x-4">
<p>{event.name}</p>
<div
className="text-xs text-gray-500 dark:text-gray-400"
suppressHydrationWarning
>
{event.allDay
? toDateStringWithDay(event.start, timezone)
: toDateTimeString(event.start, timezone)}
{event.end
? ` - ${
event.allDay
? toDateStringWithDay(event.end, timezone)
: toDateTimeString(event.end, timezone)
}`
: null}
{event.repeatRule
? `, ${rrulestr(event.repeatRule).toText()}`
: null}
</div>
</div>
<p className="text-sm">{event.description}</p>
</div>
))}
</PageSection>
) : null}

{overDue.length || dueToday.length ? (
<PageSection>
{overDue.length ? (
Expand All @@ -74,15 +120,8 @@ export default async function Today() {
<AlertTriangleIcon className="w-6 h-6 inline-block mr-1" />
Overdue
</p>
{overDue.map((task) => (
<TaskItem
key={task.id}
task={task}
projectId={+task.taskList.projectId}
timezone={timezone}
compact
/>
))}

{overDue.map((task) => TaskItem(task))}
</>
) : null}

Expand All @@ -92,19 +131,25 @@ export default async function Today() {
<InfoIcon className="w-6 h-6 inline-block mr-1" />
Due Today
</p>
{dueToday.map((task) => (
<TaskItem
key={task.id}
task={task}
projectId={+task.taskList.projectId}
timezone={timezone}
compact
/>
))}
{dueToday.map((task) => TaskItem(task))}
</>
) : null}
</PageSection>
) : null}
</>
);
}
function TaskItem(task: {
name: string;
id: number;
taskList: { name: string; status: string; project: { name: string } };
}) {
return (
<div key={task.id} className="px-4 py-2">
<p className="text-sm text-gray-500 dark:text-gray-400">
{task.taskList.project.name} - {task.taskList.name}
</p>
<p>{task.name}</p>
</div>
);
}
2 changes: 1 addition & 1 deletion components/console/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default function NavBar({
strokeWidth="1"
viewBox="0 0 24 24"
width="40"
className="ml-0.5 text-gray-300 dark:text-gray-700 xl:block"
className="text-gray-300 dark:text-gray-700 xl:block"
>
<path d="M16.88 3.549L7.12 20.451" />
</svg>
Expand Down
2 changes: 1 addition & 1 deletion components/core/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export const ProjectSwitcher = ({
strokeWidth="1"
viewBox="0 0 24 24"
width="40"
className="ml-0.5 text-gray-300 dark:text-gray-700 xl:block"
className="text-gray-300 dark:text-gray-700 xl:block"
>
<path d="M16.88 3.549L7.12 20.451" />
</svg>
Expand Down
6 changes: 3 additions & 3 deletions components/core/greeting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export function Greeting() {
const getCurrentGreeting = () => {
const currentHour = new Date().getHours();
if (currentHour >= 5 && currentHour < 12) {
return "Good morning";
return "Good morning 👋";
}
if (currentHour >= 12 && currentHour < 18) {
return "Good afternoon";
return "Good afternoon 👋";
}
return "Good evening";
return "Good evening 👋";
};

setGreeting(getCurrentGreeting());
Expand Down
Loading

0 comments on commit 43e28f9

Please sign in to comment.