Compare commits
20 Commits
106f15205c
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
681d5da4d1
|
|||
|
65ccd2daaf
|
|||
|
7e6b670847
|
|||
|
14b7405961
|
|||
|
980a3dbe0c
|
|||
|
e693713267
|
|||
|
3ff1b82b85
|
|||
|
f42b09ebab
|
|||
|
908bf5f0c2
|
|||
|
fa4ef6320a
|
|||
|
45a96f618b
|
|||
|
bbfddefc76
|
|||
|
b10d9c515b
|
|||
|
29d6ab3d80
|
|||
|
429eb07291
|
|||
|
092d537180
|
|||
|
61c1f47409
|
|||
|
0247f6ed9d
|
|||
|
ba1433b192
|
|||
|
0e485aacee
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -49,5 +49,5 @@ next-env.d.ts
|
|||||||
# data storage (ne pas commit les données clients)
|
# data storage (ne pas commit les données clients)
|
||||||
/data/clients.json
|
/data/clients.json
|
||||||
|
|
||||||
# APK
|
# APK (commenté pour permettre le téléchargement depuis le dépôt)
|
||||||
/dist/*.apk
|
# /dist/*.apk
|
||||||
|
|||||||
@ -1,53 +1,37 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Suspense } from "react";
|
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import Layout from "@/components/layout/Layout";
|
import Layout from "@/components/layout/Layout";
|
||||||
import WifiCard from "@/components/accueil/WifiCard";
|
|
||||||
import Logo from "@/components/Logo";
|
import Logo from "@/components/Logo";
|
||||||
import { useClientData } from "@/lib/hooks/useClientData";
|
import { config } from "@/lib/config";
|
||||||
|
|
||||||
const WeatherWidget = dynamic(() => import("@/components/accueil/WeatherWidget"), {
|
const WeatherWidget = dynamic(() => import("@/components/accueil/WeatherWidget"), {
|
||||||
loading: () => <div className="h-32 bg-gray-100 rounded-2xl animate-pulse" />,
|
loading: () => <div className="h-32 bg-gray-100 dark:bg-gray-800 rounded-2xl animate-pulse" />,
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
function AccueilContent() {
|
export default function AccueilPage() {
|
||||||
const { bungalowNumber, gerantMessage, loading } = useClientData();
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<div className="px-4 py-6 space-y-6">
|
|
||||||
<div className="h-32 bg-gray-100 rounded-2xl animate-pulse" />
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<div className="px-4 py-6 space-y-6">
|
<div className="px-4 py-6 space-y-6">
|
||||||
<header className="text-center py-4">
|
<header className="text-center py-4">
|
||||||
<Logo size={140} className="mb-4" />
|
<Logo size={140} className="mb-4" />
|
||||||
<h1 className="text-2xl font-bold text-primary mb-2">
|
<h1 className="text-2xl font-bold text-primary dark:text-primary mb-2">
|
||||||
Ia Ora Na
|
Ia Ora Na
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg text-gray-700">
|
<p className="text-lg text-gray-700 dark:text-gray-300">
|
||||||
Bienvenue au Bungalow {bungalowNumber}
|
Bienvenue à la Pension Marama
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<WifiCard />
|
|
||||||
|
|
||||||
<WeatherWidget />
|
<WeatherWidget />
|
||||||
|
|
||||||
<section className="bg-secondary rounded-2xl p-6">
|
<section className="bg-secondary dark:bg-primary/20 rounded-2xl p-6">
|
||||||
<h2 className="text-xl font-semibold text-primary mb-3">
|
<h2 className="text-xl font-semibold text-primary dark:text-primary mb-3">
|
||||||
Le mot du gérant
|
Le mot du gérant
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-700 leading-relaxed">
|
<p className="text-gray-700 dark:text-gray-300 leading-relaxed">
|
||||||
{gerantMessage}
|
{config.gerantMessage}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -55,17 +39,3 @@ function AccueilContent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AccueilPage() {
|
|
||||||
return (
|
|
||||||
<Suspense fallback={
|
|
||||||
<Layout>
|
|
||||||
<div className="px-4 py-6 space-y-6">
|
|
||||||
<div className="h-32 bg-gray-100 rounded-2xl animate-pulse" />
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
}>
|
|
||||||
<AccueilContent />
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@ -1,85 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
||||||
import Logo from "@/components/Logo";
|
|
||||||
|
|
||||||
export default function AdminLoginPage() {
|
|
||||||
const [password, setPassword] = useState("");
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setError("");
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
// Vérification simple côté client (la vraie vérification se fait côté serveur)
|
|
||||||
// Pour l'instant, on stocke le mot de passe dans localStorage
|
|
||||||
localStorage.setItem("adminPassword", password);
|
|
||||||
|
|
||||||
// Test avec une requête API
|
|
||||||
try {
|
|
||||||
const response = await fetch("/api/admin/clients", {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${password}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
router.push("/admin");
|
|
||||||
} else {
|
|
||||||
setError("Mot de passe incorrect");
|
|
||||||
localStorage.removeItem("adminPassword");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
setError("Erreur de connexion");
|
|
||||||
localStorage.removeItem("adminPassword");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen bg-background flex items-center justify-center px-4">
|
|
||||||
<Card className="w-full max-w-md">
|
|
||||||
<CardHeader className="text-center">
|
|
||||||
<div className="flex justify-center mb-4">
|
|
||||||
<Logo size={100} />
|
|
||||||
</div>
|
|
||||||
<CardTitle>Administration</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Mot de passe
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
value={password}
|
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error && (
|
|
||||||
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-xl text-sm">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button type="submit" disabled={loading} className="w-full">
|
|
||||||
{loading ? "Connexion..." : "Se connecter"}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import AdminLayout from "@/components/admin/AdminLayout";
|
|
||||||
import ClientForm from "@/components/admin/ClientForm";
|
|
||||||
import ClientList from "@/components/admin/ClientList";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Plus } from "lucide-react";
|
|
||||||
import { Client } from "@/lib/types/client";
|
|
||||||
|
|
||||||
export default function AdminPage() {
|
|
||||||
const [showForm, setShowForm] = useState(false);
|
|
||||||
const [editingClient, setEditingClient] = useState<Client | undefined>();
|
|
||||||
const [refreshKey, setRefreshKey] = useState(0);
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Vérifier si l'admin est connecté
|
|
||||||
const adminPassword = localStorage.getItem("adminPassword");
|
|
||||||
if (!adminPassword) {
|
|
||||||
router.push("/admin/login");
|
|
||||||
}
|
|
||||||
}, [router]);
|
|
||||||
|
|
||||||
const handleNewClient = () => {
|
|
||||||
setEditingClient(undefined);
|
|
||||||
setShowForm(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEdit = (client: Client) => {
|
|
||||||
setEditingClient(client);
|
|
||||||
setShowForm(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSuccess = () => {
|
|
||||||
setShowForm(false);
|
|
||||||
setEditingClient(undefined);
|
|
||||||
setRefreshKey((k) => k + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
setShowForm(false);
|
|
||||||
setEditingClient(undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AdminLayout>
|
|
||||||
<div className="space-y-6">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h2 className="text-2xl font-bold text-primary">Gestion des clients</h2>
|
|
||||||
{!showForm && (
|
|
||||||
<Button onClick={handleNewClient}>
|
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
|
||||||
Nouveau client
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{showForm ? (
|
|
||||||
<ClientForm
|
|
||||||
client={editingClient}
|
|
||||||
onSuccess={handleSuccess}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ClientList onEdit={handleEdit} onRefresh={() => setRefreshKey((k) => k + 1)} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</AdminLayout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,153 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
|
||||||
import { writeFile, readFile, mkdir } from "fs/promises";
|
|
||||||
import { existsSync } from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import { Client, ClientInput } from "@/lib/types/client";
|
|
||||||
|
|
||||||
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || "admin123";
|
|
||||||
const DATA_DIR = path.join(process.cwd(), "data");
|
|
||||||
const CLIENTS_FILE = path.join(DATA_DIR, "clients.json");
|
|
||||||
|
|
||||||
function verifyAuth(request: NextRequest): boolean {
|
|
||||||
const authHeader = request.headers.get("authorization");
|
|
||||||
if (!authHeader) return false;
|
|
||||||
|
|
||||||
const token = authHeader.replace("Bearer ", "");
|
|
||||||
return token === ADMIN_PASSWORD;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadClients(): Promise<Client[]> {
|
|
||||||
try {
|
|
||||||
if (!existsSync(CLIENTS_FILE)) {
|
|
||||||
if (!existsSync(DATA_DIR)) {
|
|
||||||
await mkdir(DATA_DIR, { recursive: true });
|
|
||||||
}
|
|
||||||
await writeFile(CLIENTS_FILE, JSON.stringify([], null, 2));
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await readFile(CLIENTS_FILE, "utf-8");
|
|
||||||
return JSON.parse(data);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur lecture clients:", error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveClients(clients: Client[]): Promise<void> {
|
|
||||||
try {
|
|
||||||
if (!existsSync(DATA_DIR)) {
|
|
||||||
await mkdir(DATA_DIR, { recursive: true });
|
|
||||||
}
|
|
||||||
await writeFile(CLIENTS_FILE, JSON.stringify(clients, null, 2));
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur sauvegarde clients:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET - Récupérer un client par ID
|
|
||||||
export async function GET(
|
|
||||||
request: NextRequest,
|
|
||||||
{ params }: { params: { id: string } }
|
|
||||||
) {
|
|
||||||
if (!verifyAuth(request)) {
|
|
||||||
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const clients = await loadClients();
|
|
||||||
const client = clients.find(c => c.id === params.id);
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Client non trouvé" },
|
|
||||||
{ status: 404 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(client);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur GET client:", error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Erreur serveur" },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT - Mettre à jour un client
|
|
||||||
export async function PUT(
|
|
||||||
request: NextRequest,
|
|
||||||
{ params }: { params: { id: string } }
|
|
||||||
) {
|
|
||||||
if (!verifyAuth(request)) {
|
|
||||||
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const input: ClientInput = await request.json();
|
|
||||||
const clients = await loadClients();
|
|
||||||
const clientIndex = clients.findIndex(c => c.id === params.id);
|
|
||||||
|
|
||||||
if (clientIndex === -1) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Client non trouvé" },
|
|
||||||
{ status: 404 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mettre à jour le client
|
|
||||||
const updatedClient: Client = {
|
|
||||||
...clients[clientIndex],
|
|
||||||
email: input.email || clients[clientIndex].email,
|
|
||||||
bungalowNumber: input.bungalowNumber || clients[clientIndex].bungalowNumber,
|
|
||||||
wifiName: input.wifiName || clients[clientIndex].wifiName,
|
|
||||||
wifiPassword: input.wifiPassword || clients[clientIndex].wifiPassword,
|
|
||||||
gerantMessage: input.gerantMessage || clients[clientIndex].gerantMessage,
|
|
||||||
};
|
|
||||||
|
|
||||||
clients[clientIndex] = updatedClient;
|
|
||||||
await saveClients(clients);
|
|
||||||
|
|
||||||
return NextResponse.json(updatedClient);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur PUT client:", error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Erreur serveur" },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE - Supprimer un client
|
|
||||||
export async function DELETE(
|
|
||||||
request: NextRequest,
|
|
||||||
{ params }: { params: { id: string } }
|
|
||||||
) {
|
|
||||||
if (!verifyAuth(request)) {
|
|
||||||
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const clients = await loadClients();
|
|
||||||
const filteredClients = clients.filter(c => c.id !== params.id);
|
|
||||||
|
|
||||||
if (filteredClients.length === clients.length) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Client non trouvé" },
|
|
||||||
{ status: 404 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await saveClients(filteredClients);
|
|
||||||
return NextResponse.json({ success: true });
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur DELETE client:", error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Erreur serveur" },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,131 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
|
||||||
import { writeFile, readFile, mkdir } from "fs/promises";
|
|
||||||
import { existsSync } from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import { Client, ClientInput } from "@/lib/types/client";
|
|
||||||
|
|
||||||
// Mot de passe admin (à changer en production via variable d'environnement)
|
|
||||||
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || "admin123";
|
|
||||||
|
|
||||||
// Chemin vers le fichier de stockage
|
|
||||||
const DATA_DIR = path.join(process.cwd(), "data");
|
|
||||||
const CLIENTS_FILE = path.join(DATA_DIR, "clients.json");
|
|
||||||
|
|
||||||
// Vérifier l'authentification
|
|
||||||
function verifyAuth(request: NextRequest): boolean {
|
|
||||||
const authHeader = request.headers.get("authorization");
|
|
||||||
if (!authHeader) return false;
|
|
||||||
|
|
||||||
const token = authHeader.replace("Bearer ", "");
|
|
||||||
return token === ADMIN_PASSWORD;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Charger les clients depuis le fichier
|
|
||||||
async function loadClients(): Promise<Client[]> {
|
|
||||||
try {
|
|
||||||
if (!existsSync(CLIENTS_FILE)) {
|
|
||||||
// Créer le répertoire et le fichier si nécessaire
|
|
||||||
if (!existsSync(DATA_DIR)) {
|
|
||||||
await mkdir(DATA_DIR, { recursive: true });
|
|
||||||
}
|
|
||||||
await writeFile(CLIENTS_FILE, JSON.stringify([], null, 2));
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await readFile(CLIENTS_FILE, "utf-8");
|
|
||||||
return JSON.parse(data);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur lecture clients:", error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sauvegarder les clients dans le fichier
|
|
||||||
async function saveClients(clients: Client[]): Promise<void> {
|
|
||||||
try {
|
|
||||||
if (!existsSync(DATA_DIR)) {
|
|
||||||
await mkdir(DATA_DIR, { recursive: true });
|
|
||||||
}
|
|
||||||
await writeFile(CLIENTS_FILE, JSON.stringify(clients, null, 2));
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur sauvegarde clients:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET - Récupérer tous les clients
|
|
||||||
export async function GET(request: NextRequest) {
|
|
||||||
if (!verifyAuth(request)) {
|
|
||||||
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const clients = await loadClients();
|
|
||||||
return NextResponse.json(clients);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur GET clients:", error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Erreur serveur" },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST - Créer un nouveau client
|
|
||||||
export async function POST(request: NextRequest) {
|
|
||||||
if (!verifyAuth(request)) {
|
|
||||||
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const input: ClientInput = await request.json();
|
|
||||||
|
|
||||||
// Validation
|
|
||||||
if (!input.email || !input.bungalowNumber) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Email et numéro de bungalow requis" },
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const clients = await loadClients();
|
|
||||||
|
|
||||||
// Vérifier si l'email existe déjà
|
|
||||||
if (clients.some(c => c.email === input.email)) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Un client avec cet email existe déjà" },
|
|
||||||
{ status: 409 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Créer le nouveau client
|
|
||||||
const newClient: Client = {
|
|
||||||
id: `client-${Date.now()}`,
|
|
||||||
token: generateToken(),
|
|
||||||
email: input.email,
|
|
||||||
bungalowNumber: input.bungalowNumber,
|
|
||||||
wifiName: input.wifiName || "Lagon-WiFi",
|
|
||||||
wifiPassword: input.wifiPassword || "",
|
|
||||||
gerantMessage: input.gerantMessage || "Bienvenue dans notre pension de famille !",
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
clients.push(newClient);
|
|
||||||
await saveClients(clients);
|
|
||||||
|
|
||||||
return NextResponse.json(newClient, { status: 201 });
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur POST client:", error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Erreur serveur" },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Générer un token unique
|
|
||||||
function generateToken(): string {
|
|
||||||
return Math.random().toString(36).substring(2, 15) +
|
|
||||||
Math.random().toString(36).substring(2, 15);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
|
||||||
import { readFile } from "fs/promises";
|
|
||||||
import { existsSync } from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import { Client } from "@/lib/types/client";
|
|
||||||
|
|
||||||
const DATA_DIR = path.join(process.cwd(), "data");
|
|
||||||
const CLIENTS_FILE = path.join(DATA_DIR, "clients.json");
|
|
||||||
|
|
||||||
async function loadClients(): Promise<Client[]> {
|
|
||||||
try {
|
|
||||||
if (!existsSync(CLIENTS_FILE)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await readFile(CLIENTS_FILE, "utf-8");
|
|
||||||
return JSON.parse(data);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur lecture clients:", error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET - Récupérer les données d'un client par son token
|
|
||||||
export async function GET(
|
|
||||||
request: NextRequest,
|
|
||||||
{ params }: { params: { token: string } }
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const clients = await loadClients();
|
|
||||||
const client = clients.find(c => c.token === params.token);
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Client non trouvé" },
|
|
||||||
{ status: 404 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retourner uniquement les données nécessaires (pas le token ni l'ID)
|
|
||||||
return NextResponse.json({
|
|
||||||
bungalowNumber: client.bungalowNumber,
|
|
||||||
wifiName: client.wifiName,
|
|
||||||
wifiPassword: client.wifiPassword,
|
|
||||||
gerantMessage: client.gerantMessage,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur GET client par token:", error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Erreur serveur" },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
body {
|
body {
|
||||||
@apply bg-background;
|
@apply bg-background dark:bg-background-dark;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
color: #1f2937;
|
@apply text-foreground dark:text-foreground-dark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { Metadata } from "next";
|
|||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import PWARegister from "@/components/PWARegister";
|
import PWARegister from "@/components/PWARegister";
|
||||||
|
import { ThemeProvider } from "@/components/ThemeProvider";
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
@ -29,14 +30,21 @@ export default function RootLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="fr">
|
<html lang="fr" suppressHydrationWarning>
|
||||||
<head>
|
<head>
|
||||||
<link rel="icon" href="/logo-relais-marama.svg" type="image/svg+xml" />
|
<link rel="icon" href="/logo-relais-marama.svg" type="image/svg+xml" />
|
||||||
<link rel="apple-touch-icon" href="/logo-relais-marama.svg" />
|
<link rel="apple-touch-icon" href="/logo-relais-marama.svg" />
|
||||||
</head>
|
</head>
|
||||||
<body className={inter.className}>
|
<body className={inter.className}>
|
||||||
|
<ThemeProvider
|
||||||
|
attribute="class"
|
||||||
|
defaultTheme="light"
|
||||||
|
enableSystem={true}
|
||||||
|
disableTransitionOnChange={false}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
<PWARegister />
|
<PWARegister />
|
||||||
|
</ThemeProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,11 +11,10 @@ export default function Home() {
|
|||||||
}, [router]);
|
}, [router]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen bg-background dark:bg-background-dark">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-gray-600">Redirection...</p>
|
<p className="text-gray-600 dark:text-gray-400">Redirection...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ export default function Logo({ size = 120, className = "" }: LogoProps) {
|
|||||||
alt="Relais Marama - Fakarava"
|
alt="Relais Marama - Fakarava"
|
||||||
width={size}
|
width={size}
|
||||||
height={size}
|
height={size}
|
||||||
className="object-contain"
|
className="object-contain dark:invert"
|
||||||
style={{ maxWidth: `${size}px`, maxHeight: `${size}px` }}
|
style={{ maxWidth: `${size}px`, maxHeight: `${size}px` }}
|
||||||
/>
|
/>
|
||||||
<p className="text-primary font-semibold mt-2" style={{ fontSize: `${size * 0.15}px` }}>
|
<p className="text-primary font-semibold mt-2" style={{ fontSize: `${size * 0.15}px` }}>
|
||||||
|
|||||||
12
components/ThemeProvider.tsx
Normal file
12
components/ThemeProvider.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||||
|
import { type ComponentProps } from "react";
|
||||||
|
|
||||||
|
export function ThemeProvider({
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: ComponentProps<typeof NextThemesProvider>) {
|
||||||
|
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||||
|
}
|
||||||
|
|
||||||
45
components/ThemeToggle.tsx
Normal file
45
components/ThemeToggle.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useTheme } from "next-themes";
|
||||||
|
import { Moon, Sun } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export function ThemeToggle() {
|
||||||
|
const { theme, setTheme } = useTheme();
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!mounted) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-9 w-9 rounded-full p-0"
|
||||||
|
aria-label="Changer de thème"
|
||||||
|
>
|
||||||
|
<Sun className="h-5 w-5" />
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
||||||
|
className="h-10 w-10 rounded-full hover:bg-secondary dark:hover:bg-gray-800 p-0"
|
||||||
|
aria-label="Changer de thème"
|
||||||
|
>
|
||||||
|
{theme === "dark" ? (
|
||||||
|
<Sun className="h-5 w-5 text-primary dark:text-yellow-400" />
|
||||||
|
) : (
|
||||||
|
<Moon className="h-5 w-5 text-primary dark:text-blue-300" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,35 +1,177 @@
|
|||||||
import { Cloud, Sun } from "lucide-react";
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { Cloud, Sun, CloudRain, Wind, Droplets, Loader2, Clock } from "lucide-react";
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||||
|
|
||||||
|
interface WeatherData {
|
||||||
|
temperature: number;
|
||||||
|
condition: string;
|
||||||
|
windSpeed: number;
|
||||||
|
humidity: number;
|
||||||
|
weatherCode: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coordonnées de Fakarava (Rotoava)
|
||||||
|
const FAKARAVA_LAT = -16.3167;
|
||||||
|
const FAKARAVA_LON = -145.6167;
|
||||||
|
|
||||||
|
// Codes météo Open-Meteo vers descriptions
|
||||||
|
const getWeatherCondition = (code: number): { text: string; icon: React.ReactNode } => {
|
||||||
|
// Codes Open-Meteo WMO Weather interpretation codes
|
||||||
|
if (code === 0) {
|
||||||
|
return { text: "Ciel dégagé", icon: <Sun className="h-16 w-16 text-yellow-400" /> };
|
||||||
|
} else if (code <= 3) {
|
||||||
|
return { text: "Partiellement nuageux", icon: <Cloud className="h-16 w-16 text-gray-400" /> };
|
||||||
|
} else if (code <= 48) {
|
||||||
|
return { text: "Nuageux", icon: <Cloud className="h-16 w-16 text-gray-500" /> };
|
||||||
|
} else if (code <= 55) {
|
||||||
|
return { text: "Brouillard", icon: <Cloud className="h-16 w-16 text-gray-400" /> };
|
||||||
|
} else if (code <= 67) {
|
||||||
|
return { text: "Pluie", icon: <CloudRain className="h-16 w-16 text-blue-400" /> };
|
||||||
|
} else if (code <= 77) {
|
||||||
|
return { text: "Neige", icon: <CloudRain className="h-16 w-16 text-gray-300" /> };
|
||||||
|
} else if (code <= 82) {
|
||||||
|
return { text: "Averses", icon: <CloudRain className="h-16 w-16 text-blue-500" /> };
|
||||||
|
} else if (code <= 86) {
|
||||||
|
return { text: "Averses de neige", icon: <CloudRain className="h-16 w-16 text-gray-300" /> };
|
||||||
|
} else {
|
||||||
|
return { text: "Orage", icon: <CloudRain className="h-16 w-16 text-purple-500" /> };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default function WeatherWidget() {
|
export default function WeatherWidget() {
|
||||||
|
const [weather, setWeather] = useState<WeatherData | null>(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [localTime, setLocalTime] = useState<string>("");
|
||||||
|
|
||||||
|
// Mise à jour de l'heure locale chaque seconde
|
||||||
|
useEffect(() => {
|
||||||
|
const updateTime = () => {
|
||||||
|
const now = new Date();
|
||||||
|
// Fuseau horaire de Tahiti (UTC-10)
|
||||||
|
const tahitiTime = new Date(now.toLocaleString("en-US", { timeZone: "Pacific/Tahiti" }));
|
||||||
|
const hours = tahitiTime.getHours().toString().padStart(2, "0");
|
||||||
|
const minutes = tahitiTime.getMinutes().toString().padStart(2, "0");
|
||||||
|
setLocalTime(`${hours}:${minutes}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
updateTime();
|
||||||
|
const timeInterval = setInterval(updateTime, 1000);
|
||||||
|
return () => clearInterval(timeInterval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchWeather = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
// API Open-Meteo (gratuit, pas de clé API nécessaire)
|
||||||
|
const response = await fetch(
|
||||||
|
`https://api.open-meteo.com/v1/forecast?latitude=${FAKARAVA_LAT}&longitude=${FAKARAVA_LON}¤t=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m&wind_speed_unit=kmh&timezone=Pacific/Tahiti`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Erreur lors de la récupération de la météo");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
const current = data.current;
|
||||||
|
|
||||||
|
setWeather({
|
||||||
|
temperature: Math.round(current.temperature_2m),
|
||||||
|
condition: getWeatherCondition(current.weather_code).text,
|
||||||
|
windSpeed: Math.round(current.wind_speed_10m),
|
||||||
|
humidity: current.relative_humidity_2m,
|
||||||
|
weatherCode: current.weather_code,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur météo:", err);
|
||||||
|
setError("Impossible de charger la météo");
|
||||||
|
// Valeurs par défaut en cas d'erreur
|
||||||
|
setWeather({
|
||||||
|
temperature: 28,
|
||||||
|
condition: "Ensoleillé",
|
||||||
|
windSpeed: 15,
|
||||||
|
humidity: 75,
|
||||||
|
weatherCode: 0,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchWeather();
|
||||||
|
|
||||||
|
// Rafraîchir toutes les heures
|
||||||
|
const interval = setInterval(fetchWeather, 3600000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Card className="bg-gradient-to-br from-primary/10 to-secondary">
|
<Card className="bg-gradient-to-br from-primary/10 to-secondary">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center gap-2">
|
<CardTitle className="flex items-center gap-2">
|
||||||
<Sun className="h-6 w-6 text-primary" />
|
<Sun className="h-6 w-6 text-primary" />
|
||||||
Météo
|
Météo - Fakarava
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-center py-8">
|
||||||
<div>
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||||
<p className="text-3xl font-bold text-primary">28°C</p>
|
|
||||||
<p className="text-gray-600 mt-1">Ensoleillé</p>
|
|
||||||
</div>
|
|
||||||
<div className="text-6xl">
|
|
||||||
<Sun className="h-16 w-16 text-yellow-400" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-4 flex gap-4 text-sm text-gray-600">
|
|
||||||
<div>
|
|
||||||
<span className="font-semibold">Vent:</span> 15 km/h
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="font-semibold">Humidité:</span> 75%
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!weather) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const weatherInfo = getWeatherCondition(weather.weatherCode);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="bg-gradient-to-br from-primary/10 to-secondary">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Sun className="h-6 w-6 text-primary" />
|
||||||
|
Météo - Fakarava
|
||||||
|
</div>
|
||||||
|
{localTime && (
|
||||||
|
<div className="flex items-center gap-1 text-sm font-normal text-gray-600 dark:text-gray-400">
|
||||||
|
<Clock className="h-4 w-4" />
|
||||||
|
{localTime}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p className="text-3xl font-bold text-primary">{weather.temperature}°C</p>
|
||||||
|
<p className="text-gray-600 dark:text-gray-300 mt-1">{weather.condition}</p>
|
||||||
|
{error && (
|
||||||
|
<p className="text-xs text-orange-500 mt-1">Données en cache</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="text-6xl">{weatherInfo.icon}</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 flex gap-4 text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Wind className="h-4 w-4" />
|
||||||
|
<span className="font-semibold">Vent:</span> {weather.windSpeed} km/h
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<Droplets className="h-4 w-4" />
|
||||||
|
<span className="font-semibold">Humidité:</span> {weather.humidity}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,129 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
|
||||||
import { Wifi, Copy, Check, AlertCircle } from "lucide-react";
|
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useClientData } from "@/lib/hooks/useClientData";
|
|
||||||
|
|
||||||
export default function WifiCard() {
|
|
||||||
const { wifiName, wifiPassword, loading } = useClientData();
|
|
||||||
const [copied, setCopied] = useState(false);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
|
|
||||||
// Fonction de copie avec fallback pour les navigateurs qui ne supportent pas l'API Clipboard
|
|
||||||
const copyToClipboard = async (text: string): Promise<boolean> => {
|
|
||||||
// Méthode moderne (nécessite HTTPS ou localhost)
|
|
||||||
if (navigator.clipboard && window.isSecureContext) {
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(text);
|
|
||||||
return true;
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Erreur avec l'API Clipboard:", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback pour les navigateurs plus anciens ou contextes non sécurisés
|
|
||||||
try {
|
|
||||||
const textArea = document.createElement("textarea");
|
|
||||||
textArea.value = text;
|
|
||||||
textArea.style.position = "fixed";
|
|
||||||
textArea.style.left = "-999999px";
|
|
||||||
textArea.style.top = "-999999px";
|
|
||||||
document.body.appendChild(textArea);
|
|
||||||
textArea.focus();
|
|
||||||
textArea.select();
|
|
||||||
|
|
||||||
const successful = document.execCommand("copy");
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
|
|
||||||
if (successful) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new Error("La commande copy a échoué");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Erreur avec la méthode fallback:", err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCopyPassword = async () => {
|
|
||||||
if (!wifiPassword || wifiPassword.trim() === "") {
|
|
||||||
setError("Le mot de passe WiFi n'est pas disponible");
|
|
||||||
setTimeout(() => setError(null), 3000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setError(null);
|
|
||||||
const success = await copyToClipboard(wifiPassword);
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
setCopied(true);
|
|
||||||
setTimeout(() => setCopied(false), 2000);
|
|
||||||
} else {
|
|
||||||
setError("Impossible de copier. Veuillez sélectionner manuellement le mot de passe ci-dessous.");
|
|
||||||
setTimeout(() => setError(null), 5000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Afficher le mot de passe en cas d'échec de la copie
|
|
||||||
const showPasswordFallback = error && error.includes("sélectionner manuellement");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card className="bg-white">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="flex items-center gap-2">
|
|
||||||
<Wifi className="h-6 w-6 text-primary" />
|
|
||||||
Connexion WiFi
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<p className="text-sm text-gray-600 mb-1">Nom du réseau</p>
|
|
||||||
<p className="text-lg font-semibold text-primary">{wifiName || "Chargement..."}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{showPasswordFallback && wifiPassword && (
|
|
||||||
<div className="bg-yellow-50 border border-yellow-200 rounded-xl p-3">
|
|
||||||
<p className="text-sm text-yellow-800 font-mono select-all">
|
|
||||||
{wifiPassword}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{error && !showPasswordFallback && (
|
|
||||||
<div className="bg-red-50 border border-red-200 rounded-xl p-3 flex items-start gap-2">
|
|
||||||
<AlertCircle className="h-5 w-5 text-red-600 flex-shrink-0 mt-0.5" />
|
|
||||||
<p className="text-sm text-red-800">{error}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
onClick={handleCopyPassword}
|
|
||||||
disabled={loading || !wifiPassword}
|
|
||||||
className="w-full h-14 text-lg"
|
|
||||||
size="lg"
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<>
|
|
||||||
<Copy className="mr-2 h-5 w-5" />
|
|
||||||
Chargement...
|
|
||||||
</>
|
|
||||||
) : copied ? (
|
|
||||||
<>
|
|
||||||
<Check className="mr-2 h-5 w-5" />
|
|
||||||
Mot de passe copié !
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Copy className="mr-2 h-5 w-5" />
|
|
||||||
Copier le mot de passe
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { LogOut } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
|
|
||||||
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const handleLogout = () => {
|
|
||||||
localStorage.removeItem("adminPassword");
|
|
||||||
router.push("/admin/login");
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen bg-background">
|
|
||||||
<header className="bg-white border-b border-gray-200 shadow-sm">
|
|
||||||
<div className="max-w-4xl mx-auto px-4 py-4 flex items-center justify-between">
|
|
||||||
<h1 className="text-xl font-bold text-primary">Administration</h1>
|
|
||||||
<Button variant="outline" size="sm" onClick={handleLogout}>
|
|
||||||
<LogOut className="h-4 w-4 mr-2" />
|
|
||||||
Déconnexion
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<main className="max-w-4xl mx-auto px-4 py-6">{children}</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,264 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
||||||
import { Client, ClientInput } from "@/lib/types/client";
|
|
||||||
import QRCodeDisplay from "./QRCodeDisplay";
|
|
||||||
import { Copy, Check } from "lucide-react";
|
|
||||||
|
|
||||||
interface ClientFormProps {
|
|
||||||
client?: Client;
|
|
||||||
onSuccess: () => void;
|
|
||||||
onCancel: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ClientForm({ client, onSuccess, onCancel }: ClientFormProps) {
|
|
||||||
const [formData, setFormData] = useState<ClientInput>({
|
|
||||||
email: client?.email || "",
|
|
||||||
bungalowNumber: client?.bungalowNumber || "",
|
|
||||||
wifiName: client?.wifiName || "Lagon-WiFi",
|
|
||||||
wifiPassword: client?.wifiPassword || "",
|
|
||||||
gerantMessage: client?.gerantMessage || "Bienvenue dans notre pension de famille !",
|
|
||||||
});
|
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
const [createdClient, setCreatedClient] = useState<Client | null>(client || null);
|
|
||||||
const [copied, setCopied] = useState(false);
|
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setLoading(true);
|
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const adminPassword = localStorage.getItem("adminPassword") || "";
|
|
||||||
const url = client
|
|
||||||
? `/api/admin/clients/${client.id}`
|
|
||||||
: "/api/admin/clients";
|
|
||||||
|
|
||||||
const method = client ? "PUT" : "POST";
|
|
||||||
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${adminPassword}`,
|
|
||||||
},
|
|
||||||
body: JSON.stringify(formData),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = await response.json();
|
|
||||||
throw new Error(data.error || "Erreur lors de la sauvegarde");
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
setCreatedClient(data);
|
|
||||||
onSuccess();
|
|
||||||
} catch (err: any) {
|
|
||||||
setError(err.message);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getClientUrl = () => {
|
|
||||||
if (!createdClient) return "";
|
|
||||||
const baseUrl = typeof window !== "undefined" ? window.location.origin : "";
|
|
||||||
return `${baseUrl}/accueil?token=${createdClient.token}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCopyLink = async () => {
|
|
||||||
const url = getClientUrl();
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(url);
|
|
||||||
setCopied(true);
|
|
||||||
// Alerte pour confirmer
|
|
||||||
alert(`✅ Lien copié !\n\n${url}\n\nVous pouvez maintenant le coller (Ctrl+V) pour le partager avec votre client.`);
|
|
||||||
setTimeout(() => setCopied(false), 3000);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Erreur lors de la copie:", err);
|
|
||||||
// Fallback pour les navigateurs plus anciens
|
|
||||||
const textArea = document.createElement("textarea");
|
|
||||||
textArea.value = url;
|
|
||||||
textArea.style.position = "fixed";
|
|
||||||
textArea.style.left = "-999999px";
|
|
||||||
document.body.appendChild(textArea);
|
|
||||||
textArea.select();
|
|
||||||
try {
|
|
||||||
const successful = document.execCommand("copy");
|
|
||||||
if (successful) {
|
|
||||||
setCopied(true);
|
|
||||||
alert(`✅ Lien copié !\n\n${url}\n\nVous pouvez maintenant le coller (Ctrl+V) pour le partager avec votre client.`);
|
|
||||||
setTimeout(() => setCopied(false), 3000);
|
|
||||||
} else {
|
|
||||||
alert(`❌ Copie automatique non supportée.\n\nVeuillez copier manuellement le lien:\n\n${url}`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
alert(`❌ Copie automatique non supportée.\n\nVeuillez copier manuellement le lien:\n\n${url}`);
|
|
||||||
}
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>{client ? "Modifier le client" : "Nouveau client"}</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Email *
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
required
|
|
||||||
value={formData.email}
|
|
||||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
|
||||||
disabled={!!client}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-primary focus:border-transparent disabled:bg-gray-100"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Numéro de bungalow *
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
required
|
|
||||||
value={formData.bungalowNumber}
|
|
||||||
onChange={(e) =>
|
|
||||||
setFormData({ ...formData, bungalowNumber: e.target.value })
|
|
||||||
}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Nom du WiFi
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={formData.wifiName}
|
|
||||||
onChange={(e) =>
|
|
||||||
setFormData({ ...formData, wifiName: e.target.value })
|
|
||||||
}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Mot de passe WiFi
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={formData.wifiPassword}
|
|
||||||
onChange={(e) =>
|
|
||||||
setFormData({ ...formData, wifiPassword: e.target.value })
|
|
||||||
}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
||||||
Message du gérant
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
value={formData.gerantMessage}
|
|
||||||
onChange={(e) =>
|
|
||||||
setFormData({ ...formData, gerantMessage: e.target.value })
|
|
||||||
}
|
|
||||||
rows={3}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-primary focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error && (
|
|
||||||
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-xl text-sm">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex gap-3">
|
|
||||||
<Button type="button" variant="outline" onClick={onCancel} className="flex-1">
|
|
||||||
Annuler
|
|
||||||
</Button>
|
|
||||||
<Button type="submit" disabled={loading} className="flex-1">
|
|
||||||
{loading ? "Enregistrement..." : client ? "Modifier" : "Créer"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{createdClient && !client && (
|
|
||||||
<div className="mt-6 pt-6 border-t border-gray-200">
|
|
||||||
<h3 className="font-semibold text-primary mb-3">Client créé avec succès !</h3>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium text-gray-700 mb-2">Lien unique :</p>
|
|
||||||
<div className="bg-secondary rounded-xl p-4 space-y-3">
|
|
||||||
<textarea
|
|
||||||
readOnly
|
|
||||||
value={getClientUrl()}
|
|
||||||
onClick={(e) => e.currentTarget.select()}
|
|
||||||
onFocus={(e) => e.currentTarget.select()}
|
|
||||||
className="w-full p-3 text-sm font-mono text-primary bg-white border-2 border-primary rounded-lg resize-none"
|
|
||||||
rows={3}
|
|
||||||
style={{ cursor: 'text' }}
|
|
||||||
/>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
onClick={handleCopyLink}
|
|
||||||
className={`flex-1 ${copied ? "bg-green-600 hover:bg-green-700" : ""}`}
|
|
||||||
>
|
|
||||||
{copied ? (
|
|
||||||
<>
|
|
||||||
<Check className="h-4 w-4 mr-2" />
|
|
||||||
Copié !
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Copy className="h-4 w-4 mr-2" />
|
|
||||||
Copier
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => {
|
|
||||||
const textarea = document.querySelector('textarea[readonly]') as HTMLTextAreaElement;
|
|
||||||
if (textarea) {
|
|
||||||
textarea.select();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="flex-1"
|
|
||||||
>
|
|
||||||
Sélectionner
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-gray-500 mt-2">
|
|
||||||
💡 Cliquez sur le lien pour le sélectionner, puis Ctrl+C pour copier
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-sm text-gray-600 mb-2">QR Code :</p>
|
|
||||||
<QRCodeDisplay url={getClientUrl()} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,165 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
|
||||||
import { Trash2, Edit, Copy, QrCode } from "lucide-react";
|
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Client } from "@/lib/types/client";
|
|
||||||
import QRCodeDisplay from "./QRCodeDisplay";
|
|
||||||
|
|
||||||
interface ClientListProps {
|
|
||||||
onEdit: (client: Client) => void;
|
|
||||||
onRefresh: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ClientList({ onEdit, onRefresh }: ClientListProps) {
|
|
||||||
const [clients, setClients] = useState<Client[]>([]);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [selectedClient, setSelectedClient] = useState<Client | null>(null);
|
|
||||||
const [showQR, setShowQR] = useState<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchClients();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const fetchClients = async () => {
|
|
||||||
try {
|
|
||||||
const adminPassword = localStorage.getItem("adminPassword") || "";
|
|
||||||
const response = await fetch("/api/admin/clients", {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${adminPassword}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
const data = await response.json();
|
|
||||||
setClients(data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur lors du chargement des clients:", error);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDelete = async (id: string) => {
|
|
||||||
if (!confirm("Êtes-vous sûr de vouloir supprimer ce client ?")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const adminPassword = localStorage.getItem("adminPassword") || "";
|
|
||||||
const response = await fetch(`/api/admin/clients/${id}`, {
|
|
||||||
method: "DELETE",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${adminPassword}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
fetchClients();
|
|
||||||
onRefresh();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur lors de la suppression:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getClientUrl = (token: string) => {
|
|
||||||
const baseUrl = typeof window !== "undefined" ? window.location.origin : "";
|
|
||||||
return `${baseUrl}/accueil?token=${token}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-center py-8">
|
|
||||||
<p className="text-gray-600">Chargement...</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clients.length === 0) {
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardContent className="py-8 text-center">
|
|
||||||
<p className="text-gray-600">Aucun client pour le moment.</p>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
{clients.map((client) => (
|
|
||||||
<Card key={client.id}>
|
|
||||||
<CardHeader>
|
|
||||||
<div className="flex items-start justify-between">
|
|
||||||
<div className="flex-1">
|
|
||||||
<CardTitle className="text-lg">{client.email}</CardTitle>
|
|
||||||
<p className="text-sm text-gray-600 mt-1">
|
|
||||||
Bungalow {client.bungalowNumber}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => {
|
|
||||||
const url = getClientUrl(client.token);
|
|
||||||
navigator.clipboard.writeText(url);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Copy className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() =>
|
|
||||||
setShowQR(showQR === client.id ? null : client.id)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<QrCode className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => onEdit(client)}
|
|
||||||
>
|
|
||||||
<Edit className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => handleDelete(client.id)}
|
|
||||||
>
|
|
||||||
<Trash2 className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-2 text-sm">
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">WiFi:</span> {client.wifiName}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="font-medium">Message:</span>{" "}
|
|
||||||
{client.gerantMessage.substring(0, 50)}
|
|
||||||
{client.gerantMessage.length > 50 ? "..." : ""}
|
|
||||||
</div>
|
|
||||||
<div className="text-xs text-gray-500">
|
|
||||||
Créé le {new Date(client.createdAt).toLocaleDateString("fr-FR")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{showQR === client.id && (
|
|
||||||
<div className="mt-4 pt-4 border-t border-gray-200">
|
|
||||||
<QRCodeDisplay url={getClientUrl(client.token)} size={150} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import { QRCodeSVG } from "qrcode.react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Copy, Check } from "lucide-react";
|
|
||||||
|
|
||||||
interface QRCodeDisplayProps {
|
|
||||||
url: string;
|
|
||||||
size?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function QRCodeDisplay({ url, size = 200 }: QRCodeDisplayProps) {
|
|
||||||
const [copied, setCopied] = useState(false);
|
|
||||||
|
|
||||||
const handleCopyLink = async () => {
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.writeText(url);
|
|
||||||
setCopied(true);
|
|
||||||
alert(`✅ Lien copié !\n\n${url}\n\nVous pouvez maintenant le coller (Ctrl+V) pour le partager avec votre client.`);
|
|
||||||
setTimeout(() => setCopied(false), 3000);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Erreur lors de la copie:", err);
|
|
||||||
const textArea = document.createElement("textarea");
|
|
||||||
textArea.value = url;
|
|
||||||
textArea.style.position = "fixed";
|
|
||||||
textArea.style.left = "-999999px";
|
|
||||||
document.body.appendChild(textArea);
|
|
||||||
textArea.select();
|
|
||||||
try {
|
|
||||||
const successful = document.execCommand("copy");
|
|
||||||
if (successful) {
|
|
||||||
setCopied(true);
|
|
||||||
alert(`✅ Lien copié !\n\n${url}\n\nVous pouvez maintenant le coller (Ctrl+V) pour le partager avec votre client.`);
|
|
||||||
setTimeout(() => setCopied(false), 3000);
|
|
||||||
} else {
|
|
||||||
alert(`Copiez ce lien manuellement:\n\n${url}`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
alert(`Copiez ce lien manuellement:\n\n${url}`);
|
|
||||||
}
|
|
||||||
document.body.removeChild(textArea);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center gap-4 p-6 bg-white rounded-2xl border border-gray-200">
|
|
||||||
<QRCodeSVG value={url} size={size} level="H" />
|
|
||||||
|
|
||||||
<div className="w-full space-y-3">
|
|
||||||
<p className="text-sm font-medium text-gray-700">Lien unique :</p>
|
|
||||||
<textarea
|
|
||||||
readOnly
|
|
||||||
value={url}
|
|
||||||
onClick={(e) => e.currentTarget.select()}
|
|
||||||
onFocus={(e) => e.currentTarget.select()}
|
|
||||||
className="w-full p-3 text-sm font-mono text-primary bg-secondary border-2 border-primary rounded-lg resize-none"
|
|
||||||
rows={3}
|
|
||||||
style={{ cursor: 'text' }}
|
|
||||||
/>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
onClick={handleCopyLink}
|
|
||||||
className={`flex-1 ${copied ? "bg-green-600 hover:bg-green-700" : ""}`}
|
|
||||||
>
|
|
||||||
{copied ? (
|
|
||||||
<>
|
|
||||||
<Check className="h-4 w-4 mr-2" />
|
|
||||||
Copié !
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Copy className="h-4 w-4 mr-2" />
|
|
||||||
Copier
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => {
|
|
||||||
const textarea = document.querySelector('textarea[readonly]') as HTMLTextAreaElement;
|
|
||||||
if (textarea) {
|
|
||||||
textarea.select();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="flex-1"
|
|
||||||
>
|
|
||||||
Sélectionner
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-gray-500 text-center">
|
|
||||||
💡 Cliquez sur le lien pour le sélectionner, puis Ctrl+C pour copier
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
import { MapPin, ExternalLink } from "lucide-react";
|
import { MapPin, ExternalLink } from "lucide-react";
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@ -10,6 +11,9 @@ interface PlaceCardProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PlaceCard({ place }: PlaceCardProps) {
|
export default function PlaceCard({ place }: PlaceCardProps) {
|
||||||
|
const [imageError, setImageError] = useState(false);
|
||||||
|
const hasValidImage = place.image && place.image !== "";
|
||||||
|
|
||||||
const handleOpenMaps = () => {
|
const handleOpenMaps = () => {
|
||||||
let url: string;
|
let url: string;
|
||||||
if (place.gmapLink && place.gmapLink !== "LIEN_GOOGLE_MAPS_A_INSERER") {
|
if (place.gmapLink && place.gmapLink !== "LIEN_GOOGLE_MAPS_A_INSERER") {
|
||||||
@ -22,10 +26,24 @@ export default function PlaceCard({ place }: PlaceCardProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="overflow-hidden">
|
<Card className="overflow-hidden">
|
||||||
<div className="relative h-48 bg-gradient-to-br from-primary/20 to-secondary">
|
<div className="relative h-48 bg-gradient-to-br from-primary/20 to-secondary overflow-hidden">
|
||||||
|
{hasValidImage && !imageError ? (
|
||||||
|
<img
|
||||||
|
src={place.image}
|
||||||
|
alt={place.name}
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
style={{
|
||||||
|
imageRendering: 'auto',
|
||||||
|
} as React.CSSProperties}
|
||||||
|
loading="lazy"
|
||||||
|
fetchPriority="high"
|
||||||
|
onError={() => setImageError(true)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<div className="absolute inset-0 flex items-center justify-center">
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
<MapPin className="h-16 w-16 text-primary/30" />
|
<MapPin className="h-16 w-16 text-primary/30" />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import TabNavigation from "./TabNavigation";
|
|||||||
|
|
||||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background pb-16">
|
<div className="min-h-screen bg-background dark:bg-background-dark pb-16">
|
||||||
{children}
|
{children}
|
||||||
<TabNavigation />
|
<TabNavigation />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import Link from "next/link";
|
|||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { Home, MapPin, Info, Waves } from "lucide-react";
|
import { Home, MapPin, Info, Waves } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { ThemeToggle } from "@/components/ThemeToggle";
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ export default function TabNavigation() {
|
|||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-white border-t border-gray-200 shadow-lg">
|
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800 shadow-lg">
|
||||||
<div className="flex items-center justify-around h-16 px-2">
|
<div className="flex items-center justify-around h-16 px-2">
|
||||||
{tabs.map((tab) => {
|
{tabs.map((tab) => {
|
||||||
const Icon = tab.icon;
|
const Icon = tab.icon;
|
||||||
@ -44,8 +45,8 @@ export default function TabNavigation() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col items-center justify-center gap-1 flex-1 h-full rounded-xl transition-colors",
|
"flex flex-col items-center justify-center gap-1 flex-1 h-full rounded-xl transition-colors",
|
||||||
isActive
|
isActive
|
||||||
? "text-primary bg-secondary"
|
? "text-primary bg-secondary dark:bg-primary/20"
|
||||||
: "text-gray-500 hover:text-primary hover:bg-gray-50"
|
: "text-gray-500 dark:text-gray-400 hover:text-primary dark:hover:text-primary hover:bg-gray-50 dark:hover:bg-gray-800"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Icon className="h-6 w-6" />
|
<Icon className="h-6 w-6" />
|
||||||
@ -53,6 +54,9 @@ export default function TabNavigation() {
|
|||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
<div className="flex items-center justify-center h-full px-2">
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,10 +7,10 @@ const buttonVariants = cva(
|
|||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
default: "bg-primary text-primary-foreground hover:bg-primary/90 dark:bg-primary dark:hover:bg-primary/80",
|
||||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 dark:bg-primary/20 dark:text-primary dark:hover:bg-primary/30",
|
||||||
outline: "border-2 border-primary text-primary hover:bg-primary hover:text-white",
|
outline: "border-2 border-primary text-primary hover:bg-primary hover:text-white dark:border-primary dark:text-primary dark:hover:bg-primary dark:hover:text-white",
|
||||||
ghost: "hover:bg-secondary hover:text-secondary-foreground",
|
ghost: "hover:bg-secondary hover:text-secondary-foreground dark:hover:bg-gray-800 dark:hover:text-gray-200",
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-12 px-6 py-3",
|
default: "h-12 px-6 py-3",
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const Card = React.forwardRef<
|
|||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-2xl border border-gray-200 bg-white shadow-sm",
|
"rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@ -46,7 +46,7 @@ const CardDescription = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<p
|
<p
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn("text-sm text-gray-600", className)}
|
className={cn("text-sm text-gray-600 dark:text-gray-400", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|||||||
5
deploy/.env.example
Normal file
5
deploy/.env.example
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Mot de passe admin
|
||||||
|
ADMIN_PASSWORD=votre_mot_de_passe_securise
|
||||||
|
|
||||||
|
# Port (optionnel, par défaut 3000)
|
||||||
|
PORT=3000
|
||||||
1
deploy/.next/BUILD_ID
Normal file
1
deploy/.next/BUILD_ID
Normal file
@ -0,0 +1 @@
|
|||||||
|
3c87ZLiEKCTo7fN65B1s7
|
||||||
88
deploy/.next/app-build-manifest.json
Normal file
88
deploy/.next/app-build-manifest.json
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"pages": {
|
||||||
|
"/_not-found/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/app/_not-found/page-93c891698b4decca.js"
|
||||||
|
],
|
||||||
|
"/layout": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/css/37740839d02c8860.css",
|
||||||
|
"static/chunks/app/layout-012feff5f2309838.js"
|
||||||
|
],
|
||||||
|
"/accueil/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/130-fbdba5ec657d70e2.js",
|
||||||
|
"static/chunks/876-74e3127f7295a7cc.js",
|
||||||
|
"static/chunks/app/accueil/page-eeceff806dc9e963.js"
|
||||||
|
],
|
||||||
|
"/admin/login/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/130-fbdba5ec657d70e2.js",
|
||||||
|
"static/chunks/app/admin/login/page-64d4a547eaf512e7.js"
|
||||||
|
],
|
||||||
|
"/admin/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/130-fbdba5ec657d70e2.js",
|
||||||
|
"static/chunks/659-547b5910f7777d12.js",
|
||||||
|
"static/chunks/app/admin/page-be00d3b5e7fb599b.js"
|
||||||
|
],
|
||||||
|
"/explorer/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/130-fbdba5ec657d70e2.js",
|
||||||
|
"static/chunks/876-74e3127f7295a7cc.js",
|
||||||
|
"static/chunks/app/explorer/page-94fbb37299b728f0.js"
|
||||||
|
],
|
||||||
|
"/infos/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/130-fbdba5ec657d70e2.js",
|
||||||
|
"static/chunks/876-74e3127f7295a7cc.js",
|
||||||
|
"static/chunks/app/infos/page-9c23965cb3e698cb.js"
|
||||||
|
],
|
||||||
|
"/mana-tracker/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/130-fbdba5ec657d70e2.js",
|
||||||
|
"static/chunks/876-74e3127f7295a7cc.js",
|
||||||
|
"static/chunks/app/mana-tracker/page-190454f13d1cd3f9.js"
|
||||||
|
],
|
||||||
|
"/offline/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/130-fbdba5ec657d70e2.js",
|
||||||
|
"static/chunks/876-74e3127f7295a7cc.js",
|
||||||
|
"static/chunks/app/offline/page-c706c75d3862967d.js"
|
||||||
|
],
|
||||||
|
"/page": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js",
|
||||||
|
"static/chunks/app/page-66582cb216c486f4.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
1
deploy/.next/app-path-routes-manifest.json
Normal file
1
deploy/.next/app-path-routes-manifest.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"/_not-found/page":"/_not-found","/accueil/page":"/accueil","/admin/login/page":"/admin/login","/admin/page":"/admin","/api/admin/clients/route":"/api/admin/clients","/explorer/page":"/explorer","/infos/page":"/infos","/mana-tracker/page":"/mana-tracker","/offline/page":"/offline","/page":"/"}
|
||||||
32
deploy/.next/build-manifest.json
Normal file
32
deploy/.next/build-manifest.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"polyfillFiles": [
|
||||||
|
"static/chunks/polyfills-42372ed130431b0a.js"
|
||||||
|
],
|
||||||
|
"devFiles": [],
|
||||||
|
"ampDevFiles": [],
|
||||||
|
"lowPriorityFiles": [
|
||||||
|
"static/3c87ZLiEKCTo7fN65B1s7/_buildManifest.js",
|
||||||
|
"static/3c87ZLiEKCTo7fN65B1s7/_ssgManifest.js"
|
||||||
|
],
|
||||||
|
"rootMainFiles": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/fd9d1056-f29a34e8cb4f1ac5.js",
|
||||||
|
"static/chunks/117-81b684a50b4e5a2c.js",
|
||||||
|
"static/chunks/main-app-be78d15d42f0ba33.js"
|
||||||
|
],
|
||||||
|
"pages": {
|
||||||
|
"/_app": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/framework-f66176bb897dc684.js",
|
||||||
|
"static/chunks/main-98da237dfd0126ae.js",
|
||||||
|
"static/chunks/pages/_app-72b849fbd24ac258.js"
|
||||||
|
],
|
||||||
|
"/_error": [
|
||||||
|
"static/chunks/webpack-272d92e0b8f870de.js",
|
||||||
|
"static/chunks/framework-f66176bb897dc684.js",
|
||||||
|
"static/chunks/main-98da237dfd0126ae.js",
|
||||||
|
"static/chunks/pages/_error-7ba65e1336b92748.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ampFirstPages": []
|
||||||
|
}
|
||||||
1
deploy/.next/cache/eslint/.cache_afsi2w
vendored
Normal file
1
deploy/.next/cache/eslint/.cache_afsi2w
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
deploy/.next/cache/webpack/client-development/0.pack.gz
vendored
Normal file
BIN
deploy/.next/cache/webpack/client-development/0.pack.gz
vendored
Normal file
Binary file not shown.
BIN
deploy/.next/cache/webpack/client-development/index.pack.gz
vendored
Normal file
BIN
deploy/.next/cache/webpack/client-development/index.pack.gz
vendored
Normal file
Binary file not shown.
BIN
deploy/.next/cache/webpack/client-production/0.pack
vendored
Normal file
BIN
deploy/.next/cache/webpack/client-production/0.pack
vendored
Normal file
Binary file not shown.
BIN
deploy/.next/cache/webpack/client-production/index.pack
vendored
Normal file
BIN
deploy/.next/cache/webpack/client-production/index.pack
vendored
Normal file
Binary file not shown.
BIN
deploy/.next/cache/webpack/edge-server-production/0.pack
vendored
Normal file
BIN
deploy/.next/cache/webpack/edge-server-production/0.pack
vendored
Normal file
Binary file not shown.
BIN
deploy/.next/cache/webpack/edge-server-production/index.pack
vendored
Normal file
BIN
deploy/.next/cache/webpack/edge-server-production/index.pack
vendored
Normal file
Binary file not shown.
BIN
deploy/.next/cache/webpack/server-production/0.pack
vendored
Normal file
BIN
deploy/.next/cache/webpack/server-production/0.pack
vendored
Normal file
Binary file not shown.
BIN
deploy/.next/cache/webpack/server-production/index.pack
vendored
Normal file
BIN
deploy/.next/cache/webpack/server-production/index.pack
vendored
Normal file
Binary file not shown.
1
deploy/.next/export-marker.json
Normal file
1
deploy/.next/export-marker.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"hasExportPathMap":false,"exportTrailingSlash":false,"isNextImageImported":false}
|
||||||
1
deploy/.next/images-manifest.json
Normal file
1
deploy/.next/images-manifest.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[16,32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":60,"formats":["image/avif","image/webp"],"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"inline","remotePatterns":[],"unoptimized":false,"sizes":[640,750,828,1080,1200,1920,2048,3840,16,32,48,64,96,128,256,384]}}
|
||||||
1
deploy/.next/next-minimal-server.js.nft.json
Normal file
1
deploy/.next/next-minimal-server.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../node_modules/styled-jsx/index.js","../node_modules/styled-jsx/package.json","../node_modules/styled-jsx/dist/index/index.js","../node_modules/react/package.json","../node_modules/react/index.js","../node_modules/client-only/package.json","../node_modules/react/cjs/react.production.min.js","../node_modules/client-only/index.js","../node_modules/styled-jsx/style.js","../node_modules/next/dist/compiled/next-server/server.runtime.prod.js","../node_modules/next/package.json","../node_modules/next/dist/server/body-streams.js","../node_modules/next/dist/lib/constants.js","../node_modules/next/dist/lib/picocolors.js","../node_modules/next/dist/shared/lib/constants.js","../node_modules/next/dist/server/web/utils.js","../node_modules/next/dist/client/components/app-router-headers.js","../node_modules/next/dist/server/lib/trace/tracer.js","../node_modules/next/dist/server/lib/trace/constants.js","../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../node_modules/next/dist/shared/lib/modern-browserslist-target.js","../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../node_modules/next/dist/shared/lib/runtime-config.external.js","../node_modules/next/dist/compiled/ws/package.json","../node_modules/next/dist/compiled/node-html-parser/package.json","../node_modules/next/dist/compiled/lru-cache/package.json","../node_modules/@swc/helpers/_/_interop_require_default/package.json","../node_modules/next/dist/client/components/async-local-storage.js","../node_modules/next/dist/compiled/ws/index.js","../node_modules/next/dist/compiled/node-html-parser/index.js","../node_modules/next/dist/compiled/lru-cache/index.js","../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../node_modules/@swc/helpers/package.json","../node_modules/next/dist/compiled/jsonwebtoken/package.json","../node_modules/next/dist/shared/lib/error-source.js","../node_modules/@swc/helpers/cjs/_interop_require_default.cjs","../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../node_modules/next/dist/compiled/jsonwebtoken/index.js","../node_modules/next/dist/compiled/debug/package.json","../node_modules/next/dist/lib/semver-noop.js","../node_modules/next/dist/compiled/debug/index.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/amp-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/app-router-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/entrypoints.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/head-manager-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/hooks-client-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/html-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/image-config-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/loadable-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/loadable.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/router-context.js","../node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/server-inserted-html.js","../node_modules/next/dist/server/future/route-modules/app-page/module.compiled.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/amp-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/app-router-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/entrypoints.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/head-manager-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/hooks-client-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/html-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/image-config-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/loadable-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/loadable.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/router-context.js","../node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/server-inserted-html.js","../node_modules/next/dist/server/future/route-modules/pages/module.compiled.js"]}
|
||||||
1
deploy/.next/next-server.js.nft.json
Normal file
1
deploy/.next/next-server.js.nft.json
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/package.json
Normal file
1
deploy/.next/package.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"type": "commonjs"}
|
||||||
1
deploy/.next/prerender-manifest.json
Normal file
1
deploy/.next/prerender-manifest.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":4,"routes":{"/infos":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/infos","dataRoute":"/infos.rsc"},"/mana-tracker":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/mana-tracker","dataRoute":"/mana-tracker.rsc"},"/offline":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/offline","dataRoute":"/offline.rsc"},"/":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/","dataRoute":"/index.rsc"},"/accueil":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/accueil","dataRoute":"/accueil.rsc"},"/admin":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/admin","dataRoute":"/admin.rsc"},"/explorer":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/explorer","dataRoute":"/explorer.rsc"},"/admin/login":{"experimentalBypassFor":[{"type":"header","key":"Next-Action"},{"type":"header","key":"content-type","value":"multipart/form-data;.*"}],"initialRevalidateSeconds":false,"srcRoute":"/admin/login","dataRoute":"/admin/login.rsc"}},"dynamicRoutes":{},"notFoundRoutes":[],"preview":{"previewModeId":"72798059332883bb836619ead11f265d","previewModeSigningKey":"c91fe6a8fb8a6afd08166f7488f47956827aa8492d588a1be69527dd7453feda","previewModeEncryptionKey":"b90ebc3c46fd8e2c88f96f242898610916379d8d4dc5cc0f98f6d0bb8b887095"}}
|
||||||
14
deploy/.next/react-loadable-manifest.json
Normal file
14
deploy/.next/react-loadable-manifest.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"app/accueil/page.tsx -> @/components/accueil/WeatherWidget": {
|
||||||
|
"id": 5147,
|
||||||
|
"files": [
|
||||||
|
"static/chunks/147.f0c63fadc263cdbf.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app/explorer/page.tsx -> @/components/explorer/PlaceList": {
|
||||||
|
"id": 3293,
|
||||||
|
"files": [
|
||||||
|
"static/chunks/80.c30ab4050c6d10af.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
1
deploy/.next/required-server-files.json
Normal file
1
deploy/.next/required-server-files.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"config":{"env":{},"webpack":null,"eslint":{"ignoreDuringBuilds":false},"typescript":{"ignoreBuildErrors":false,"tsconfigPath":"tsconfig.json"},"distDir":".next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.js","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":false,"compress":true,"analyticsId":"","images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[16,32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":60,"formats":["image/avif","image/webp"],"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"inline","remotePatterns":[],"unoptimized":false},"devIndicators":{"buildActivity":true,"buildActivityPosition":"bottom-right"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"amp":{"canonicalBase":""},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"optimizeFonts":true,"excludeDefaultMomentLocales":true,"serverRuntimeConfig":{},"publicRuntimeConfig":{},"reactProductionProfiling":false,"reactStrictMode":true,"httpAgentOptions":{"keepAlive":true},"outputFileTracing":true,"staticPageGenerationTimeout":60,"swcMinify":true,"modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"experimental":{"multiZoneDraftMode":false,"prerenderEarlyExit":false,"serverMinification":true,"serverSourceMaps":false,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","middlewarePrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":7,"memoryBasedWorkersCount":false,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"outputFileTracingRoot":"/home/syoul/Ccompagnon Marama","swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"adjustFontFallbacks":false,"adjustFontFallbacksWithSizeAdjust":false,"typedRoutes":false,"instrumentationHook":false,"bundlePagesExternals":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"missingSuspenseWithCSRBailout":true,"optimizeServerReact":true,"useEarlyImport":false,"staleTimes":{"dynamic":30,"static":300},"optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"configFileName":"next.config.js"},"appDir":"/home/syoul/Ccompagnon Marama","relativeAppDir":"","files":[".next/routes-manifest.json",".next/server/pages-manifest.json",".next/build-manifest.json",".next/prerender-manifest.json",".next/server/middleware-manifest.json",".next/server/middleware-build-manifest.js",".next/server/middleware-react-loadable-manifest.js",".next/server/app-paths-manifest.json",".next/app-path-routes-manifest.json",".next/app-build-manifest.json",".next/server/server-reference-manifest.js",".next/server/server-reference-manifest.json",".next/react-loadable-manifest.json",".next/server/font-manifest.json",".next/BUILD_ID",".next/server/next-font-manifest.js",".next/server/next-font-manifest.json"],"ignore":["node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*"]}
|
||||||
12
deploy/.next/server/app-paths-manifest.json
Normal file
12
deploy/.next/server/app-paths-manifest.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"/_not-found/page": "app/_not-found/page.js",
|
||||||
|
"/accueil/page": "app/accueil/page.js",
|
||||||
|
"/admin/login/page": "app/admin/login/page.js",
|
||||||
|
"/admin/page": "app/admin/page.js",
|
||||||
|
"/api/admin/clients/route": "app/api/admin/clients/route.js",
|
||||||
|
"/explorer/page": "app/explorer/page.js",
|
||||||
|
"/infos/page": "app/infos/page.js",
|
||||||
|
"/mana-tracker/page": "app/mana-tracker/page.js",
|
||||||
|
"/offline/page": "app/offline/page.js",
|
||||||
|
"/page": "app/page.js"
|
||||||
|
}
|
||||||
1
deploy/.next/server/app/_not-found.html
Normal file
1
deploy/.next/server/app/_not-found.html
Normal file
File diff suppressed because one or more lines are too long
6
deploy/.next/server/app/_not-found.meta
Normal file
6
deploy/.next/server/app/_not-found.meta
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"status": 404,
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/_not-found/layout,_N_T_/_not-found/page,_N_T_/_not-found"
|
||||||
|
}
|
||||||
|
}
|
||||||
11
deploy/.next/server/app/_not-found.rsc
Normal file
11
deploy/.next/server/app/_not-found.rsc
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
2:I[4707,[],""]
|
||||||
|
3:I[6423,[],""]
|
||||||
|
4:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
9:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
5:{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"}
|
||||||
|
6:{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"}
|
||||||
|
7:{"display":"inline-block"}
|
||||||
|
8:{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0}
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["/_not-found",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["/_not-found",{"children":["__PAGE__",{},[["$L1",[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],null],null],null]},[null,["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children","/_not-found","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$L4",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L2",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":"$5","children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":"$6","children":"404"}],["$","div",null,{"style":"$7","children":["$","h2",null,{"style":"$8","children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$L9",null,{}]]}]}]]}]],null],null],["$La",["$","meta",null,{"name":"robots","content":"noindex"}]]]]]
|
||||||
|
a:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/_not-found/page.js
Normal file
1
deploy/.next/server/app/_not-found/page.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
(()=>{var e={};e.id=409,e.ids=[409],e.modules={2934:e=>{"use strict";e.exports=require("next/dist/client/components/action-async-storage.external.js")},4580:e=>{"use strict";e.exports=require("next/dist/client/components/request-async-storage.external.js")},5869:e=>{"use strict";e.exports=require("next/dist/client/components/static-generation-async-storage.external.js")},399:e=>{"use strict";e.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},4390:(e,t,n)=>{"use strict";n.r(t),n.d(t,{GlobalError:()=>i.a,__next_app__:()=>p,originalPathname:()=>c,pages:()=>d,routeModule:()=>f,tree:()=>u}),n(7352),n(5866),n(5481);var r=n(3191),o=n(8716),a=n(7922),i=n.n(a),s=n(5231),l={};for(let e in s)0>["default","tree","pages","GlobalError","originalPathname","__next_app__","routeModule"].indexOf(e)&&(l[e]=()=>s[e]);n.d(t,l);let u=["",{children:["/_not-found",{children:["__PAGE__",{},{page:[()=>Promise.resolve().then(n.t.bind(n,5866,23)),"next/dist/client/components/not-found-error"]}]},{}]},{layout:[()=>Promise.resolve().then(n.bind(n,5481)),"/home/syoul/Ccompagnon Marama/app/layout.tsx"],"not-found":[()=>Promise.resolve().then(n.t.bind(n,5866,23)),"next/dist/client/components/not-found-error"]}],d=[],c="/_not-found/page",p={require:n,loadChunk:()=>Promise.resolve()},f=new r.AppPageRouteModule({definition:{kind:o.x.APP_PAGE,page:"/_not-found/page",pathname:"/_not-found",bundlePath:"",filename:"",appPaths:[]},userland:{loaderTree:u}})},7274:(e,t,n)=>{Promise.resolve().then(n.bind(n,7904)),Promise.resolve().then(n.bind(n,7459))},9401:(e,t,n)=>{Promise.resolve().then(n.t.bind(n,2994,23)),Promise.resolve().then(n.t.bind(n,6114,23)),Promise.resolve().then(n.t.bind(n,9727,23)),Promise.resolve().then(n.t.bind(n,9671,23)),Promise.resolve().then(n.t.bind(n,1868,23)),Promise.resolve().then(n.t.bind(n,4759,23))},7904:(e,t,n)=>{"use strict";function r(){return null}n.d(t,{default:()=>r}),n(7577)},7459:(e,t,n)=>{"use strict";n.d(t,{ThemeProvider:()=>a});var r=n(326),o=n(4831);function a({children:e,...t}){return r.jsx(o.f,{...t,children:e})}},5481:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>d,metadata:()=>u});var r=n(9510),o=n(5384),a=n.n(o);n(7272);var i=n(8570);let s=(0,i.createProxy)(String.raw`/home/syoul/Ccompagnon Marama/components/PWARegister.tsx#default`),l=(0,i.createProxy)(String.raw`/home/syoul/Ccompagnon Marama/components/ThemeProvider.tsx#ThemeProvider`),u={title:"Compagnon du lagon - Pension Marama",description:"Votre guide num\xe9rique pour votre s\xe9jour \xe0 Fakarava",manifest:"/manifest.json",themeColor:"#0E7490",appleWebApp:{capable:!0,statusBarStyle:"default",title:"Compagnon du lagon - Pension Marama"},viewport:{width:"device-width",initialScale:1,maximumScale:1,userScalable:!1}};function d({children:e}){return(0,r.jsxs)("html",{lang:"fr",suppressHydrationWarning:!0,children:[(0,r.jsxs)("head",{children:[r.jsx("link",{rel:"icon",href:"/logo-relais-marama.svg",type:"image/svg+xml"}),r.jsx("link",{rel:"apple-touch-icon",href:"/logo-relais-marama.svg"})]}),r.jsx("body",{className:a().className,children:(0,r.jsxs)(l,{attribute:"class",defaultTheme:"light",enableSystem:!0,disableTransitionOnChange:!1,children:[e,r.jsx(s,{})]})})]})}},6399:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{isNotFoundError:function(){return o},notFound:function(){return r}});let n="NEXT_NOT_FOUND";function r(){let e=Error(n);throw e.digest=n,e}function o(e){return"object"==typeof e&&null!==e&&"digest"in e&&e.digest===n}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},7352:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,t){for(var n in t)Object.defineProperty(e,n,{enumerable:!0,get:t[n]})}(t,{PARALLEL_ROUTE_DEFAULT_PATH:function(){return o},default:function(){return a}});let r=n(6399),o="next/dist/client/components/parallel-route-default.js";function a(){(0,r.notFound)()}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},7272:()=>{}};var t=require("../../webpack-runtime.js");t.C(e);var n=e=>t(t.s=e),r=t.X(0,[276,740],()=>n(4390));module.exports=r})();
|
||||||
1
deploy/.next/server/app/_not-found/page.js.nft.json
Normal file
1
deploy/.next/server/app/_not-found/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../package.json","../../chunks/276.js","../../chunks/740.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/accueil.html
Normal file
1
deploy/.next/server/app/accueil.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/accueil.meta
Normal file
5
deploy/.next/server/app/accueil.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/accueil/layout,_N_T_/accueil/page,_N_T_/accueil"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
deploy/.next/server/app/accueil.rsc
Normal file
9
deploy/.next/server/app/accueil.rsc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
2:I[9107,[],"ClientPageRoot"]
|
||||||
|
3:I[8666,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","206","static/chunks/app/accueil/page-eeceff806dc9e963.js"],"default",1]
|
||||||
|
4:I[4707,[],""]
|
||||||
|
5:I[6423,[],""]
|
||||||
|
6:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
7:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["accueil",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["accueil",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","accueil","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$L6",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$L7",null,{}]]}]}]]}]],null],null],["$L8",null]]]]
|
||||||
|
8:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/accueil/page.js
Normal file
1
deploy/.next/server/app/accueil/page.js
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/accueil/page.js.nft.json
Normal file
1
deploy/.next/server/app/accueil/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/276.js","../../chunks/341.js","../../chunks/740.js","../../chunks/87.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/admin.html
Normal file
1
deploy/.next/server/app/admin.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/admin.meta
Normal file
5
deploy/.next/server/app/admin.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/admin/layout,_N_T_/admin/page,_N_T_/admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
deploy/.next/server/app/admin.rsc
Normal file
9
deploy/.next/server/app/admin.rsc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
2:I[9107,[],"ClientPageRoot"]
|
||||||
|
3:I[5176,["130","static/chunks/130-fbdba5ec657d70e2.js","659","static/chunks/659-547b5910f7777d12.js","3","static/chunks/app/admin/page-be00d3b5e7fb599b.js"],"default",1]
|
||||||
|
4:I[4707,[],""]
|
||||||
|
5:I[6423,[],""]
|
||||||
|
6:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
7:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["admin",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["admin",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","admin","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$L6",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$L7",null,{}]]}]}]]}]],null],null],["$L8",null]]]]
|
||||||
|
8:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/admin/login.html
Normal file
1
deploy/.next/server/app/admin/login.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/admin/login.meta
Normal file
5
deploy/.next/server/app/admin/login.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/admin/layout,_N_T_/admin/login/layout,_N_T_/admin/login/page,_N_T_/admin/login"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
deploy/.next/server/app/admin/login.rsc
Normal file
9
deploy/.next/server/app/admin/login.rsc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
2:I[9107,[],"ClientPageRoot"]
|
||||||
|
3:I[4507,["130","static/chunks/130-fbdba5ec657d70e2.js","920","static/chunks/app/admin/login/page-64d4a547eaf512e7.js"],"default",1]
|
||||||
|
4:I[4707,[],""]
|
||||||
|
5:I[6423,[],""]
|
||||||
|
6:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
7:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["admin",{"children":["login",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",{"children":["admin",{"children":["login",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","admin","children","login","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","admin","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$L6",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$L7",null,{}]]}]}]]}]],null],null],["$L8",null]]]]
|
||||||
|
8:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/admin/login/page.js
Normal file
1
deploy/.next/server/app/admin/login/page.js
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/admin/login/page.js.nft.json
Normal file
1
deploy/.next/server/app/admin/login/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../../node_modules/next/package.json","../../../../../package.json","../../../../package.json","../../../chunks/276.js","../../../chunks/740.js","../../../chunks/87.js","../../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
29
deploy/.next/server/app/admin/page.js
Normal file
29
deploy/.next/server/app/admin/page.js
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/admin/page.js.nft.json
Normal file
1
deploy/.next/server/app/admin/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/276.js","../../chunks/740.js","../../chunks/87.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
12
deploy/.next/server/app/api/admin/clients/route.js
Normal file
12
deploy/.next/server/app/api/admin/clients/route.js
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../../../data/.gitkeep","../../../../../../data/clients.json","../../../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../../../node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js","../../../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../../../node_modules/next/package.json","../../../../../../package.json","../../../../../package.json","../../../../chunks/276.js","../../../../webpack-runtime.js"]}
|
||||||
1
deploy/.next/server/app/explorer.html
Normal file
1
deploy/.next/server/app/explorer.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/explorer.meta
Normal file
5
deploy/.next/server/app/explorer.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/explorer/layout,_N_T_/explorer/page,_N_T_/explorer"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
deploy/.next/server/app/explorer.rsc
Normal file
9
deploy/.next/server/app/explorer.rsc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
2:I[9107,[],"ClientPageRoot"]
|
||||||
|
3:I[9566,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","743","static/chunks/app/explorer/page-94fbb37299b728f0.js"],"default",1]
|
||||||
|
4:I[4707,[],""]
|
||||||
|
5:I[6423,[],""]
|
||||||
|
6:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
7:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["explorer",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["explorer",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","explorer","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$L6",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$L7",null,{}]]}]}]]}]],null],null],["$L8",null]]]]
|
||||||
|
8:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/explorer/page.js
Normal file
1
deploy/.next/server/app/explorer/page.js
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/explorer/page.js.nft.json
Normal file
1
deploy/.next/server/app/explorer/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/276.js","../../chunks/341.js","../../chunks/740.js","../../chunks/87.js","../../chunks/933.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/index.html
Normal file
1
deploy/.next/server/app/index.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/index.meta
Normal file
5
deploy/.next/server/app/index.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/page,_N_T_/"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
deploy/.next/server/app/index.rsc
Normal file
9
deploy/.next/server/app/index.rsc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
2:I[9107,[],"ClientPageRoot"]
|
||||||
|
3:I[7340,["931","static/chunks/app/page-66582cb216c486f4.js"],"default",1]
|
||||||
|
4:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
5:I[4707,[],""]
|
||||||
|
6:I[6423,[],""]
|
||||||
|
7:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$L4",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$L7",null,{}]]}]}]]}]],null],null],["$L8",null]]]]
|
||||||
|
8:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/infos.html
Normal file
1
deploy/.next/server/app/infos.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/infos.meta
Normal file
5
deploy/.next/server/app/infos.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/infos/layout,_N_T_/infos/page,_N_T_/infos"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
deploy/.next/server/app/infos.rsc
Normal file
15
deploy/.next/server/app/infos.rsc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
2:"$Sreact.suspense"
|
||||||
|
3:I[49,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","767","static/chunks/app/infos/page-9c23965cb3e698cb.js"],"PreloadCss"]
|
||||||
|
6:I[1110,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","767","static/chunks/app/infos/page-9c23965cb3e698cb.js"],"default"]
|
||||||
|
7:I[9673,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","767","static/chunks/app/infos/page-9c23965cb3e698cb.js"],"default"]
|
||||||
|
8:I[4707,[],""]
|
||||||
|
9:I[6423,[],""]
|
||||||
|
a:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
b:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["infos",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["infos",{"children":["__PAGE__",{},[["$L1",["$","div",null,{"className":"min-h-screen bg-background dark:bg-background-dark pb-16","children":[["$","div",null,{"className":"px-4 py-6 space-y-8","children":[["$","header",null,{"children":[["$","h1",null,{"className":"text-2xl font-bold text-primary mb-2","children":"Infos Pratiques"}],["$","p",null,{"className":"text-gray-600","children":"Tout ce que vous devez savoir pour votre séjour"}]]}],["$","section",null,{"children":[["$","h2",null,{"className":"text-xl font-semibold text-primary mb-4","children":"Questions Fréquentes"}],["$","$2",null,{"fallback":["$","div",null,{"className":"h-64 bg-gray-100 rounded-2xl animate-pulse"}],"children":[["$","$L3",null,{"moduleIds":["app/infos/page.tsx -> @/components/infos/FAQAccordion"]}],"$L4"]}]]}],["$","section",null,{"children":["$","$2",null,{"fallback":["$","div",null,{"className":"h-48 bg-gray-100 rounded-2xl animate-pulse"}],"children":[["$","$L3",null,{"moduleIds":["app/infos/page.tsx -> @/components/infos/LexiqueSection"]}],"$L5"]}]}],["$","section",null,{"children":["$","$L6",null,{}]}]]}],["$","$L7",null,{}]]}],null],null],null]},[null,["$","$L8",null,{"parallelRouterKey":"children","segmentPath":["children","infos","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L9",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$La",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L8",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L9",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$Lb",null,{}]]}]}]]}]],null],null],["$Lc",null]]]]
|
||||||
|
d:I[646,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","767","static/chunks/app/infos/page-9c23965cb3e698cb.js"],"default"]
|
||||||
|
e:I[9795,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","767","static/chunks/app/infos/page-9c23965cb3e698cb.js"],"default"]
|
||||||
|
4:["$","$Ld",null,{}]
|
||||||
|
5:["$","$Le",null,{}]
|
||||||
|
c:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/infos/page.js
Normal file
1
deploy/.next/server/app/infos/page.js
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/infos/page.js.nft.json
Normal file
1
deploy/.next/server/app/infos/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../components/infos/FAQAccordion.tsx","../../../../components/infos/LexiqueSection.tsx","../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/174.js","../../chunks/276.js","../../chunks/341.js","../../chunks/698.js","../../chunks/740.js","../../chunks/87.js","../../chunks/99.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/mana-tracker.html
Normal file
1
deploy/.next/server/app/mana-tracker.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/mana-tracker.meta
Normal file
5
deploy/.next/server/app/mana-tracker.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/mana-tracker/layout,_N_T_/mana-tracker/page,_N_T_/mana-tracker"
|
||||||
|
}
|
||||||
|
}
|
||||||
16
deploy/.next/server/app/mana-tracker.rsc
Normal file
16
deploy/.next/server/app/mana-tracker.rsc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
2:I[7849,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","347","static/chunks/app/mana-tracker/page-190454f13d1cd3f9.js"],"default"]
|
||||||
|
3:I[1556,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","347","static/chunks/app/mana-tracker/page-190454f13d1cd3f9.js"],"default"]
|
||||||
|
4:"$Sreact.suspense"
|
||||||
|
5:I[49,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","347","static/chunks/app/mana-tracker/page-190454f13d1cd3f9.js"],"PreloadCss"]
|
||||||
|
8:I[9673,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","347","static/chunks/app/mana-tracker/page-190454f13d1cd3f9.js"],"default"]
|
||||||
|
9:I[4707,[],""]
|
||||||
|
a:I[6423,[],""]
|
||||||
|
b:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
c:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["mana-tracker",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["mana-tracker",{"children":["__PAGE__",{},[["$L1",["$","div",null,{"className":"min-h-screen bg-background dark:bg-background-dark pb-16","children":[["$","div",null,{"className":"px-4 py-6 space-y-6","children":[["$","header",null,{"children":[["$","h1",null,{"className":"text-2xl font-bold text-primary mb-2","children":"Mana Tracker"}],["$","p",null,{"className":"text-gray-600","children":"Activités & Météo - Tout dépend de la mer et du soleil"}]]}],["$","$L2",null,{}],["$","$L3",null,{}],["$","$4",null,{"fallback":["$","div",null,{"className":"h-64 bg-gray-100 rounded-2xl animate-pulse"}],"children":[["$","$L5",null,{"moduleIds":["app/mana-tracker/page.tsx -> @/components/mana-tracker/ExcursionBooking"]}],"$L6"]}],["$","$4",null,{"fallback":["$","div",null,{"className":"h-48 bg-gray-100 rounded-2xl animate-pulse"}],"children":[["$","$L5",null,{"moduleIds":["app/mana-tracker/page.tsx -> @/components/mana-tracker/PushNotificationManager"]}],"$L7"]}]]}],["$","$L8",null,{}]]}],null],null],null]},[null,["$","$L9",null,{"parallelRouterKey":"children","segmentPath":["children","mana-tracker","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$La",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$Lb",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L9",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$La",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$Lc",null,{}]]}]}]]}]],null],null],["$Ld",null]]]]
|
||||||
|
e:I[4636,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","347","static/chunks/app/mana-tracker/page-190454f13d1cd3f9.js"],"default"]
|
||||||
|
f:I[845,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","347","static/chunks/app/mana-tracker/page-190454f13d1cd3f9.js"],"default"]
|
||||||
|
6:["$","$Le",null,{}]
|
||||||
|
7:["$","$Lf",null,{}]
|
||||||
|
d:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/mana-tracker/page.js
Normal file
1
deploy/.next/server/app/mana-tracker/page.js
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/mana-tracker/page.js.nft.json
Normal file
1
deploy/.next/server/app/mana-tracker/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../components/mana-tracker/ExcursionBooking.tsx","../../../../components/mana-tracker/PushNotificationManager.tsx","../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/174.js","../../chunks/180.js","../../chunks/207.js","../../chunks/276.js","../../chunks/341.js","../../chunks/740.js","../../chunks/87.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/offline.html
Normal file
1
deploy/.next/server/app/offline.html
Normal file
File diff suppressed because one or more lines are too long
5
deploy/.next/server/app/offline.meta
Normal file
5
deploy/.next/server/app/offline.meta
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"headers": {
|
||||||
|
"x-next-cache-tags": "_N_T_/layout,_N_T_/offline/layout,_N_T_/offline/page,_N_T_/offline"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
deploy/.next/server/app/offline.rsc
Normal file
8
deploy/.next/server/app/offline.rsc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
2:I[9673,["130","static/chunks/130-fbdba5ec657d70e2.js","876","static/chunks/876-74e3127f7295a7cc.js","200","static/chunks/app/offline/page-c706c75d3862967d.js"],"default"]
|
||||||
|
3:I[4707,[],""]
|
||||||
|
4:I[6423,[],""]
|
||||||
|
5:I[5495,["185","static/chunks/app/layout-012feff5f2309838.js"],"ThemeProvider"]
|
||||||
|
6:I[1454,["185","static/chunks/app/layout-012feff5f2309838.js"],"default"]
|
||||||
|
0:["3c87ZLiEKCTo7fN65B1s7",[[["",{"children":["offline",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["offline",{"children":["__PAGE__",{},[["$L1",["$","div",null,{"className":"min-h-screen bg-background dark:bg-background-dark pb-16","children":[["$","div",null,{"className":"flex flex-col items-center justify-center min-h-[60vh] px-4 text-center","children":[["$","h1",null,{"className":"text-2xl font-bold text-primary mb-4","children":"Mode hors ligne"}],["$","p",null,{"className":"text-gray-600 mb-6","children":"Vous êtes actuellement hors ligne. Certaines fonctionnalités peuvent être limitées."}],["$","p",null,{"className":"text-sm text-gray-500","children":"Les données mises en cache restent disponibles."}]]}],["$","$L2",null,{}]]}],null],null],null]},[null,["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children","offline","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/37740839d02c8860.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"fr","suppressHydrationWarning":true,"children":[["$","head",null,{"children":[["$","link",null,{"rel":"icon","href":"/logo-relais-marama.svg","type":"image/svg+xml"}],["$","link",null,{"rel":"apple-touch-icon","href":"/logo-relais-marama.svg"}]]}],["$","body",null,{"className":"__className_f367f3","children":["$","$L5",null,{"attribute":"class","defaultTheme":"light","enableSystem":true,"disableTransitionOnChange":false,"children":[["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}],["$","$L6",null,{}]]}]}]]}]],null],null],["$L7",null]]]]
|
||||||
|
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Compagnon du lagon - Pension Marama"}],["$","meta","3",{"name":"description","content":"Votre guide numérique pour votre séjour à Fakarava"}],["$","link","4",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","meta","5",{"name":"apple-mobile-web-app-capable","content":"yes"}],["$","meta","6",{"name":"apple-mobile-web-app-title","content":"Compagnon du lagon - Pension Marama"}],["$","meta","7",{"name":"apple-mobile-web-app-status-bar-style","content":"default"}],["$","meta","8",{"name":"next-size-adjust"}]]
|
||||||
|
1:null
|
||||||
1
deploy/.next/server/app/offline/page.js
Normal file
1
deploy/.next/server/app/offline/page.js
Normal file
File diff suppressed because one or more lines are too long
1
deploy/.next/server/app/offline/page.js.nft.json
Normal file
1
deploy/.next/server/app/offline/page.js.nft.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":1,"files":["../../../../node_modules/next/dist/client/components/action-async-storage-instance.js","../../../../node_modules/next/dist/client/components/action-async-storage.external.js","../../../../node_modules/next/dist/client/components/async-local-storage.js","../../../../node_modules/next/dist/client/components/request-async-storage-instance.js","../../../../node_modules/next/dist/client/components/request-async-storage.external.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage-instance.js","../../../../node_modules/next/dist/client/components/static-generation-async-storage.external.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../../node_modules/next/dist/compiled/next-server/app-page.runtime.prod.js","../../../../node_modules/next/dist/server/lib/trace/constants.js","../../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../../node_modules/next/package.json","../../../../package.json","../../../package.json","../../chunks/276.js","../../chunks/341.js","../../chunks/740.js","../../chunks/87.js","../../webpack-runtime.js","page_client-reference-manifest.js"]}
|
||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user