commit
1ca8b99667
6 changed files with 123 additions and 134 deletions
|
|
@ -74,7 +74,7 @@ tabloDataRouter.get("/:tabloId/:fileName", checkTabloMember, async (c) => {
|
|||
tabloDataRouter.post(
|
||||
"/:tabloId/:fileName",
|
||||
regularUserCheckMiddleware,
|
||||
checkTabloAdmin,
|
||||
checkTabloMember,
|
||||
async (c) => {
|
||||
const tabloId = c.req.param("tabloId");
|
||||
const fileName = c.req.param("fileName");
|
||||
|
|
|
|||
|
|
@ -2,16 +2,15 @@ import { SessionProvider } from "@xtablo/shared/contexts/SessionContext";
|
|||
import { ThemeProvider } from "@xtablo/shared/contexts/ThemeContext";
|
||||
import { Toaster } from "@xtablo/ui/components/sonner";
|
||||
import { BrowserRouter as Router, useRoutes } from "react-router-dom";
|
||||
import { useCookieConsent } from "./hooks/useCookieConsent";
|
||||
import { CookieBanner } from "./components/CookieBanner";
|
||||
import { useCookieConsent } from "./hooks/useCookieConsent";
|
||||
import { useDatadogRumViewName } from "./hooks/useDatadogRumViewName";
|
||||
import { publicRoutes } from "./lib/publicRoutes";
|
||||
import { routes } from "./lib/routes";
|
||||
import { supabase } from "./lib/supabase";
|
||||
import { NotFoundPage } from "./pages/NotFoundPage";
|
||||
import { UserStoreProvider } from "./providers/UserStoreProvider";
|
||||
|
||||
import { useDatadogRumViewName } from "./hooks/useDatadogRumViewName";
|
||||
|
||||
const Routes = () => {
|
||||
useDatadogRumViewName();
|
||||
const publicElement = useRoutes(publicRoutes);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@xtablo/ui/components/button";
|
||||
import { Card } from "@xtablo/ui/components/card";
|
||||
import { Label } from "@xtablo/ui/components/label";
|
||||
import { Switch } from "@xtablo/ui/components/switch";
|
||||
import { X } from "lucide-react";
|
||||
import { Label } from "@xtablo/ui/components/label";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export interface CookiePreferences {
|
||||
essential: boolean;
|
||||
|
|
|
|||
|
|
@ -191,133 +191,126 @@ export const TabloFilesSection = ({ tablo, isAdmin }: TabloFilesSectionProps) =>
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* File Upload Section - Only for Admins and non-read-only users */}
|
||||
{isAdmin && !isReadOnly && (
|
||||
<div className="bg-card rounded-lg border border-border p-6">
|
||||
<div className="flex items-center space-x-2 mb-4">
|
||||
<svg
|
||||
className="w-5 h-5 text-green-600 dark:text-green-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
||||
/>
|
||||
</svg>
|
||||
<h3 className="text-lg font-semibold text-foreground">Ajouter un fichier</h3>
|
||||
</div>
|
||||
{/* File Upload Section - Available for all members */}
|
||||
<div className="bg-card rounded-lg border border-border p-6">
|
||||
<div className="flex items-center space-x-2 mb-4">
|
||||
<svg
|
||||
className="w-5 h-5 text-green-600 dark:text-green-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
||||
/>
|
||||
</svg>
|
||||
<h3 className="text-lg font-semibold text-foreground">Ajouter un fichier</h3>
|
||||
</div>
|
||||
|
||||
{!selectedFile ? (
|
||||
<div className="space-y-3">
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
onChange={handleFileSelect}
|
||||
className="hidden"
|
||||
accept="*/*"
|
||||
/>
|
||||
{!selectedFile ? (
|
||||
<div className="space-y-3">
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
onChange={handleFileSelect}
|
||||
className="hidden"
|
||||
accept="*/*"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
className="w-full justify-center py-8 border-2 border-dashed border-gray-300 dark:border-gray-600 hover:border-blue-400 dark:hover:border-blue-500 bg-gray-50 dark:bg-gray-800/50 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors rounded-md cursor-pointer inline-flex items-center"
|
||||
>
|
||||
<div className="flex flex-col items-center space-y-2">
|
||||
<svg
|
||||
className="w-8 h-8 text-gray-400 dark:text-gray-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
<div className="text-center">
|
||||
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Cliquez pour sélectionner un fichier
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center space-x-3 p-3 bg-blue-50 dark:bg-blue-900/20 rounded-md">
|
||||
<div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center text-white text-sm font-medium">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
{selectedFile.name}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
{(selectedFile.size / 1024 / 1024).toFixed(2)} MB
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
className="w-full justify-center py-8 border-2 border-dashed border-gray-300 dark:border-gray-600 hover:border-blue-400 dark:hover:border-blue-500 bg-gray-50 dark:bg-gray-800/50 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors rounded-md cursor-pointer inline-flex items-center"
|
||||
onClick={handleFileUpload}
|
||||
disabled={isUploading}
|
||||
className="flex-1 px-4 py-2.5 text-sm font-medium text-white bg-green-600 hover:bg-green-700 disabled:bg-gray-400 disabled:cursor-not-allowed rounded-lg transition-colors flex items-center justify-center space-x-2 shadow-sm"
|
||||
>
|
||||
<div className="flex flex-col items-center space-y-2">
|
||||
<svg
|
||||
className="w-8 h-8 text-gray-400 dark:text-gray-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
<div className="text-center">
|
||||
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Cliquez pour sélectionner un fichier
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{isUploading ? (
|
||||
<>
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
|
||||
<span>Ajout en cours...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
<span>Ajouter le fichier</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={cancelFileUpload}
|
||||
disabled={isUploading}
|
||||
className="px-4 py-2.5 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600 disabled:opacity-50 disabled:cursor-not-allowed rounded-lg transition-colors"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center space-x-3 p-3 bg-blue-50 dark:bg-blue-900/20 rounded-md">
|
||||
<div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center text-white text-sm font-medium">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
{selectedFile.name}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
{(selectedFile.size / 1024 / 1024).toFixed(2)} MB
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex space-x-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleFileUpload}
|
||||
disabled={isUploading}
|
||||
className="flex-1 px-4 py-2.5 text-sm font-medium text-white bg-green-600 hover:bg-green-700 disabled:bg-gray-400 disabled:cursor-not-allowed rounded-lg transition-colors flex items-center justify-center space-x-2 shadow-sm"
|
||||
>
|
||||
{isUploading ? (
|
||||
<>
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
|
||||
<span>Ajout en cours...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg
|
||||
className="w-4 h-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
<span>Ajouter le fichier</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={cancelFileUpload}
|
||||
disabled={isUploading}
|
||||
className="px-4 py-2.5 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-600 disabled:opacity-50 disabled:cursor-not-allowed rounded-lg transition-colors"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
Taille maximale par fichier: 20MB
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
Taille maximale par fichier: 20MB
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* File List */}
|
||||
<div className="bg-card rounded-lg border border-border p-6">
|
||||
|
|
@ -501,11 +494,9 @@ export const TabloFilesSection = ({ tablo, isAdmin }: TabloFilesSectionProps) =>
|
|||
/>
|
||||
</svg>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">Aucun fichier dans ce tablo</p>
|
||||
{isAdmin && !isReadOnly && (
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500 mt-1">
|
||||
Ajoutez votre premier fichier ci-dessus
|
||||
</p>
|
||||
)}
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500 mt-1">
|
||||
Ajoutez votre premier fichier ci-dessus
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ import { CameraIcon, CookieIcon, Loader2Icon, Trash2Icon, UploadIcon } from "luc
|
|||
import { useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { LanguageSelector } from "../components/LanguageSelector";
|
||||
import { useCookieConsent } from "../hooks/useCookieConsent";
|
||||
import { useIntroduction } from "../hooks/intros";
|
||||
import { useRemoveAvatar, useUpdateProfile, useUploadAvatar } from "../hooks/profile";
|
||||
import { useCookieConsent } from "../hooks/useCookieConsent";
|
||||
import { useUser } from "../providers/UserStoreProvider";
|
||||
|
||||
export default function SettingsPage() {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ export * from "./card";
|
|||
export * from "./checkbox";
|
||||
export * from "./clipboard";
|
||||
export * from "./collapsible";
|
||||
export * from "./cookie-banner";
|
||||
export * from "./date-field";
|
||||
export * from "./date-picker";
|
||||
export * from "./dialog";
|
||||
|
|
|
|||
Loading…
Reference in a new issue