Merge branch 'main' into develop

This commit is contained in:
Arthur Belleville 2025-11-18 10:07:28 +01:00
commit 054bcb63ee
No known key found for this signature in database
10 changed files with 813 additions and 763 deletions

View file

@ -525,7 +525,9 @@ describe("Tablo Endpoint", () => {
expect(latestNotification?.action_type).toBe("created");
// Message is now a JSONB object with en/fr keys
expect(latestNotification?.message).toBeDefined();
// biome-ignore lint/suspicious/noExplicitAny: testClient requires any for dynamic route access
expect((latestNotification?.message as any)?.en).toContain("invited");
// biome-ignore lint/suspicious/noExplicitAny: testClient requires any for dynamic route access
expect((latestNotification?.message as any)?.fr).toContain("invité");
expect(latestNotification?.read_at).toBeNull();
});
@ -570,7 +572,9 @@ describe("Tablo Endpoint", () => {
// Should create notification for the newly created temporary user
expect(notificationsForInvite?.length || 0).toBeGreaterThan(0);
// Message is now a JSONB object with en/fr keys
// biome-ignore lint/suspicious/noExplicitAny: testClient requires any for dynamic route access
expect((notificationsForInvite?.[0].message as any)?.en).toContain("invited");
// biome-ignore lint/suspicious/noExplicitAny: testClient requires any for dynamic route access
expect((notificationsForInvite?.[0].message as any)?.fr).toContain("invité");
});
});

View file

@ -8,7 +8,6 @@ import { fileURLToPath } from "url";
import { createConfig } from "./config.js";
import { MiddlewareManager } from "./middlewares/middleware.js";
import { getMainRouter } from "./routers/index.js";
import { getPublicRouter } from "./routers/public.js";
import { loadSecrets, type Secrets } from "./secrets.js";
tracer.init({
@ -55,7 +54,6 @@ async function startServer(secrets: Secrets) {
});
app.route("/api/v1", getMainRouter(config));
app.route("/api/public", getPublicRouter());
serve(
{

View file

@ -16,9 +16,6 @@ export const getMainRouter = (config: AppConfig) => {
// Apply supabase middleware globally (needed by all routes)
mainRouter.use(middlewareManager.supabase);
// public routes (only need supabase, no other middlewares)
mainRouter.route("/public", getPublicRouter());
// Apply remaining middlewares after public routes
mainRouter.use(middlewareManager.streamChat);
mainRouter.use(middlewareManager.r2);
@ -26,6 +23,9 @@ export const getMainRouter = (config: AppConfig) => {
mainRouter.use(middlewareManager.stripe);
mainRouter.use(middlewareManager.stripeSync);
// public routes
mainRouter.route("/public", getPublicRouter());
// tasks routes
mainRouter.route("/tasks", getTaskRouter());

View file

@ -12,6 +12,8 @@ import {
} from "../helpers/slots.js";
import type { BaseEnv } from "../types/app.types.js";
// import { MiddlewareManager } from "../middlewares/middleware.js";
const factory = createFactory<BaseEnv>();
const getPublicSlots = factory.createHandlers(async (c) => {
@ -124,7 +126,8 @@ const getPublicSlots = factory.createHandlers(async (c) => {
});
export const getPublicRouter = () => {
const publicRouter = new Hono();
const publicRouter = new Hono<BaseEnv>();
publicRouter.get("/slots/:shortUserId/:standardName", ...getPublicSlots);
return publicRouter;

View file

@ -1,3 +1,4 @@
import type { Database } from "@xtablo/shared-types";
import { Badge } from "@xtablo/ui/components/badge";
import { Button } from "@xtablo/ui/components/button";
import {
@ -13,21 +14,20 @@ import {
} from "@xtablo/ui/components/typography";
import {
BellIcon,
CheckCheckIcon,
CalendarIcon,
CheckCheckIcon,
FileTextIcon,
KanbanIcon,
LayoutDashboardIcon,
UserPlusIcon,
MailIcon,
UserPlusIcon,
XIcon,
} from "lucide-react";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { useNotifications, useNotificationsSubscription } from "../hooks/notifications";
import type { Database } from "@xtablo/shared-types";
import { twMerge } from "tailwind-merge";
import { useNotifications, useNotificationsSubscription } from "../hooks/notifications";
type Notification = Database["public"]["Tables"]["notifications"]["Row"];

View file

@ -1,6 +1,6 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { supabase } from "../lib/supabase";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { Database } from "@xtablo/shared-types";
import { supabase } from "../lib/supabase";
type Notification = Database["public"]["Tables"]["notifications"]["Row"];
@ -8,7 +8,12 @@ export function useNotifications() {
const queryClient = useQueryClient();
// Fetch unread notifications
const { data: notifications = [], isLoading, error, refetch } = useQuery({
const {
data: notifications = [],
isLoading,
error,
refetch,
} = useQuery({
queryKey: ["notifications", "unread"],
queryFn: async () => {
const { data, error } = await supabase
@ -67,7 +72,11 @@ export function useNotifications() {
// Hook to fetch all notifications (including read ones)
export function useAllNotifications(limit = 50) {
const { data: notifications = [], isLoading, error } = useQuery({
const {
data: notifications = [],
isLoading,
error,
} = useQuery({
queryKey: ["notifications", "all", limit],
queryFn: async () => {
const { data, error } = await supabase
@ -116,4 +125,3 @@ export function useNotificationsSubscription() {
return { setupSubscription };
}

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,7 @@ export type {
export type {
DragItem,
DropResult,
Etape,
KanbanBoard,
KanbanColumn,
KanbanColumnUpdate,

View file

@ -3,7 +3,15 @@ import type { RemoveNullFromObject } from "./utils.js";
export type TaskStatus = "todo" | "in_progress" | "in_review" | "done";
export type KanbanTask = RemoveNullFromObject<Tables<"tasks_with_assignee">, "id" | "tablo_id">;
export type KanbanTask = RemoveNullFromObject<
Tables<"tasks_with_assignee">,
"id" | "tablo_id" | "is_parent"
>;
export type Etape = RemoveNullFromObject<
Tables<"tasks">,
"id" | "tablo_id" | "title" | "is_parent"
>;
export interface KanbanColumn {
id: string;

View file

@ -32,7 +32,7 @@ export function usePublicSlots(api: AxiosInstance, shortUserId: string, standard
}>({
queryKey: ["public-slots", shortUserId, standardName],
queryFn: async () => {
const res = await api.get(`/api/public/slots/${shortUserId}/${standardName}`);
const res = await api.get(`/api/v1/public/slots/${shortUserId}/${standardName}`);
if (res.status !== 200) {
throw new Error("Failed to fetch public slots");
}