Frontend updates to Day and Month views
This commit is contained in:
parent
4a434b59e4
commit
020b75b72e
@ -4,7 +4,7 @@ import Sidebar from "@/components/dashboard/sidebar/Sidebar";
|
||||
import DemoModeBanner from "@/components/DemoModeBanner";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import ValidAccountCheck from "@/components/utils/ValidAccountCheck";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import serverConfig from "@lifetracker/shared/config";
|
||||
|
||||
export default async function Dashboard({
|
||||
@ -29,7 +29,7 @@ export default async function Dashboard({
|
||||
<Separator />
|
||||
</div>
|
||||
{modal}
|
||||
<div className="min-h-30 container p-4">{children}</div>
|
||||
<div className={cn("min-h-30 p-4 container")}>{children}</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -6,6 +6,7 @@ import { EditableHourCode } from "@/components/dashboard/hours/EditableHourCode"
|
||||
import { useUpdateHour } from "@lifetracker/shared-react/hooks/days";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { getHourFromTime } from "@lifetracker/shared/utils/hours";
|
||||
import MonthView from "@/components/dashboard/timelines/MonthView";
|
||||
|
||||
async function fetchDays(view: string, dateQuery: string) {
|
||||
const timezone = await api.users.getTimezone();
|
||||
@ -16,7 +17,7 @@ async function fetchDays(view: string, dateQuery: string) {
|
||||
const days = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const dayDate = firstDay.add(i, "day").format("iso-short");
|
||||
console.log(dayDate);
|
||||
// console.log(dayDate);
|
||||
const dayRes = await api.days.get({
|
||||
dateQuery: dayDate,
|
||||
timezone: timezone,
|
||||
@ -33,44 +34,7 @@ export default async function TimelinePage({ params }: { params: { view: string,
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid" style={{ "gridTemplateColumns": "repeat(25, 1fr)" }}>
|
||||
<div className="flex items-center">Date</div>
|
||||
{Array.from({ length: 24 }, (_, i) => (
|
||||
<div key={i} className="flex text-center items-center justify-center font-mono">
|
||||
{getHourFromTime(i, "twelves")}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{days.map((day, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="grid"
|
||||
style={{ "gridTemplateColumns": "repeat(25, 1fr)" }}
|
||||
>
|
||||
<div className="text-right font-mono">
|
||||
{spacetime(day.date).format("{iso-month}/{date-pad}")}
|
||||
</div>
|
||||
{day.hours.map((hour, i) => (
|
||||
<EditableHourCode
|
||||
key={i}
|
||||
originalText={hour.categoryCode}
|
||||
hour={hour}
|
||||
i={i}
|
||||
/>
|
||||
// <div key={i}
|
||||
// datetime={day.date + "T" + hour.time + ":00:00"}
|
||||
// className="flex items-center justify-center font-mono"
|
||||
// style={{
|
||||
// backgroundColor: hour.background ?? "white",
|
||||
// color: hour.foreground ?? "black",
|
||||
// }}
|
||||
// >
|
||||
// {hour.categoryCode ?? "_"}
|
||||
// </div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
))}
|
||||
<MonthView days={days} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -26,7 +26,7 @@ export default async function DayView({
|
||||
return (
|
||||
<div className="flex flex-col gap-3">
|
||||
|
||||
<div className="flex justify-between pr-4">
|
||||
<div className="flex justify-between pr-4 flex-col gap-4 md:flex-row">
|
||||
<div className="flex">
|
||||
<Link
|
||||
href={`/dashboard/day/${prevDay}`}
|
||||
@ -38,9 +38,12 @@ export default async function DayView({
|
||||
<ArrowLeftSquare size={18} />
|
||||
</div>
|
||||
</Link>
|
||||
<span className="text-2xl flex-1">
|
||||
<span className="text-2xl flex-1 hidden lg:block">
|
||||
{spacetime(day.date).format("{day}, {month} {date}, {year}")}
|
||||
</span>
|
||||
<span className="text-2xl flex-1 lg:hidden block text-center">
|
||||
{spacetime(day.date).format("{day-short}, {month-short} {date}, {year}")}
|
||||
</span>
|
||||
<Link
|
||||
href={`/dashboard/day/${nextDay}`}
|
||||
className={cn(
|
||||
@ -52,7 +55,7 @@ export default async function DayView({
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="flex justify-center">
|
||||
<MoodStars
|
||||
day={day}
|
||||
/>
|
||||
|
||||
@ -10,7 +10,7 @@ import { EditableText } from "@/components/dashboard/EditableText";
|
||||
import { format } from "date-fns";
|
||||
import { TZDate } from "@date-fns/tz";
|
||||
import { ZHour } from "@lifetracker/shared/types/days";
|
||||
import { MessageCircle } from "lucide-react";
|
||||
import { MessageCircle, Pencil } from "lucide-react";
|
||||
import { ButtonWithTooltip } from "@/components/ui/button";
|
||||
import { EditableHourCode } from "./EditableHourCode";
|
||||
import { EditableHourComment } from "./EditableHourComment";
|
||||
@ -27,22 +27,23 @@ export default function EditableHour({
|
||||
i: number,
|
||||
className?: string;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const currentPath = usePathname();
|
||||
const [hour, setHour] = useState(initialHour);
|
||||
const { mutate: updateHour, isPending } = useUpdateHour({
|
||||
onSuccess: (res, req, meta) => {
|
||||
const { categoryCode: oldCode, comment: oldComment } = hour;
|
||||
const newHour = {
|
||||
categoryCode: req.code,
|
||||
categoryCode: parseInt(req.code!),
|
||||
comment: oldComment,
|
||||
...res,
|
||||
};
|
||||
console.log(res);
|
||||
setHour(newHour);
|
||||
// Only show toast if client screen is larger than mobile
|
||||
if (window.innerWidth > 640) {
|
||||
toast({
|
||||
description: "Hour updated!",
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
const tzOffset = spacetime().offset() / 60;
|
||||
@ -64,28 +65,29 @@ export default function EditableHour({
|
||||
}
|
||||
return (
|
||||
<div
|
||||
hourid={hour.id}
|
||||
data-hourid={hour.id}
|
||||
className={cn(
|
||||
"p-4 grid justify-between",
|
||||
)}
|
||||
style={{
|
||||
background: hour.background, color: hour.foreground, fontFamily: "inherit",
|
||||
gridTemplateColumns: "100px 100px 1fr 200px"
|
||||
background: hour.background!, color: hour.foreground!, fontFamily: "inherit",
|
||||
gridTemplateColumns: window.innerWidth > 640 ? "50px 100px 1fr 50px" : "50px 100px 1fr", // Known issue: This won't work if the screen is resized, only on reload
|
||||
}}
|
||||
>
|
||||
<span className="text-right">
|
||||
{isActiveHour(hour) && "--> "}
|
||||
{/* {isActiveHour(hour) && "--> "} */}
|
||||
{hour.datetime}
|
||||
</span>
|
||||
<div className="flex justify-center">
|
||||
<EditableHourCode
|
||||
className={"w-8 border-b"}
|
||||
originalText={hour.categoryCode}
|
||||
hour={hour}
|
||||
onSubmit={updateHour}
|
||||
i={i}
|
||||
/>
|
||||
</div>
|
||||
<span>
|
||||
<span className="hidden sm:block">
|
||||
<EditableHourComment
|
||||
originalText={hour.categoryDesc}
|
||||
hour={hour}
|
||||
@ -93,18 +95,26 @@ export default function EditableHour({
|
||||
i={i}
|
||||
/>
|
||||
</span>
|
||||
<div className="text-right">
|
||||
<span className="block sm:hidden">
|
||||
<div className="w-full text-left edit-hour-comment"
|
||||
style={{
|
||||
background: hour.background ?? "inherit", color: hour.foreground ?? "inherit", fontFamily: "inherit",
|
||||
}}>
|
||||
{hour.categoryName}
|
||||
</div>
|
||||
</span>
|
||||
<div className="text-right hidden sm:block">
|
||||
<ButtonWithTooltip
|
||||
delayDuration={500}
|
||||
tooltip="Add Comment"
|
||||
tooltip="Edit"
|
||||
size="none"
|
||||
variant="ghost"
|
||||
className="align-middle text-gray-400"
|
||||
className="align-middle text-gray-400 hover:bg-active"
|
||||
onClick={() => {
|
||||
console.log("Pushed edit")
|
||||
}}
|
||||
>
|
||||
<MessageCircle className="size-4" />
|
||||
<Pencil className="size-4" />
|
||||
</ButtonWithTooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { or } from "drizzle-orm";
|
||||
import { useEffect, useRef } from "react";
|
||||
import {
|
||||
cn
|
||||
|
||||
} from "@/lib/utils";
|
||||
function selectHourCode(time: number) {
|
||||
document.getElementById("hour-" + (time).toString())?.getElementsByClassName("edit-hour-code")[0].focus();
|
||||
}
|
||||
@ -11,6 +13,7 @@ function selectHourComment(time: number) {
|
||||
}
|
||||
|
||||
export function EditableHourCode({
|
||||
className = "",
|
||||
originalText,
|
||||
hour,
|
||||
onSubmit,
|
||||
@ -50,6 +53,7 @@ export function EditableHourCode({
|
||||
dayId: hour.dayId,
|
||||
code: newCode ?? "",
|
||||
comment: hour.comment,
|
||||
i: i
|
||||
})
|
||||
selectHourCode(i + 1);
|
||||
};
|
||||
@ -62,7 +66,7 @@ export function EditableHourCode({
|
||||
</div>
|
||||
|
||||
<input
|
||||
className="w-8 border-b text-center edit-hour-code"
|
||||
className={cn("text-center edit-hour-code", className)}
|
||||
style={{
|
||||
background: hour.background ?? "inherit", color: hour.foreground ?? "inherit", fontFamily: "inherit",
|
||||
borderColor: hour.foreground ?? "inherit"
|
||||
|
||||
@ -54,9 +54,10 @@ export function EditableHourComment({
|
||||
};
|
||||
return (
|
||||
<input
|
||||
className="w-full text-left edit-hour-comment"
|
||||
className="w-full text-left edit-hour-comment hover:border-b hover:border-dashed"
|
||||
style={{
|
||||
background: hour.background ?? "inherit", color: hour.foreground ?? "inherit", fontFamily: "inherit",
|
||||
borderColor: hour.foreground ?? "inherit"
|
||||
}}
|
||||
ref={ref}
|
||||
value={originalText ?? ""}
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import MobileSidebarItem from "@/components/shared/sidebar/ModileSidebarItem";
|
||||
import HoarderLogoIcon from "@/public/icons/logo-icon.svg";
|
||||
import { ClipboardList, Search, Tag } from "lucide-react";
|
||||
import { CheckCheck, ClipboardList, GaugeCircleIcon, Home, HomeIcon, Search, Tag } from "lucide-react";
|
||||
|
||||
export default async function MobileSidebar() {
|
||||
return (
|
||||
<aside className="w-full">
|
||||
<ul className="flex justify-between space-x-2 border-b-black px-5 py-2 pt-5">
|
||||
<MobileSidebarItem
|
||||
logo={<HoarderLogoIcon className="w-5 fill-foreground" />}
|
||||
path="/dashboard/bookmarks"
|
||||
logo={<Home />}
|
||||
path="/dashboard/day/today"
|
||||
/>
|
||||
<MobileSidebarItem logo={<Search />} path="/dashboard/search" />
|
||||
<MobileSidebarItem logo={<ClipboardList />} path="/dashboard/lists" />
|
||||
<MobileSidebarItem logo={<Tag />} path="/dashboard/tags" />
|
||||
<MobileSidebarItem logo={<Tag />} path="/dashboard/categories" />
|
||||
<MobileSidebarItem logo={<CheckCheck />} path="/dashboard/habits" />
|
||||
<MobileSidebarItem logo={<GaugeCircleIcon />} path="/analytics" />
|
||||
</ul>
|
||||
</aside>
|
||||
);
|
||||
|
||||
@ -3,7 +3,7 @@ import SidebarItem from "@/components/shared/sidebar/SidebarItem";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { api } from "@/server/api/client";
|
||||
import { getServerAuthSession } from "@/server/auth";
|
||||
import { Archive, Calendar, Home, Search, Tag } from "lucide-react";
|
||||
import { Archive, Calendar, CheckCheck, Home, Search, Tag } from "lucide-react";
|
||||
import serverConfig from "@lifetracker/shared/config";
|
||||
|
||||
import AllLists from "./AllLists";
|
||||
@ -43,6 +43,11 @@ export default async function Sidebar() {
|
||||
path: "/dashboard/timeline/month",
|
||||
},
|
||||
...searchItem,
|
||||
{
|
||||
name: "Habits",
|
||||
icon: <CheckCheck size={18} />,
|
||||
path: "/dashboard/habits",
|
||||
},
|
||||
{
|
||||
name: "Categories",
|
||||
icon: <Tag size={18} />,
|
||||
|
||||
@ -1,57 +1,96 @@
|
||||
'use client';
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { getServerAuthSession } from "@/server/auth";
|
||||
import { ZDay } from "@lifetracker/shared/types/days";
|
||||
import EditableDayComment from "./EditableDayComment";
|
||||
import { MoodStars } from "./MoodStars";
|
||||
import { EditableHourCode } from "../hours/EditableHourCode";
|
||||
import { getHourFromTime } from "@lifetracker/shared/utils/hours";
|
||||
import Link from "next/link";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowLeftSquare, ArrowRightSquare } from "lucide-react";
|
||||
import spacetime from "spacetime";
|
||||
import EditableHour from "@/components/dashboard/hours/EditableHour";
|
||||
import { useUpdateHour } from "@lifetracker/shared-react/hooks/days";
|
||||
import { useState } from "react";
|
||||
|
||||
export default async function MonthView({
|
||||
dateRange,
|
||||
export default function MonthView({
|
||||
days: initialDays,
|
||||
}: {
|
||||
dateRange: string[];
|
||||
days: ZDay[];
|
||||
}) {
|
||||
const session = await getServerAuthSession();
|
||||
if (!session) {
|
||||
redirect("/");
|
||||
|
||||
// Hacky, but it works
|
||||
// Remove "container" class from parent div
|
||||
const parent = document.querySelector(".container");
|
||||
if (parent) {
|
||||
parent.classList.remove("container");
|
||||
}
|
||||
|
||||
const [days, setDays] = useState(initialDays);
|
||||
const { mutate: updateHour, isPending } = useUpdateHour({
|
||||
onSuccess: (res, req, meta) => {
|
||||
const hourDay = days.find(day => day.date === req.date);
|
||||
// Replace the relevant hour within hourDay
|
||||
hourDay.hours[req.i] = res;
|
||||
// Place the new hourDay within the days array
|
||||
setDays([...days]);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex justify-between pr-4">
|
||||
<div className="flex">
|
||||
<Link
|
||||
href={`/dashboard/timeline/month/last`}
|
||||
className={cn(
|
||||
"flex-0 items-center rounded-[inherit] px-3 py-2",
|
||||
)}
|
||||
<>
|
||||
<div className="grid font-mono border-b-2" style={{ gridTemplateColumns: "repeat(26, 1fr)", borderColor: "white" }}>
|
||||
<div className="flex text-center justify-center">DATE</div>
|
||||
<div className="flex text-center justify-center border-r-2 border-inherit">DAY</div>
|
||||
{Array.from({ length: 24 }, (_, i) => (
|
||||
<div key={i} className={cn("flex text-center items-center justify-center",
|
||||
i == spacetime().hour() ? "bg-white text-black" : ""
|
||||
)}>
|
||||
{getHourFromTime(i, "all")}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{
|
||||
days.map((day, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="grid font-mono"
|
||||
style={{ gridTemplateColumns: "repeat(26, 1fr)", borderColor: "white" }}
|
||||
>
|
||||
<div className="flex w-full justify-between">
|
||||
<ArrowLeftSquare size={18} />
|
||||
<div className={cn("text-center",
|
||||
spacetime(day.date).diff(spacetime.now()).hours < 24 && spacetime(day.date).diff(spacetime.now()).hours > 0 ? "bg-white text-black" : ""
|
||||
)}>
|
||||
{spacetime(day.date).format("{iso-month}/{date-pad}")}
|
||||
</div>
|
||||
</Link>
|
||||
<span className="text-2xl flex-1">
|
||||
{spacetime().format("{day}, {month} {date}, {year}")}
|
||||
</span>
|
||||
<Link
|
||||
href={`/dashboard/timeline/month/next`}
|
||||
className={cn(
|
||||
"flex-0 items-center rounded-[inherit] px-3 py-2",
|
||||
)}
|
||||
>
|
||||
<div className="flex w-full justify-between">
|
||||
<ArrowRightSquare size={18} />
|
||||
</div>
|
||||
</Link>
|
||||
<div className={cn("text-center",
|
||||
spacetime(day.date).diff(spacetime.now()).hours < 24 && spacetime(day.date).diff(spacetime.now()).hours > 0 ? "bg-white text-black" : ""
|
||||
)}>
|
||||
{spacetime(day.date).format("{day-short}")}
|
||||
</div>
|
||||
{day.hours.map((hour, i) => (
|
||||
<EditableHourCode
|
||||
className="w-full h-full hover:cursor-default"
|
||||
key={i}
|
||||
originalText={hour.categoryCode}
|
||||
hour={hour}
|
||||
i={i}
|
||||
onSubmit={updateHour}
|
||||
/>
|
||||
// <div key={i}
|
||||
// datetime={day.date + "T" + hour.time + ":00:00"}
|
||||
// className="flex items-center justify-center font-mono"
|
||||
// style={{
|
||||
// backgroundColor: hour.background ?? "white",
|
||||
// color: hour.foreground ?? "black",
|
||||
// }}
|
||||
// >
|
||||
// {hour.categoryCode ?? "_"}
|
||||
// </div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ export function dateFromInput(input: { dateQuery: string, timezone: string }) {
|
||||
throw new Error("Invalid dateQuery");
|
||||
}
|
||||
}
|
||||
console.log(`dateFromInput(${input.dateQuery}, ${input.timezone}) = ${t}`);
|
||||
// console.log(`dateFromInput(${input.dateQuery}, ${input.timezone}) = ${t}`);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user