diff --git a/ui/src/App.tsx b/ui/src/App.tsx
index d89292f..8f89cd9 100644
--- a/ui/src/App.tsx
+++ b/ui/src/App.tsx
@@ -16,6 +16,7 @@ import { FacturesPage } from "./pages/factures";
import { PlanningPage } from "./pages/planning";
import { ChantiersPage } from "./pages/chantiers";
import { ChatPage } from "./pages/chat";
+import { FeedbackPage } from "./pages/feedback";
import { AllCommunityModule, ModuleRegistry } from "ag-grid-community";
import ChatProvider from "./providers/ChatProvider";
import { UserStoreProvider } from "./providers/UserStoreProvider";
@@ -83,6 +84,14 @@ export const App = () => {
}
/>
+
+
+
+ }
+ />
} />
} />
diff --git a/ui/src/components/NavigationBar.tsx b/ui/src/components/NavigationBar.tsx
index c980b9f..d6b88bf 100644
--- a/ui/src/components/NavigationBar.tsx
+++ b/ui/src/components/NavigationBar.tsx
@@ -354,7 +354,7 @@ export function MainNavigation({ isCollapsed }: { isCollapsed: boolean }) {
diff --git a/ui/src/hooks/feedback.ts b/ui/src/hooks/feedback.ts
new file mode 100644
index 0000000..276c578
--- /dev/null
+++ b/ui/src/hooks/feedback.ts
@@ -0,0 +1,22 @@
+import { useMutation } from "@tanstack/react-query";
+import { supabase } from "./auth";
+import { useUser } from "@ui/providers/UserStoreProvider";
+import { FeedbackData } from "@ui/pages/feedback";
+
+// Create new feedback
+export const useCreateFeedback = () => {
+ const user = useUser();
+ const { mutate, isSuccess, isPending } = useMutation({
+ mutationFn: async ({ fd_type, message }: FeedbackData) => {
+ const { error } = await supabase.from("feedbacks").insert({
+ fd_type,
+ message,
+ user_id: user?.id ?? "",
+ });
+ if (error) throw error;
+ },
+ onSuccess: () => {},
+ });
+
+ return { createFeedback: mutate, isSuccess, isPending };
+};
diff --git a/ui/src/pages/feedback.tsx b/ui/src/pages/feedback.tsx
new file mode 100644
index 0000000..fe49df9
--- /dev/null
+++ b/ui/src/pages/feedback.tsx
@@ -0,0 +1,157 @@
+import React, { useState } from "react";
+import { Button } from "@ui/ui-library/button";
+import { Form } from "@ui/ui-library/form";
+import { TextField, Label, TextArea, Description } from "@ui/ui-library/field";
+import { Text } from "@ui/ui-library/text";
+import { Separator } from "react-aria-components";
+import { SendIcon, ArrowLeftIcon } from "lucide-react";
+import { twMerge } from "tailwind-merge";
+import { useNavigate } from "react-router-dom";
+import { useCreateFeedback } from "@ui/hooks/feedback";
+
+export interface FeedbackData {
+ fd_type: "bug" | "feature" | "improvement" | "other";
+ message: string;
+}
+
+export function FeedbackPage() {
+ const navigate = useNavigate();
+ const [formData, setFormData] = useState({
+ fd_type: "improvement",
+ message: "",
+ });
+
+ const { createFeedback, isSuccess, isPending } = useCreateFeedback();
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ createFeedback(formData);
+ };
+
+ const handleInputChange = (field: keyof FeedbackData, value: string) => {
+ setFormData((prev) => ({ ...prev, [field]: value }));
+ };
+
+ return (
+
+ {/* Header */}
+
+
+
navigate(-1)}
+ aria-label="Retour"
+ className="shrink-0"
+ >
+
+
+
+ Envoyer un commentaire
+
+ Aidez-nous à améliorer XTablo en partageant vos idées
+
+
+
+
+
+
+
+ {isSuccess ? (
+
+
+
+
+
+ Merci pour votre commentaire !
+
+
+ Votre commentaire a été envoyé avec succès. Nous apprécions que vous
+ ayez pris le temps de nous aider à nous améliorer.
+
+
navigate(-1)}>
+
+ Retour
+
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/ui/src/providers/UserStoreProvider.tsx b/ui/src/providers/UserStoreProvider.tsx
index ff13025..04a6c94 100644
--- a/ui/src/providers/UserStoreProvider.tsx
+++ b/ui/src/providers/UserStoreProvider.tsx
@@ -19,6 +19,7 @@ export const UserStoreProvider = ({
children: React.ReactNode;
}) => {
const { session } = useSession();
+ const shouldFetchUser = !!session?.access_token;
const { data, isPending } = useQuery({
queryKey: ["user"],
queryFn: async () => {
@@ -42,10 +43,10 @@ export const UserStoreProvider = ({
streamToken: token,
};
},
- enabled: !!session?.access_token,
+ enabled: shouldFetchUser,
});
- if (isPending) {
+ if (isPending && shouldFetchUser) {
return ;
}