format and fix
This commit is contained in:
@@ -31,12 +31,14 @@ type FlutterViewProps = {
|
||||
state: Record<string, unknown>;
|
||||
onEvent: (event: { type: string; payload?: Record<string, unknown> }) => void;
|
||||
className?: string;
|
||||
height?: number;
|
||||
};
|
||||
|
||||
export function FlutterView({
|
||||
state,
|
||||
onEvent,
|
||||
className,
|
||||
height,
|
||||
}: FlutterViewProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [status, setStatus] = useState<"loading" | "ready" | "error">(
|
||||
@@ -142,7 +144,7 @@ export function FlutterView({
|
||||
}, [state]);
|
||||
|
||||
return (
|
||||
<div className={className} style={{ height: "100%", position: "relative" }}>
|
||||
<div className={className} style={{ position: "relative" }}>
|
||||
{status === "loading" && (
|
||||
<div
|
||||
style={{
|
||||
@@ -170,7 +172,10 @@ export function FlutterView({
|
||||
Failed to load Flutter view
|
||||
</div>
|
||||
)}
|
||||
<div ref={containerRef} style={{ width: "100%", height: "100%" }} />
|
||||
<div
|
||||
ref={containerRef}
|
||||
style={{ width: "100%", height: height ?? 400 }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,21 +3,25 @@ import { useForm } from "@tanstack/react-form";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { createTimelineGroup } from "@/functions/create-timeline-group";
|
||||
import { Button } from "./ui/button";
|
||||
import { FieldControl, FieldError, FieldLabel, FieldRoot } from "./ui/field";
|
||||
import {
|
||||
DrawerRoot,
|
||||
DrawerTrigger,
|
||||
DrawerPortal,
|
||||
DrawerViewport,
|
||||
DrawerPopup,
|
||||
DrawerTitle,
|
||||
DrawerContent,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerPopup,
|
||||
DrawerPortal,
|
||||
DrawerRoot,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
DrawerViewport,
|
||||
} from "./ui/drawer";
|
||||
import { createTimelineGroup } from "@/functions/create-timeline-group";
|
||||
|
||||
export default function GroupFormDrawer({ timelineId }: { timelineId: string }) {
|
||||
export default function GroupFormDrawer({
|
||||
timelineId,
|
||||
}: {
|
||||
timelineId: string;
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -30,12 +34,16 @@ export default function GroupFormDrawer({ timelineId }: { timelineId: string })
|
||||
await createTimelineGroup({
|
||||
data: { title: value.title, timelineId },
|
||||
});
|
||||
await queryClient.invalidateQueries({ queryKey: ["timeline", timelineId] });
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["timeline", timelineId],
|
||||
});
|
||||
setOpen(false);
|
||||
form.reset();
|
||||
toast.success("Group created");
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : "Failed to create group");
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Failed to create group"
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -73,10 +81,14 @@ export default function GroupFormDrawer({ timelineId }: { timelineId: string })
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) =>
|
||||
field.handleChange((e.target as HTMLInputElement).value)
|
||||
field.handleChange(
|
||||
(e.target as HTMLInputElement).value
|
||||
)
|
||||
}
|
||||
/>
|
||||
<FieldError match="valueMissing">Title is required</FieldError>
|
||||
<FieldError match="valueMissing">
|
||||
Title is required
|
||||
</FieldError>
|
||||
</FieldRoot>
|
||||
)}
|
||||
</form.Field>
|
||||
|
||||
@@ -3,19 +3,19 @@ import { useForm } from "@tanstack/react-form";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { createTimelineItem } from "@/functions/create-timeline-item";
|
||||
import { Button } from "./ui/button";
|
||||
import { FieldControl, FieldError, FieldLabel, FieldRoot } from "./ui/field";
|
||||
import {
|
||||
DrawerRoot,
|
||||
DrawerTrigger,
|
||||
DrawerPortal,
|
||||
DrawerViewport,
|
||||
DrawerPopup,
|
||||
DrawerTitle,
|
||||
DrawerContent,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerPopup,
|
||||
DrawerPortal,
|
||||
DrawerRoot,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
DrawerViewport,
|
||||
} from "./ui/drawer";
|
||||
import { createTimelineItem } from "@/functions/create-timeline-item";
|
||||
|
||||
export default function ItemFormDrawer({
|
||||
timelineGroupId,
|
||||
@@ -45,12 +45,16 @@ export default function ItemFormDrawer({
|
||||
timelineGroupId,
|
||||
},
|
||||
});
|
||||
await queryClient.invalidateQueries({ queryKey: ["timeline", timelineId] });
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["timeline", timelineId],
|
||||
});
|
||||
setOpen(false);
|
||||
form.reset();
|
||||
toast.success("Item created");
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : "Failed to create item");
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Failed to create item"
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -88,10 +92,14 @@ export default function ItemFormDrawer({
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) =>
|
||||
field.handleChange((e.target as HTMLInputElement).value)
|
||||
field.handleChange(
|
||||
(e.target as HTMLInputElement).value
|
||||
)
|
||||
}
|
||||
/>
|
||||
<FieldError match="valueMissing">Title is required</FieldError>
|
||||
<FieldError match="valueMissing">
|
||||
Title is required
|
||||
</FieldError>
|
||||
</FieldRoot>
|
||||
)}
|
||||
</form.Field>
|
||||
@@ -105,7 +113,9 @@ export default function ItemFormDrawer({
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) =>
|
||||
field.handleChange((e.target as HTMLInputElement).value)
|
||||
field.handleChange(
|
||||
(e.target as HTMLInputElement).value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</FieldRoot>
|
||||
@@ -122,10 +132,14 @@ export default function ItemFormDrawer({
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) =>
|
||||
field.handleChange((e.target as HTMLInputElement).value)
|
||||
field.handleChange(
|
||||
(e.target as HTMLInputElement).value
|
||||
)
|
||||
}
|
||||
/>
|
||||
<FieldError match="valueMissing">Start date is required</FieldError>
|
||||
<FieldError match="valueMissing">
|
||||
Start date is required
|
||||
</FieldError>
|
||||
</FieldRoot>
|
||||
)}
|
||||
</form.Field>
|
||||
@@ -139,7 +153,9 @@ export default function ItemFormDrawer({
|
||||
value={field.state.value}
|
||||
onBlur={field.handleBlur}
|
||||
onChange={(e) =>
|
||||
field.handleChange((e.target as HTMLInputElement).value)
|
||||
field.handleChange(
|
||||
(e.target as HTMLInputElement).value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</FieldRoot>
|
||||
|
||||
@@ -11,5 +11,5 @@ export const Route = createFileRoute("/.well-known/oauth-authorization-server")(
|
||||
GET: ({ request }) => handler(request),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ export const Route = createFileRoute("/.well-known/oauth-protected-resource")({
|
||||
"Cache-Control":
|
||||
"public, max-age=15, stale-while-revalidate=15, stale-if-error=86400",
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -47,7 +47,7 @@ function RootDocument() {
|
||||
<HeadContent />
|
||||
</head>
|
||||
<body>
|
||||
<div className="grid h-svh grid-rows-[auto_1fr]">
|
||||
<div className="grid min-h-svh grid-rows-[auto_1fr]">
|
||||
<Header />
|
||||
<Outlet />
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Button } from "@/components/ui/button";
|
||||
|
||||
export const Route = createFileRoute("/consent")({
|
||||
validateSearch: (search: Record<string, unknown>) => ({
|
||||
client_id: (search.client_id as string) ?? "",
|
||||
scope: (search.scope as string) ?? "",
|
||||
client_id: (search.client_id as string | undefined) ?? "",
|
||||
scope: (search.scope as string | undefined) ?? "",
|
||||
}),
|
||||
component: ConsentComponent,
|
||||
});
|
||||
|
||||
@@ -5,7 +5,12 @@ import { toast } from "sonner";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { createTimeline } from "@/functions/create-timeline";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { FieldControl, FieldError, FieldLabel, FieldRoot } from "@/components/ui/field";
|
||||
import {
|
||||
FieldControl,
|
||||
FieldError,
|
||||
FieldLabel,
|
||||
FieldRoot,
|
||||
} from "@/components/ui/field";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: HomeComponent,
|
||||
@@ -22,9 +27,14 @@ function HomeComponent() {
|
||||
try {
|
||||
await authClient.signIn.anonymous();
|
||||
const timeline = await createTimeline({ data: { title: value.title } });
|
||||
navigate({ to: "/timeline/$timelineId", params: { timelineId: timeline.id } });
|
||||
navigate({
|
||||
to: "/timeline/$timelineId",
|
||||
params: { timelineId: timeline.id },
|
||||
});
|
||||
} catch (error) {
|
||||
toast.error(error instanceof Error ? error.message : "Failed to create timeline");
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Failed to create timeline"
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -66,9 +76,7 @@ function HomeComponent() {
|
||||
field.handleChange((e.target as HTMLInputElement).value)
|
||||
}
|
||||
/>
|
||||
<FieldError match="valueMissing">
|
||||
Name is required
|
||||
</FieldError>
|
||||
<FieldError match="valueMissing">Name is required</FieldError>
|
||||
</FieldRoot>
|
||||
)}
|
||||
</form.Field>
|
||||
|
||||
@@ -2,8 +2,6 @@ import { useCallback, useMemo, useState } from "react";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { timelineQueryOptions } from "@/functions/get-timeline";
|
||||
import GroupFormDrawer from "@/components/group-form-drawer";
|
||||
import ItemFormDrawer from "@/components/item-form-drawer";
|
||||
import { FlutterView } from "@/components/flutter-view";
|
||||
|
||||
export const Route = createFileRoute("/timeline/$timelineId")({
|
||||
@@ -44,11 +42,16 @@ function RouteComponent() {
|
||||
[timeline, selectedItemId]
|
||||
);
|
||||
|
||||
const [flutterHeight, setFlutterHeight] = useState<number | undefined>();
|
||||
|
||||
const handleEvent = useCallback(
|
||||
(event: { type: string; payload?: Record<string, unknown> }) => {
|
||||
switch (event.type) {
|
||||
case "content_height":
|
||||
setFlutterHeight(event.payload?.height as number);
|
||||
break;
|
||||
case "item_selected":
|
||||
setSelectedItemId((event.payload?.itemId as string) ?? null);
|
||||
// setSelectedItemId((event.payload?.itemId as string) ?? null);
|
||||
break;
|
||||
case "item_deselected":
|
||||
setSelectedItemId(null);
|
||||
@@ -59,13 +62,16 @@ function RouteComponent() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen flex-col px-4 py-6">
|
||||
<h1 className="text-3xl font-serif font-bold mb-6">{timeline.title}</h1>
|
||||
<div className="flex flex-col">
|
||||
<h1 className="text-3xl font-serif font-bold mb-6 mx-4">
|
||||
{timeline.title}
|
||||
</h1>
|
||||
|
||||
<FlutterView
|
||||
state={flutterState}
|
||||
onEvent={handleEvent}
|
||||
className="min-h-0 flex-1 rounded-lg overflow-hidden"
|
||||
className="overflow-hidden"
|
||||
height={flutterHeight}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user