change project structure
This commit is contained in:
parent
0dc1717704
commit
bf84395efe
|
@ -1,4 +1,31 @@
|
|||
# Update these with your Supabase details from your project settings > API
|
||||
# https://app.supabase.com/project/_/settings/api
|
||||
NEXT_PUBLIC_SUPABASE_URL=your-project-url
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
||||
|
||||
# Supabase Production URL
|
||||
NEXT_PUBLIC_SUPABASE_URL=
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
||||
SUPABASE_SERVICE_ROLE_SECRET=
|
||||
NEXT_PUBLIC_SUPABASE_STORAGE_URL=
|
||||
# Supabase Local URL
|
||||
NEXT_PUBLIC_SUPABASE_URL=
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=
|
||||
|
||||
# Supabase Service Role Secret Key
|
||||
SERVICE_ROLE_SECRET=
|
||||
|
||||
# RESEND_API_KEY_TES=
|
||||
RESEND_API_KEY=
|
||||
SEND_EMAIL_HOOK_SECRET=
|
||||
|
||||
# db connection string
|
||||
# Connect to Supabase via connection pooling with Supavisor.
|
||||
DATABASE_URL=
|
||||
|
||||
|
||||
|
||||
# Direct connection to the database. Used for migrations.
|
||||
DIRECT_URL=
|
||||
|
||||
DENO_ENV=
|
||||
|
||||
SIGAP_MAPBOX_ACCESS_TOKEN=
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
"use server";
|
||||
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { encodedRedirect } from "@/utils/utils";
|
||||
import { headers } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const forgotPasswordAction = async (formData: FormData) => {
|
||||
const email = formData.get("email")?.toString();
|
||||
const supabase = await createClient();
|
||||
const origin = (await headers()).get("origin");
|
||||
const callbackUrl = formData.get("callbackUrl")?.toString();
|
||||
|
||||
if (!email) {
|
||||
return encodedRedirect("error", "/forgot-password", "Email is required");
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.resetPasswordForEmail(email, {
|
||||
redirectTo: `${origin}/auth/callback?redirect_to=/protected/reset-password`,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error(error.message);
|
||||
return encodedRedirect(
|
||||
"error",
|
||||
"/forgot-password",
|
||||
"Could not reset password",
|
||||
);
|
||||
}
|
||||
|
||||
if (callbackUrl) {
|
||||
return redirect(callbackUrl);
|
||||
}
|
||||
|
||||
return encodedRedirect(
|
||||
"success",
|
||||
"/forgot-password",
|
||||
"Check your email for a link to reset your password.",
|
||||
);
|
||||
};
|
|
@ -1,43 +0,0 @@
|
|||
"use server";
|
||||
|
||||
import { encodedRedirect } from "@/utils/utils";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { headers } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const resetPasswordAction = async (formData: FormData) => {
|
||||
const supabase = await createClient();
|
||||
|
||||
const password = formData.get("password") as string;
|
||||
const confirmPassword = formData.get("confirmPassword") as string;
|
||||
|
||||
if (!password || !confirmPassword) {
|
||||
encodedRedirect(
|
||||
"error",
|
||||
"/protected/reset-password",
|
||||
"Password and confirm password are required"
|
||||
);
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
encodedRedirect(
|
||||
"error",
|
||||
"/protected/reset-password",
|
||||
"Passwords do not match"
|
||||
);
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.updateUser({
|
||||
password: password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
encodedRedirect(
|
||||
"error",
|
||||
"/protected/reset-password",
|
||||
"Password update failed"
|
||||
);
|
||||
}
|
||||
|
||||
encodedRedirect("success", "/protected/reset-password", "Password updated");
|
||||
};
|
|
@ -1,100 +0,0 @@
|
|||
// import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
// export async function sendContactEmail(formData: {
|
||||
// name: string;
|
||||
// email: string;
|
||||
// phone: string;
|
||||
// typeMessage: string;
|
||||
// message: string;
|
||||
// }) {
|
||||
// try {
|
||||
// // Initialize Supabase
|
||||
// const supabase = await createClient();
|
||||
// const { resend } = useResend();
|
||||
|
||||
// // Get message type label
|
||||
// const messageTypeLabel =
|
||||
// typeMessageMap.get(formData.typeMessage) || "Unknown";
|
||||
|
||||
// // Save to Supabase
|
||||
// const { data: contactData, error: contactError } = await supabase
|
||||
// .from("contact_messages")
|
||||
// .insert([
|
||||
// {
|
||||
// name: formData.name,
|
||||
// email: formData.email,
|
||||
// phone: formData.phone,
|
||||
// message_type: formData.typeMessage,
|
||||
// message_type_label: messageTypeLabel,
|
||||
// message: formData.message,
|
||||
// status: "new",
|
||||
// },
|
||||
// ])
|
||||
// .select();
|
||||
|
||||
// if (contactError) {
|
||||
// console.error("Error saving contact message to Supabase:", contactError);
|
||||
// return {
|
||||
// success: false,
|
||||
// error: "Failed to save your message. Please try again later.",
|
||||
// };
|
||||
// }
|
||||
|
||||
// // Render admin email template
|
||||
// const adminEmailHtml = await render(
|
||||
// AdminNotification({
|
||||
// name: formData.name,
|
||||
// email: formData.email,
|
||||
// phone: formData.phone,
|
||||
// messageType: messageTypeLabel,
|
||||
// message: formData.message,
|
||||
// })
|
||||
// );
|
||||
|
||||
// // Send email to admin
|
||||
// const { data: emailData, error: emailError } = await resend.emails.send({
|
||||
// from: "Contact Form <contact@backspacex.tech>",
|
||||
// to: ["xdamazon17@gmail.com"],
|
||||
// subject: `New Contact Form Submission: ${messageTypeLabel}`,
|
||||
// html: adminEmailHtml,
|
||||
// });
|
||||
|
||||
// if (emailError) {
|
||||
// console.error("Error sending email via Resend:", emailError);
|
||||
// // Note: We don't return error here since the data is already saved to Supabase
|
||||
// }
|
||||
|
||||
// const userEmailHtml = await render(
|
||||
// UserConfirmation({
|
||||
// name: formData.name,
|
||||
// messageType: messageTypeLabel,
|
||||
// message: formData.message,
|
||||
// })
|
||||
// );
|
||||
|
||||
// // Send confirmation email to user
|
||||
// const { data: confirmationData, error: confirmationError } =
|
||||
// await resend.emails.send({
|
||||
// from: "Your Company <support@backspacex.tech>",
|
||||
// to: [formData.email],
|
||||
// subject: "Thank you for contacting us",
|
||||
// html: userEmailHtml,
|
||||
// });
|
||||
|
||||
// if (confirmationError) {
|
||||
// console.error("Error sending confirmation email:", confirmationError);
|
||||
// // Note: We don't return error here either
|
||||
// }
|
||||
|
||||
// return {
|
||||
// success: true,
|
||||
// message: "Your message has been sent successfully!",
|
||||
// };
|
||||
// } catch (error) {
|
||||
// console.error("Unexpected error in sendContactEmail:", error);
|
||||
// return {
|
||||
// success: false,
|
||||
// error: "An unexpected error occurred. Please try again later.",
|
||||
// };
|
||||
// }
|
||||
// }
|
|
@ -1,37 +0,0 @@
|
|||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
export const checkSession = async () => {
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const {
|
||||
data: { session },
|
||||
error,
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.message,
|
||||
};
|
||||
}
|
||||
|
||||
if (session) {
|
||||
return {
|
||||
success: true,
|
||||
session,
|
||||
redirectTo: "/dashboard",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: "No active session",
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: "An unexpected error occurred",
|
||||
};
|
||||
}
|
||||
};
|
|
@ -1,56 +0,0 @@
|
|||
"use server";
|
||||
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { encodedRedirect } from "@/utils/utils";
|
||||
import { redirect } from "next/navigation";
|
||||
import { checkSession } from "./session";
|
||||
|
||||
export const signInAction = async (formData: FormData) => {
|
||||
const supabase = await createClient();
|
||||
const email = formData.get("email") as string;
|
||||
const encodeEmail = encodeURIComponent(email);
|
||||
|
||||
try {
|
||||
// First, check for existing session
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
// If there's an active session and the email matches
|
||||
if (session?.user?.email === email) {
|
||||
return {
|
||||
success: true,
|
||||
message: "You are already signed in",
|
||||
redirectTo: "/dashboard",
|
||||
};
|
||||
}
|
||||
|
||||
// If no active session or different email, proceed with OTP
|
||||
const { data, error } = await supabase.auth.signInWithOtp({
|
||||
email,
|
||||
options: {
|
||||
shouldCreateUser: false,
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.message,
|
||||
redirectTo: `/verify-otp?email=${encodeEmail}`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "OTP has been sent to your email",
|
||||
redirectTo: `/verify-otp?email=${encodeEmail}`,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: "An unexpected error occurred",
|
||||
redirectTo: "/sign-in",
|
||||
};
|
||||
}
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
"use server";
|
||||
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const signOutAction = async () => {
|
||||
const supabase = await createClient();
|
||||
await supabase.auth.signOut();
|
||||
return redirect("/sign-in");
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
"use server";
|
||||
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { encodedRedirect } from "@/utils/utils";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export const signUpAction = async (formData: FormData) => {
|
||||
const email = formData.get("email")?.toString();
|
||||
const password = formData.get("password")?.toString();
|
||||
const supabase = await createClient();
|
||||
const origin = (await headers()).get("origin");
|
||||
|
||||
if (!email || !password) {
|
||||
return encodedRedirect(
|
||||
"error",
|
||||
"/sign-up",
|
||||
"Email and password are required"
|
||||
);
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
options: {
|
||||
emailRedirectTo: `${origin}/auth/callback`,
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error(error.code + " " + error.message);
|
||||
return encodedRedirect("error", "/sign-up", error.message);
|
||||
} else {
|
||||
return encodedRedirect(
|
||||
"success",
|
||||
"/sign-up",
|
||||
"Thanks for signing up! Please check your email for a verification link."
|
||||
);
|
||||
}
|
||||
};
|
|
@ -1,30 +0,0 @@
|
|||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export const verifyOtpAction = async (formData: FormData) => {
|
||||
const email = formData.get("email") as string;
|
||||
const token = formData.get("token") as string;
|
||||
const supabase = await createClient();
|
||||
|
||||
console.log("email", email);
|
||||
console.log("token", token);
|
||||
|
||||
if (!email || !token) {
|
||||
redirect("/error?message=Email and OTP are required");
|
||||
}
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
error,
|
||||
} = await supabase.auth.verifyOtp({
|
||||
email,
|
||||
token,
|
||||
type: "email",
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return redirect(`/verify-otp?error=${encodeURIComponent(error.message)}`);
|
||||
}
|
||||
|
||||
return redirect("/dashboard?message=OTP verified successfully");
|
||||
};
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
import * as React from "react";
|
||||
|
||||
import { NavMain } from "@/app/(protected)/(admin)/_components/admin/navigations/nav-main";
|
||||
import { NavReports } from "@/app/(protected)/(admin)/_components/admin/navigations/nav-report";
|
||||
import { NavUser } from "@/app/(protected)/(admin)/_components/admin/navigations/nav-user";
|
||||
import { NavMain } from "@/app/(pages)/(admin)/_components/navigations/nav-main";
|
||||
import { NavReports } from "@/app/(pages)/(admin)/_components/navigations/nav-report";
|
||||
import { NavUser } from "@/app/(pages)/(admin)/_components/navigations/nav-user";
|
||||
|
||||
import {
|
||||
Sidebar,
|
||||
|
@ -15,10 +15,10 @@ import {
|
|||
} from "@/app/_components/ui/sidebar";
|
||||
import { NavPreMain } from "./navigations/nav-pre-main";
|
||||
import { navData } from "@/prisma/data/nav";
|
||||
import { TeamSwitcher } from "../../../../_components/team-switcher";
|
||||
import { TeamSwitcher } from "../../../_components/team-switcher";
|
||||
|
||||
import { Profile, User } from "@/src/models/users/users.model";
|
||||
import { getCurrentUser } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
||||
import { Profile, User } from "@/src/entities/models/users/users.model";
|
||||
import { getCurrentUser } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
|
||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
const [user, setUser] = React.useState<User | null>(null);
|
|
@ -19,7 +19,7 @@ import {
|
|||
import type * as TablerIcons from "@tabler/icons-react";
|
||||
|
||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||
import { formatUrl } from "@/utils/utils";
|
||||
import { formatUrl } from "@/app/_utils/utils";
|
||||
|
||||
interface SubSubItem {
|
||||
title: string;
|
|
@ -24,8 +24,8 @@ import {
|
|||
useSidebar,
|
||||
} from "@/app/_components/ui/sidebar";
|
||||
import { IconLogout, IconSettings, IconSparkles } from "@tabler/icons-react";
|
||||
import type { User } from "@/src/models/users/users.model";
|
||||
import { signOut } from "@/app/(auth-pages)/action";
|
||||
import type { User } from "@/src/entities/models/users/users.model";
|
||||
import { signOut } from "@/app/(pages)/(auth)/action";
|
||||
import { SettingsDialog } from "../settings/setting-dialog";
|
||||
|
||||
export function NavUser({ user }: { user: User | null }) {
|
|
@ -4,7 +4,7 @@ import { Card, CardContent } from "@/app/_components/ui/card";
|
|||
import { ScrollArea } from "@/app/_components/ui/scroll-area";
|
||||
import { Separator } from "@/app/_components/ui/separator";
|
||||
import { Upload } from "lucide-react";
|
||||
import { Badge } from "../../../../../_components/ui/badge";
|
||||
import { Badge } from "../../../../_components/ui/badge";
|
||||
import {
|
||||
IconBrandGoogleAnalytics,
|
||||
IconCsv,
|
|
@ -10,7 +10,7 @@ import {
|
|||
getNotificationPreferences,
|
||||
saveNotificationPreferences,
|
||||
applyNotificationPreferences,
|
||||
} from "@/utils/notification-cookies-manager";
|
||||
} from "@/app/_utils/cookies/notification-cookies-manager";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export default function NotificationsSetting() {
|
|
@ -5,8 +5,8 @@ import { ChevronDown } from "lucide-react";
|
|||
import { Switch } from "@/app/_components/ui/switch";
|
||||
import { Separator } from "@/app/_components/ui/separator";
|
||||
import { ScrollArea } from "@/app/_components/ui/scroll-area";
|
||||
import { ThemeSwitcher } from "../../../../../_components/theme-switcher";
|
||||
import DropdownSwitcher from "../../../../../_components/custom-dropdown-switcher";
|
||||
import { ThemeSwitcher } from "../../../../_components/theme-switcher";
|
||||
import DropdownSwitcher from "../../../../_components/custom-dropdown-switcher";
|
||||
import {
|
||||
type CookiePreferences,
|
||||
defaultCookiePreferences,
|
||||
|
@ -21,7 +21,7 @@ import {
|
|||
getAutoTimezonePreference,
|
||||
saveAutoTimezonePreference,
|
||||
applyCookiePreferences,
|
||||
} from "@/utils/cookies-manager";
|
||||
} from "@/app/_utils/cookies/cookies-manager";
|
||||
import { toast } from "sonner";
|
||||
import { initialTimezones, TimezoneType } from "@/prisma/data/timezones";
|
||||
import { languages, LanguageType } from "@/prisma/data/languages";
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import type React from "react";
|
||||
|
||||
import type { User } from "@/src/models/users/users.model";
|
||||
import type { User } from "@/src/entities/models/users/users.model";
|
||||
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
@ -31,7 +31,7 @@ import { ScrollArea } from "@/app/_components/ui/scroll-area";
|
|||
import {
|
||||
updateUser,
|
||||
uploadAvatar,
|
||||
} from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
||||
} from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
|
||||
const profileFormSchema = z.object({
|
||||
username: z.string().nullable().optional(),
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import type { User } from "@/src/models/users/users.model";
|
||||
import type { User } from "@/src/entities/models/users/users.model";
|
||||
import { Button } from "@/app/_components/ui/button";
|
||||
import { Separator } from "@/app/_components/ui/separator";
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
@ -28,7 +28,7 @@ import {
|
|||
IconUsers,
|
||||
IconWorld,
|
||||
} from "@tabler/icons-react";
|
||||
import type { User } from "@/src/models/users/users.model";
|
||||
import type { User } from "@/src/entities/models/users/users.model";
|
||||
import { ProfileSettings } from "./profile-settings";
|
||||
import { DialogTitle } from "@radix-ui/react-dialog";
|
||||
import { useState } from "react";
|
|
@ -1,5 +1,5 @@
|
|||
import { DateTimePicker2 } from "@/app/_components/ui/date-picker";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { createClient } from "@/app/_utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function DashboardPage() {
|
|
@ -10,7 +10,7 @@ import {
|
|||
import { Button } from "@/app/_components/ui/button";
|
||||
import { Input } from "@/app/_components/ui/input";
|
||||
import { Checkbox } from "@/app/_components/ui/checkbox";
|
||||
import { createUser } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
||||
import { createUser } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
import { toast } from "sonner";
|
||||
import { Mail, Lock, Loader2, X } from "lucide-react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
|
@ -14,7 +14,7 @@ import { Label } from "@/app/_components/ui/label";
|
|||
import { Input } from "@/app/_components/ui/input";
|
||||
import { Textarea } from "@/app/_components/ui/textarea";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { inviteUser } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
||||
import { inviteUser } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
import { toast } from "sonner";
|
||||
|
||||
interface InviteUserDialogProps {
|
|
@ -6,7 +6,7 @@ import { useState, useRef } from "react";
|
|||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import type { User } from "@/src/models/users/users.model";
|
||||
import type { User } from "@/src/entities/models/users/users.model";
|
||||
|
||||
import {
|
||||
Form,
|
||||
|
@ -27,7 +27,7 @@ import { Textarea } from "@/app/_components/ui/textarea";
|
|||
import { Button } from "@/app/_components/ui/button";
|
||||
import { Label } from "@/app/_components/ui/label";
|
||||
import { ImageIcon, Loader2 } from "lucide-react";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import { createClient } from "@/app/_utils/supabase/client";
|
||||
|
||||
// Profile update form schema
|
||||
const profileFormSchema = z.object({
|
|
@ -38,7 +38,7 @@ import {
|
|||
sendMagicLink,
|
||||
sendPasswordRecovery,
|
||||
unbanUser,
|
||||
} from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
||||
} from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
import { format } from "date-fns";
|
||||
|
||||
interface UserDetailSheetProps {
|
|
@ -1,20 +1,15 @@
|
|||
|
||||
import type React from "react"
|
||||
|
||||
import { useState } from "react"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useForm } from "react-hook-form"
|
||||
import type * as z from "zod"
|
||||
|
||||
import { Loader2 } from "lucide-react"
|
||||
|
||||
import { UpdateUserParamsSchema, type User, UserSchema } from "@/src/models/users/users.model"
|
||||
import { UpdateUserParamsSchema, type User } from "@/src/entities/models/users/users.model"
|
||||
|
||||
// UI Components
|
||||
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/app/_components/ui/sheet"
|
||||
import {
|
||||
Form,
|
||||
} from "@/app/_components/ui/form"
|
||||
import { Form } from "@/app/_components/ui/form"
|
||||
|
||||
import { Button } from "@/app/_components/ui/button"
|
||||
import { FormSection } from "@/app/_components/form-section"
|
||||
|
@ -22,8 +17,6 @@ import { FormFieldWrapper } from "@/app/_components/form-wrapper"
|
|||
import { useMutation } from "@tanstack/react-query"
|
||||
import { updateUser } from "../action"
|
||||
import { toast } from "sonner"
|
||||
import { DateTimePicker2 } from "@/app/_components/ui/date-picker"
|
||||
|
||||
|
||||
type UserProfileFormValues = z.infer<typeof UpdateUserParamsSchema>
|
||||
|
||||
|
@ -31,33 +24,33 @@ interface UserProfileSheetProps {
|
|||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
userData?: User
|
||||
onUserUpdated: () => void
|
||||
}
|
||||
|
||||
export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSheetProps) {
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
export function UserProfileSheet({ open, onOpenChange, userData, onUserUpdated }: UserProfileSheetProps) {
|
||||
// Initialize form with user data
|
||||
const form = useForm<UserProfileFormValues>({
|
||||
resolver: zodResolver(UpdateUserParamsSchema),
|
||||
defaultValues: {
|
||||
email: userData?.email || "",
|
||||
password_hash: userData?.password_hash || "",
|
||||
email: userData?.email || undefined,
|
||||
encrypted_password: userData?.encrypted_password || undefined,
|
||||
role: (userData?.role as "user" | "staff" | "admin") || "user",
|
||||
phone: userData?.phone || "",
|
||||
phone: userData?.phone || undefined,
|
||||
invited_at: userData?.invited_at || undefined,
|
||||
confirmed_at: userData?.confirmed_at || undefined,
|
||||
recovery_sent_at: userData?.recovery_sent_at || undefined,
|
||||
// recovery_sent_at: userData?.recovery_sent_at || undefined,
|
||||
last_sign_in_at: userData?.last_sign_in_at || undefined,
|
||||
created_at: userData?.created_at || undefined,
|
||||
updated_at: userData?.updated_at || undefined,
|
||||
is_anonymous: userData?.is_anonymous || false,
|
||||
profile: {
|
||||
id: userData?.profile?.id || "",
|
||||
user_id: userData?.profile?.user_id || "",
|
||||
avatar: userData?.profile?.avatar || "",
|
||||
username: userData?.profile?.username || "",
|
||||
first_name: userData?.profile?.first_name || "",
|
||||
last_name: userData?.profile?.last_name || "",
|
||||
bio: userData?.profile?.bio || "",
|
||||
id: userData?.profile?.id || undefined,
|
||||
user_id: userData?.profile?.user_id || undefined,
|
||||
avatar: userData?.profile?.avatar || undefined,
|
||||
username: userData?.profile?.username || undefined,
|
||||
first_name: userData?.profile?.first_name || undefined,
|
||||
last_name: userData?.profile?.last_name || undefined,
|
||||
bio: userData?.profile?.bio || undefined,
|
||||
address: userData?.profile?.address || {
|
||||
street: "",
|
||||
city: "",
|
||||
|
@ -74,27 +67,26 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
|||
mutationKey: ["updateUser"],
|
||||
mutationFn: (data: UserProfileFormValues) => {
|
||||
if (!userData?.id) {
|
||||
throw new Error("User ID is required");
|
||||
throw new Error("User ID is required")
|
||||
}
|
||||
return updateUser(userData.id, data);
|
||||
return updateUser(userData.id, data)
|
||||
},
|
||||
onError: (error) => {
|
||||
toast("Failed to update user");
|
||||
toast("Failed to update user")
|
||||
onOpenChange(false)
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast("User updated");
|
||||
toast("User updated")
|
||||
onUserUpdated()
|
||||
onOpenChange(false)
|
||||
},
|
||||
})
|
||||
|
||||
async function onSubmit(data: UserProfileFormValues) {
|
||||
try {
|
||||
setIsSaving(true)
|
||||
await updateUserMutation(data)
|
||||
onOpenChange(false)
|
||||
} catch (error) {
|
||||
console.error("Error saving user profile:", error)
|
||||
} finally {
|
||||
setIsSaving(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +105,6 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
|||
title="User Information"
|
||||
description="Update the user information below. Fields marked with an asterisk (*) are required."
|
||||
>
|
||||
|
||||
<FormFieldWrapper
|
||||
name="email"
|
||||
label="Email"
|
||||
|
@ -149,19 +140,13 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
|||
booleanType="select"
|
||||
/>
|
||||
<FormFieldWrapper
|
||||
name="password_hash"
|
||||
label="Password Hash"
|
||||
name="encrypted_password_hash"
|
||||
label="Encrypted_password Hash"
|
||||
type="string"
|
||||
control={form.control}
|
||||
placeholder="Password Hash"
|
||||
/>
|
||||
<FormFieldWrapper
|
||||
name="invited_at"
|
||||
label="Invited At"
|
||||
type="date"
|
||||
control={form.control}
|
||||
isDate={true}
|
||||
placeholder="Encrypted_password Hash"
|
||||
/>
|
||||
<FormFieldWrapper name="invited_at" label="Invited At" type="date" control={form.control} isDate={true} />
|
||||
<FormFieldWrapper
|
||||
name="confirmed_at"
|
||||
label="Confirmed At"
|
||||
|
@ -183,21 +168,8 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
|||
control={form.control}
|
||||
isDate={true}
|
||||
/>
|
||||
<FormFieldWrapper
|
||||
name="created_at"
|
||||
label="Created At"
|
||||
type="date"
|
||||
control={form.control}
|
||||
isDate={true}
|
||||
/>
|
||||
<FormFieldWrapper
|
||||
name="updated_at"
|
||||
label="Updated At"
|
||||
type="date"
|
||||
control={form.control}
|
||||
isDate={true}
|
||||
/>
|
||||
|
||||
<FormFieldWrapper name="created_at" label="Created At" type="date" control={form.control} isDate={true} />
|
||||
<FormFieldWrapper name="updated_at" label="Updated At" type="date" control={form.control} isDate={true} />
|
||||
</FormSection>
|
||||
|
||||
{/* Profile Information Section */}
|
||||
|
@ -288,11 +260,17 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
|||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex justify-end space-x-4">
|
||||
<Button type="button" variant="outline" size="xs" onClick={() => onOpenChange(false)} disabled={isPending}>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() => !isPending && onOpenChange(false)}
|
||||
disabled={isPending}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button size="xs" type="submit" disabled={isPending}>
|
||||
{isPending && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
{isPending && <Loader2 className="mr-1 h-4 w-4 animate-spin" />}
|
||||
{isPending ? "Saving..." : "Save"}
|
||||
</Button>
|
||||
</div>
|
|
@ -26,8 +26,8 @@ import {
|
|||
DropdownMenuCheckboxItem,
|
||||
} from "@/app/_components/ui/dropdown-menu";
|
||||
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
||||
import { fetchUsers } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
||||
import type { User } from "@/src/models/users/users.model";
|
||||
import { fetchUsers } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
import type { User } from "@/src/entities/models/users/users.model";
|
||||
import { DataTable } from "./data-table";
|
||||
import { InviteUserDialog } from "./invite-user";
|
||||
import { AddUserDialog } from "./add-user-dialog";
|
||||
|
@ -668,7 +668,7 @@ export default function UserManagement() {
|
|||
open={isUpdateOpen}
|
||||
onOpenChange={setIsUpdateOpen}
|
||||
userData={updateUser}
|
||||
|
||||
onUserUpdated={() => refetch()}
|
||||
/>
|
||||
)}
|
||||
</div>
|
|
@ -3,8 +3,8 @@
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Card, CardContent } from "@/app/_components/ui/card";
|
||||
import { Users, UserCheck, UserX } from "lucide-react";
|
||||
import { fetchUsers } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
||||
import { User } from "@/src/models/users/users.model";
|
||||
import { fetchUsers } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||
import { User } from "@/src/entities/models/users/users.model";
|
||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
|
@ -1,15 +1,15 @@
|
|||
"use server";
|
||||
|
||||
import db from "@/lib/db";
|
||||
import db from "@/prisma/db";
|
||||
import {
|
||||
CreateUserParams,
|
||||
InviteUserParams,
|
||||
UpdateUserParams,
|
||||
User,
|
||||
UserResponse,
|
||||
} from "@/src/models/users/users.model";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { createAdminClient } from "@/utils/supabase/admin";
|
||||
} from "@/src/entities/models/users/users.model";
|
||||
import { createClient } from "@/app/_utils/supabase/server";
|
||||
import { createAdminClient } from "@/app/_utils/supabase/admin";
|
||||
|
||||
// Initialize Supabase client with admin key
|
||||
|
||||
|
@ -84,7 +84,7 @@ export async function createUser(
|
|||
|
||||
const { data, error } = await supabase.auth.admin.createUser({
|
||||
email: params.email,
|
||||
password: params.password,
|
||||
password: params.encrypted_password,
|
||||
phone: params.phone,
|
||||
email_confirm: params.email_confirm,
|
||||
});
|
||||
|
@ -163,8 +163,8 @@ export async function updateUser(
|
|||
const { data, error } = await supabase.auth.admin.updateUserById(userId, {
|
||||
email: params.email,
|
||||
email_confirm: params.email_confirmed_at,
|
||||
password: params.password_hash ?? undefined,
|
||||
password_hash: params.password_hash ?? undefined,
|
||||
password: params.encrypted_password ?? undefined,
|
||||
password_hash: params.encrypted_password ?? undefined,
|
||||
phone: params.phone,
|
||||
phone_confirm: params.phone_confirmed_at,
|
||||
role: params.role,
|
||||
|
@ -196,13 +196,13 @@ export async function updateUser(
|
|||
},
|
||||
data: {
|
||||
role: params.role || user.role,
|
||||
invited_at: params.invited_at || user.role,
|
||||
confirmed_at: params.confirmed_at || user.role,
|
||||
recovery_sent_at: params.recovery_sent_at || user.role,
|
||||
last_sign_in_at: params.last_sign_in_at || user.role,
|
||||
invited_at: params.invited_at || user.invited_at,
|
||||
confirmed_at: params.confirmed_at || user.confirmed_at,
|
||||
// recovery_sent_at: params.recovery_sent_at || user.recovery_sent_at,
|
||||
last_sign_in_at: params.last_sign_in_at || user.last_sign_in_at,
|
||||
is_anonymous: params.is_anonymous || user.is_anonymous,
|
||||
created_at: params.created_at || user.role,
|
||||
updated_at: params.updated_at || user.role,
|
||||
created_at: params.created_at || user.created_at,
|
||||
updated_at: params.updated_at || user.updated_at,
|
||||
profile: {
|
||||
update: {
|
||||
avatar: params.profile?.avatar || user.profile?.avatar,
|
|
@ -1,5 +1,5 @@
|
|||
import UserManagement from "@/app/(protected)/(admin)/dashboard/user-management/_components/user-management";
|
||||
import { UserStats } from "@/app/(protected)/(admin)/dashboard/user-management/_components/user-stats";
|
||||
import UserManagement from "@/app/(pages)/(admin)/dashboard/user-management/_components/user-management";
|
||||
import { UserStats } from "@/app/(pages)/(admin)/dashboard/user-management/_components/user-stats";
|
||||
|
||||
export default function UsersPage() {
|
||||
return (
|
|
@ -26,8 +26,8 @@ import { ThemeSwitcher } from "@/app/_components/theme-switcher";
|
|||
import { Separator } from "@/app/_components/ui/separator";
|
||||
import { InboxDrawer } from "@/app/_components/inbox-drawer";
|
||||
import FloatingActionSearchBar from "@/app/_components/floating-action-search-bar";
|
||||
import { AppSidebar } from "@/app/(protected)/(admin)/_components/admin/app-sidebar";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { AppSidebar } from "@/app/(pages)/(admin)/_components/app-sidebar";
|
||||
import { createClient } from "@/app/_utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function Layout({
|
|
@ -3,11 +3,11 @@
|
|||
import type React from "react";
|
||||
|
||||
import { Lock } from "lucide-react";
|
||||
import { Button } from "../ui/button";
|
||||
import { Input } from "../ui/input";
|
||||
import { SubmitButton } from "../submit-button";
|
||||
import { Button } from "../../../_components/ui/button";
|
||||
import { Input } from "../../../_components/ui/input";
|
||||
import { SubmitButton } from "../../../_components/submit-button";
|
||||
import Link from "next/link";
|
||||
import { FormField } from "../form-field";
|
||||
import { FormField } from "../../../_components/form-field";
|
||||
import { useSignInForm } from "@/src/controller/auth/sign-in-controller";
|
||||
|
||||
export function SignInForm({
|
|
@ -23,7 +23,7 @@ import {
|
|||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/app/_components/ui/card";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
import { useVerifyOtpForm } from "@/src/controller/auth/verify-otp.controller";
|
||||
|
||||
interface VerifyOtpFormProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
@ -1,12 +1,12 @@
|
|||
// src/app/(auth-pages)/actions.ts
|
||||
// src/app/(auth)/actions.ts
|
||||
"use server";
|
||||
|
||||
import db from "@/lib/db";
|
||||
import { SignInFormData } from "@/src/models/auth/sign-in.model";
|
||||
import { VerifyOtpFormData } from "@/src/models/auth/verify-otp.model";
|
||||
import { User } from "@/src/models/users/users.model";
|
||||
import db from "@/prisma/db";
|
||||
import { SignInFormData } from "@/src/entities/models/auth/sign-in.model";
|
||||
import { VerifyOtpFormData } from "@/src/entities/models/auth/verify-otp.model";
|
||||
import { User } from "@/src/entities/models/users/users.model";
|
||||
import { authRepository } from "@/src/repositories/authentication.repository";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { createClient } from "@/app/_utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export async function signIn(
|
|
@ -1,6 +1,6 @@
|
|||
import { redirect } from "next/navigation";
|
||||
import { checkSession } from "./_actions/session";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import { createClient } from "@/app/_utils/supabase/client";
|
||||
|
||||
export default async function Layout({
|
||||
children,
|
|
@ -1,4 +1,4 @@
|
|||
import { SignInForm } from "@/app/_components/auth/signin-form";
|
||||
import { SignInForm } from "@/app/(pages)/(auth)/_components/signin-form";
|
||||
import { Message } from "@/app/_components/form-message";
|
||||
import { Button } from "@/app/_components/ui/button";
|
||||
import { GalleryVerticalEnd, Globe } from "lucide-react";
|
|
@ -1,4 +1,4 @@
|
|||
import { VerifyOtpForm } from "@/app/_components/auth/verify-otp-form";
|
||||
import { VerifyOtpForm } from "@/app/(pages)/(auth)/_components/verify-otp-form";
|
||||
import { GalleryVerticalEnd } from "lucide-react";
|
||||
|
||||
export default async function VerifyOtpPage() {
|
|
@ -1,13 +1,7 @@
|
|||
import DeployButton from "@/app/_components/deploy-button";
|
||||
import { EnvVarWarning } from "@/app/_components/env-var-warning";
|
||||
import HeaderAuth from "@/app/_components/header-auth";
|
||||
import { ThemeSwitcher } from "@/app/_components/theme-switcher";
|
||||
import { hasEnvVars } from "@/utils/supabase/check-env-vars";
|
||||
import { Geist } from "next/font/google";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import Link from "next/link";
|
||||
import "./globals.css";
|
||||
import ReactQueryProvider from "@/providers/react-query-provider";
|
||||
import "@/app/_styles/globals.css";
|
||||
import ReactQueryProvider from "@/app/_lib/react-query-provider";
|
||||
import { Toaster } from "@/app/_components/ui/sonner";
|
||||
|
||||
const defaultUrl = process.env.VERCEL_URL
|
|
@ -1,7 +1,7 @@
|
|||
import Hero from "@/app/_components/hero";
|
||||
import ConnectSupabaseSteps from "@/app/_components/tutorial/connect-supabase-steps";
|
||||
import SignUpUserSteps from "@/app/_components/tutorial/sign-up-user-steps";
|
||||
import { hasEnvVars } from "@/utils/supabase/check-env-vars";
|
||||
import { hasEnvVars } from "@/app/_utils/supabase/check-env-vars";
|
||||
|
||||
export default async function Home() {
|
||||
return (
|
|
@ -1,48 +0,0 @@
|
|||
import FetchDataSteps from "@/app/_components/tutorial/fetch-data-steps";
|
||||
import db from "@/lib/db";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { InfoIcon } from "lucide-react";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function ProtectedPage() {
|
||||
const supabase = await createClient();
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
if (!user) {
|
||||
return redirect("/sign-in");
|
||||
}
|
||||
|
||||
const userDetail = await db.users.findUnique({
|
||||
where: {
|
||||
id: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex-1 w-full flex flex-col gap-12">
|
||||
<div className="w-full">
|
||||
<div className="bg-accent text-sm p-3 px-5 rounded-md text-foreground flex gap-3 items-center">
|
||||
<InfoIcon size="16" strokeWidth={2} />
|
||||
This is a protected page that you can only see as an authenticated
|
||||
user
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 items-start">
|
||||
<h2 className="font-bold text-2xl mb-4">Your user details</h2>
|
||||
<pre className="text-xs font-mono p-3 rounded border overflow-auto">
|
||||
{JSON.stringify(userDetail, null, 2)}
|
||||
</pre>
|
||||
<pre className="text-xs font-mono p-3 rounded border overflow-auto">
|
||||
{JSON.stringify(user, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="font-bold text-2xl mb-4">Next steps</h2>
|
||||
<FetchDataSteps />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -18,7 +18,7 @@ import {
|
|||
} from "@/app/_components/ui/dropdown-menu";
|
||||
import { Badge } from "@/app/_components/ui/badge";
|
||||
import { Input } from "@/app/_components/ui/input";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
|
||||
type Option<T> = {
|
||||
value: T;
|
||||
|
|
|
@ -5,7 +5,7 @@ import { ChevronLeft, ChevronRight, Clock } from "lucide-react"
|
|||
import { DayPicker } from "react-day-picker"
|
||||
import { useVirtualizer } from "@tanstack/react-virtual"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/app/_components/ui/select"
|
||||
import { Input } from "@/app/_components/ui/input"
|
||||
import { Button } from "@/app/_components/ui/button"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"use client"
|
||||
import { format } from "date-fns"
|
||||
import { CalendarIcon, ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
// UI Components
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription } from "@/app/_components/ui/form"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
import { hasEnvVars } from "@/utils/supabase/check-env-vars";
|
||||
import { hasEnvVars } from "@/app/_utils/supabase/check-env-vars";
|
||||
import Link from "next/link";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { Button } from "./ui/button";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { signOutAction } from "@/app/(auth-pages)/_actions/sign-out";
|
||||
import { createClient } from "@/app/_utils/supabase/server";
|
||||
import { signOutAction } from "@/app/(pages)/(auth)/_actions/sign-out";
|
||||
|
||||
export default async function AuthButton() {
|
||||
const supabase = await createClient();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react";
|
||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
import { buttonVariants } from "@/app/_components/ui/button";
|
||||
|
||||
const AlertDialog = AlertDialogPrimitive.Root;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Avatar = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as React from "react"
|
|||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Breadcrumb = React.forwardRef<
|
||||
HTMLElement,
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as React from "react"
|
|||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react";
|
|||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { DayPicker } from "react-day-picker";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
import { buttonVariants } from "@/app/_components/ui/button";
|
||||
|
||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react";
|
|||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
||||
import { Check } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
|
||||
const Checkbox = React.forwardRef<
|
||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react"
|
|||
import { format, getMonth, getYear, setMonth, setYear, setHours, setMinutes, setSeconds } from "date-fns"
|
||||
import { Calendar as CalendarIcon, Clock } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
import { Button } from "@/app/_components/ui/button"
|
||||
import { Calendar } from "@/app/_components/ui/calendar"
|
||||
import {
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react";
|
|||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react"
|
||||
import { Drawer as DrawerPrimitive } from "vaul"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Drawer = ({
|
||||
shouldScaleBackground = true,
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react";
|
|||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
useFormContext,
|
||||
} from "react-hook-form";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
import { Label } from "@/app/_components/ui/label";
|
||||
|
||||
const Form = FormProvider;
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react"
|
|||
import { OTPInput, OTPInputContext } from "input-otp"
|
||||
import { Dot } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const InputOTP = React.forwardRef<
|
||||
React.ElementRef<typeof OTPInput>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react"
|
|||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react";
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react"
|
|||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Select = SelectPrimitive.Root
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react"
|
||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Separator = React.forwardRef<
|
||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||
|
|
|
@ -5,7 +5,7 @@ import * as SheetPrimitive from "@radix-ui/react-dialog"
|
|||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Sheet = SheetPrimitive.Root
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { VariantProps, cva } from "class-variance-authority";
|
|||
import { PanelLeft } from "lucide-react";
|
||||
|
||||
import { useIsMobile } from "@/app/_hooks/use-mobile";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn } from "@/app/_lib/utils";
|
||||
import { Button } from "@/app/_components/ui/button";
|
||||
import { Input } from "@/app/_components/ui/input";
|
||||
import { Separator } from "@/app/_components/ui/separator";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
function Skeleton({
|
||||
className,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Table = React.forwardRef<
|
||||
HTMLTableElement,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react"
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Tabs = TabsPrimitive.Root
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const Textarea = React.forwardRef<
|
||||
HTMLTextAreaElement,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import * as React from "react"
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { cn } from "@/app/_lib/utils"
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { createClient } from "@/utils/supabase/server";
|
||||
import { createClient } from "@/app/_utils/supabase/server";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
Before Width: | Height: | Size: 283 KiB After Width: | Height: | Size: 283 KiB |
Before Width: | Height: | Size: 283 KiB After Width: | Height: | Size: 283 KiB |
|
@ -1,5 +1,5 @@
|
|||
import { type NextRequest } from "next/server";
|
||||
import { updateSession } from "@/utils/supabase/middleware";
|
||||
import { updateSession } from "@/app/_utils/supabase/middleware";
|
||||
|
||||
export async function middleware(request: NextRequest) {
|
||||
return await updateSession(request);
|
||||
|
|
|
@ -7,11 +7,11 @@ import {
|
|||
defaultSignInValues,
|
||||
SignInFormData,
|
||||
signInSchema,
|
||||
} from "@/src/models/auth/sign-in.model";
|
||||
} from "@/src/entities/models/auth/sign-in.model";
|
||||
import { useState, type FormEvent, type ChangeEvent } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import { signIn } from "@/app/(auth-pages)/action";
|
||||
import { signIn } from "@/app/(pages)/(auth)/action";
|
||||
|
||||
type SignInFormErrors = Partial<Record<keyof SignInFormData, string>>;
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ import { useState } from "react";
|
|||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { verifyOtp } from "@/app/(auth-pages)/action";
|
||||
import { verifyOtp } from "@/app/(pages)/(auth)/action";
|
||||
import {
|
||||
defaultVerifyOtpValues,
|
||||
VerifyOtpFormData,
|
||||
verifyOtpSchema,
|
||||
} from "@/src/models/auth/verify-otp.model";
|
||||
} from "@/src/entities/models/auth/verify-otp.model";
|
||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||
import { toast } from "sonner";
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
export class AuthenticationError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthenticatedError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthorizedError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
export class DatabaseOperationError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class NotFoundError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class InputParseError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
super(message, options);
|
||||
}
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ export const UserSchema = z.object({
|
|||
role: z.string().optional(),
|
||||
email: z.string().email().optional(),
|
||||
email_confirmed_at: z.union([z.string(), z.date()]).nullable().optional(),
|
||||
password_hash: z.string().nullable().optional(),
|
||||
encrypted_password: z.string().nullable().optional(),
|
||||
invited_at: z.union([z.string(), z.date()]).nullable().optional(),
|
||||
phone: z.string().nullable().optional(),
|
||||
confirmed_at: z.union([z.string(), z.date()]).nullable().optional(),
|
||||
|
@ -84,7 +84,7 @@ export type Profile = z.infer<typeof ProfileSchema>;
|
|||
|
||||
export const CreateUserParamsSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string(),
|
||||
encrypted_password: z.string(),
|
||||
phone: z.string().optional(),
|
||||
user_metadata: z.record(z.any()).optional(),
|
||||
email_confirm: z.boolean().optional(),
|
||||
|
@ -95,13 +95,13 @@ export type CreateUserParams = z.infer<typeof CreateUserParamsSchema>;
|
|||
export const UpdateUserParamsSchema = z.object({
|
||||
email: z.string().email().optional(),
|
||||
email_confirmed_at: z.boolean().optional(),
|
||||
password_hash: z.string().optional(),
|
||||
encrypted_password: z.string().optional(),
|
||||
role: z.enum(["user", "staff", "admin"]).optional(),
|
||||
phone: z.string().optional(),
|
||||
phone_confirmed_at: z.boolean().optional(),
|
||||
invited_at: z.union([z.string(), z.date()]).optional(),
|
||||
confirmed_at: z.union([z.string(), z.date()]).optional(),
|
||||
recovery_sent_at: z.union([z.string(), z.date()]).optional(),
|
||||
// recovery_sent_at: z.union([z.string(), z.date()]).optional(),
|
||||
last_sign_in_at: z.union([z.string(), z.date()]).optional(),
|
||||
created_at: z.union([z.string(), z.date()]).optional(),
|
||||
updated_at: z.union([z.string(), z.date()]).optional(),
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue