feat: multimodal AI event creation with image support #1
@@ -32,7 +32,7 @@ export default function SignInPage() {
|
|||||||
providerId: "authentik",
|
providerId: "authentik",
|
||||||
callbackURL: "/",
|
callbackURL: "/",
|
||||||
});
|
});
|
||||||
} catch (_error) {
|
} catch {
|
||||||
toast.error("Failed to sign in. Please try again.");
|
toast.error("Failed to sign in. Please try again.");
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|||||||
@@ -182,10 +182,9 @@ export default function HomePage() {
|
|||||||
|
|
||||||
const persistAiEvents = async (data: CalendarEvent[]) => {
|
const persistAiEvents = async (data: CalendarEvent[]) => {
|
||||||
for (const ev of data) {
|
for (const ev of data) {
|
||||||
const { id: _existingId, ...rest } = ev;
|
const newEvent: CalendarEvent = {
|
||||||
const newEvent = {
|
...ev,
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
...rest,
|
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
lastModified: new Date().toISOString(),
|
lastModified: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ export function IcsFilePicker({
|
|||||||
accept=".ics"
|
accept=".ics"
|
||||||
onChange={handleFileChange}
|
onChange={handleFileChange}
|
||||||
className="hidden"
|
className="hidden"
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ export function RRuleDisplayDetailed({
|
|||||||
|
|
||||||
{showBadges && details.length > 0 && (
|
{showBadges && details.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-1">
|
<div className="flex flex-wrap gap-1">
|
||||||
{details.map((detail, index) => (
|
{details.map((detail) => (
|
||||||
<Badge key={index} variant="outline" className="text-xs">
|
<Badge key={detail} variant="outline" className="text-xs">
|
||||||
{detail}
|
{detail}
|
||||||
</Badge>
|
</Badge>
|
||||||
))}
|
))}
|
||||||
@@ -159,7 +159,7 @@ function formatRRuleToHuman(rule: RecurrenceRule): string {
|
|||||||
const [, num, dayCode] = match;
|
const [, num, dayCode] = match;
|
||||||
const dayName = dayNames[dayCode as keyof typeof dayNames];
|
const dayName = dayNames[dayCode as keyof typeof dayNames];
|
||||||
if (num) {
|
if (num) {
|
||||||
const ordinal = getOrdinal(parseInt(num));
|
const ordinal = getOrdinal(parseInt(num, 10));
|
||||||
return `${ordinal} ${dayName}`;
|
return `${ordinal} ${dayName}`;
|
||||||
}
|
}
|
||||||
return dayName;
|
return dayName;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default function SignIn() {
|
|||||||
try {
|
try {
|
||||||
await signOut();
|
await signOut();
|
||||||
router.push("/");
|
router.push("/");
|
||||||
} catch (_error) {
|
} catch {
|
||||||
toast.error("Failed to sign out. Please try again.");
|
toast.error("Failed to sign out. Please try again.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import { drizzle } from "drizzle-orm/postgres-js";
|
|||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
import * as schema from "./schema";
|
import * as schema from "./schema";
|
||||||
|
|
||||||
const connectionString = process.env.DATABASE_URL!;
|
const connectionString = process.env.DATABASE_URL;
|
||||||
|
|
||||||
|
if (!connectionString) {
|
||||||
|
throw new Error("DATABASE_URL environment variable is required");
|
||||||
|
}
|
||||||
|
|
||||||
const client = postgres(connectionString, {
|
const client = postgres(connectionString, {
|
||||||
prepare: false,
|
prepare: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user