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
|
# Update these with your Supabase details from your project settings > API
|
||||||
# https://app.supabase.com/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 * as React from "react";
|
||||||
|
|
||||||
import { NavMain } from "@/app/(protected)/(admin)/_components/admin/navigations/nav-main";
|
import { NavMain } from "@/app/(pages)/(admin)/_components/navigations/nav-main";
|
||||||
import { NavReports } from "@/app/(protected)/(admin)/_components/admin/navigations/nav-report";
|
import { NavReports } from "@/app/(pages)/(admin)/_components/navigations/nav-report";
|
||||||
import { NavUser } from "@/app/(protected)/(admin)/_components/admin/navigations/nav-user";
|
import { NavUser } from "@/app/(pages)/(admin)/_components/navigations/nav-user";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
|
@ -15,10 +15,10 @@ import {
|
||||||
} from "@/app/_components/ui/sidebar";
|
} from "@/app/_components/ui/sidebar";
|
||||||
import { NavPreMain } from "./navigations/nav-pre-main";
|
import { NavPreMain } from "./navigations/nav-pre-main";
|
||||||
import { navData } from "@/prisma/data/nav";
|
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 { Profile, User } from "@/src/entities/models/users/users.model";
|
||||||
import { getCurrentUser } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
import { getCurrentUser } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||||
|
|
||||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||||
const [user, setUser] = React.useState<User | null>(null);
|
const [user, setUser] = React.useState<User | null>(null);
|
|
@ -19,7 +19,7 @@ import {
|
||||||
import type * as TablerIcons from "@tabler/icons-react";
|
import type * as TablerIcons from "@tabler/icons-react";
|
||||||
|
|
||||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||||
import { formatUrl } from "@/utils/utils";
|
import { formatUrl } from "@/app/_utils/utils";
|
||||||
|
|
||||||
interface SubSubItem {
|
interface SubSubItem {
|
||||||
title: string;
|
title: string;
|
|
@ -24,8 +24,8 @@ import {
|
||||||
useSidebar,
|
useSidebar,
|
||||||
} from "@/app/_components/ui/sidebar";
|
} from "@/app/_components/ui/sidebar";
|
||||||
import { IconLogout, IconSettings, IconSparkles } from "@tabler/icons-react";
|
import { IconLogout, IconSettings, IconSparkles } from "@tabler/icons-react";
|
||||||
import type { User } from "@/src/models/users/users.model";
|
import type { User } from "@/src/entities/models/users/users.model";
|
||||||
import { signOut } from "@/app/(auth-pages)/action";
|
import { signOut } from "@/app/(pages)/(auth)/action";
|
||||||
import { SettingsDialog } from "../settings/setting-dialog";
|
import { SettingsDialog } from "../settings/setting-dialog";
|
||||||
|
|
||||||
export function NavUser({ user }: { user: User | null }) {
|
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 { ScrollArea } from "@/app/_components/ui/scroll-area";
|
||||||
import { Separator } from "@/app/_components/ui/separator";
|
import { Separator } from "@/app/_components/ui/separator";
|
||||||
import { Upload } from "lucide-react";
|
import { Upload } from "lucide-react";
|
||||||
import { Badge } from "../../../../../_components/ui/badge";
|
import { Badge } from "../../../../_components/ui/badge";
|
||||||
import {
|
import {
|
||||||
IconBrandGoogleAnalytics,
|
IconBrandGoogleAnalytics,
|
||||||
IconCsv,
|
IconCsv,
|
|
@ -10,7 +10,7 @@ import {
|
||||||
getNotificationPreferences,
|
getNotificationPreferences,
|
||||||
saveNotificationPreferences,
|
saveNotificationPreferences,
|
||||||
applyNotificationPreferences,
|
applyNotificationPreferences,
|
||||||
} from "@/utils/notification-cookies-manager";
|
} from "@/app/_utils/cookies/notification-cookies-manager";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
export default function NotificationsSetting() {
|
export default function NotificationsSetting() {
|
|
@ -5,8 +5,8 @@ import { ChevronDown } from "lucide-react";
|
||||||
import { Switch } from "@/app/_components/ui/switch";
|
import { Switch } from "@/app/_components/ui/switch";
|
||||||
import { Separator } from "@/app/_components/ui/separator";
|
import { Separator } from "@/app/_components/ui/separator";
|
||||||
import { ScrollArea } from "@/app/_components/ui/scroll-area";
|
import { ScrollArea } from "@/app/_components/ui/scroll-area";
|
||||||
import { ThemeSwitcher } from "../../../../../_components/theme-switcher";
|
import { ThemeSwitcher } from "../../../../_components/theme-switcher";
|
||||||
import DropdownSwitcher from "../../../../../_components/custom-dropdown-switcher";
|
import DropdownSwitcher from "../../../../_components/custom-dropdown-switcher";
|
||||||
import {
|
import {
|
||||||
type CookiePreferences,
|
type CookiePreferences,
|
||||||
defaultCookiePreferences,
|
defaultCookiePreferences,
|
||||||
|
@ -21,7 +21,7 @@ import {
|
||||||
getAutoTimezonePreference,
|
getAutoTimezonePreference,
|
||||||
saveAutoTimezonePreference,
|
saveAutoTimezonePreference,
|
||||||
applyCookiePreferences,
|
applyCookiePreferences,
|
||||||
} from "@/utils/cookies-manager";
|
} from "@/app/_utils/cookies/cookies-manager";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { initialTimezones, TimezoneType } from "@/prisma/data/timezones";
|
import { initialTimezones, TimezoneType } from "@/prisma/data/timezones";
|
||||||
import { languages, LanguageType } from "@/prisma/data/languages";
|
import { languages, LanguageType } from "@/prisma/data/languages";
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import type React from "react";
|
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 { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
@ -31,7 +31,7 @@ import { ScrollArea } from "@/app/_components/ui/scroll-area";
|
||||||
import {
|
import {
|
||||||
updateUser,
|
updateUser,
|
||||||
uploadAvatar,
|
uploadAvatar,
|
||||||
} from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
} from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||||
|
|
||||||
const profileFormSchema = z.object({
|
const profileFormSchema = z.object({
|
||||||
username: z.string().nullable().optional(),
|
username: z.string().nullable().optional(),
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"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 { Button } from "@/app/_components/ui/button";
|
||||||
import { Separator } from "@/app/_components/ui/separator";
|
import { Separator } from "@/app/_components/ui/separator";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
@ -28,7 +28,7 @@ import {
|
||||||
IconUsers,
|
IconUsers,
|
||||||
IconWorld,
|
IconWorld,
|
||||||
} from "@tabler/icons-react";
|
} 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 { ProfileSettings } from "./profile-settings";
|
||||||
import { DialogTitle } from "@radix-ui/react-dialog";
|
import { DialogTitle } from "@radix-ui/react-dialog";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
|
@ -1,5 +1,5 @@
|
||||||
import { DateTimePicker2 } from "@/app/_components/ui/date-picker";
|
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";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export default async function DashboardPage() {
|
export default async function DashboardPage() {
|
|
@ -10,7 +10,7 @@ import {
|
||||||
import { Button } from "@/app/_components/ui/button";
|
import { Button } from "@/app/_components/ui/button";
|
||||||
import { Input } from "@/app/_components/ui/input";
|
import { Input } from "@/app/_components/ui/input";
|
||||||
import { Checkbox } from "@/app/_components/ui/checkbox";
|
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 { toast } from "sonner";
|
||||||
import { Mail, Lock, Loader2, X } from "lucide-react";
|
import { Mail, Lock, Loader2, X } from "lucide-react";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
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 { Input } from "@/app/_components/ui/input";
|
||||||
import { Textarea } from "@/app/_components/ui/textarea";
|
import { Textarea } from "@/app/_components/ui/textarea";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
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";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
interface InviteUserDialogProps {
|
interface InviteUserDialogProps {
|
|
@ -6,7 +6,7 @@ import { useState, useRef } from "react";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
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 {
|
import {
|
||||||
Form,
|
Form,
|
||||||
|
@ -27,7 +27,7 @@ import { Textarea } from "@/app/_components/ui/textarea";
|
||||||
import { Button } from "@/app/_components/ui/button";
|
import { Button } from "@/app/_components/ui/button";
|
||||||
import { Label } from "@/app/_components/ui/label";
|
import { Label } from "@/app/_components/ui/label";
|
||||||
import { ImageIcon, Loader2 } from "lucide-react";
|
import { ImageIcon, Loader2 } from "lucide-react";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/app/_utils/supabase/client";
|
||||||
|
|
||||||
// Profile update form schema
|
// Profile update form schema
|
||||||
const profileFormSchema = z.object({
|
const profileFormSchema = z.object({
|
|
@ -38,7 +38,7 @@ import {
|
||||||
sendMagicLink,
|
sendMagicLink,
|
||||||
sendPasswordRecovery,
|
sendPasswordRecovery,
|
||||||
unbanUser,
|
unbanUser,
|
||||||
} from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
} from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
|
||||||
interface UserDetailSheetProps {
|
interface UserDetailSheetProps {
|
|
@ -1,20 +1,15 @@
|
||||||
|
|
||||||
import type React from "react"
|
|
||||||
|
|
||||||
import { useState } from "react"
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod"
|
import { zodResolver } from "@hookform/resolvers/zod"
|
||||||
import { useForm } from "react-hook-form"
|
import { useForm } from "react-hook-form"
|
||||||
import type * as z from "zod"
|
import type * as z from "zod"
|
||||||
|
|
||||||
import { Loader2 } from "lucide-react"
|
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
|
// UI Components
|
||||||
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/app/_components/ui/sheet"
|
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/app/_components/ui/sheet"
|
||||||
import {
|
import { Form } from "@/app/_components/ui/form"
|
||||||
Form,
|
|
||||||
} from "@/app/_components/ui/form"
|
|
||||||
|
|
||||||
import { Button } from "@/app/_components/ui/button"
|
import { Button } from "@/app/_components/ui/button"
|
||||||
import { FormSection } from "@/app/_components/form-section"
|
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 { useMutation } from "@tanstack/react-query"
|
||||||
import { updateUser } from "../action"
|
import { updateUser } from "../action"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { DateTimePicker2 } from "@/app/_components/ui/date-picker"
|
|
||||||
|
|
||||||
|
|
||||||
type UserProfileFormValues = z.infer<typeof UpdateUserParamsSchema>
|
type UserProfileFormValues = z.infer<typeof UpdateUserParamsSchema>
|
||||||
|
|
||||||
|
@ -31,33 +24,33 @@ interface UserProfileSheetProps {
|
||||||
open: boolean
|
open: boolean
|
||||||
onOpenChange: (open: boolean) => void
|
onOpenChange: (open: boolean) => void
|
||||||
userData?: User
|
userData?: User
|
||||||
|
onUserUpdated: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSheetProps) {
|
export function UserProfileSheet({ open, onOpenChange, userData, onUserUpdated }: UserProfileSheetProps) {
|
||||||
const [isSaving, setIsSaving] = useState(false)
|
|
||||||
// Initialize form with user data
|
// Initialize form with user data
|
||||||
const form = useForm<UserProfileFormValues>({
|
const form = useForm<UserProfileFormValues>({
|
||||||
resolver: zodResolver(UpdateUserParamsSchema),
|
resolver: zodResolver(UpdateUserParamsSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
email: userData?.email || "",
|
email: userData?.email || undefined,
|
||||||
password_hash: userData?.password_hash || "",
|
encrypted_password: userData?.encrypted_password || undefined,
|
||||||
role: (userData?.role as "user" | "staff" | "admin") || "user",
|
role: (userData?.role as "user" | "staff" | "admin") || "user",
|
||||||
phone: userData?.phone || "",
|
phone: userData?.phone || undefined,
|
||||||
invited_at: userData?.invited_at || undefined,
|
invited_at: userData?.invited_at || undefined,
|
||||||
confirmed_at: userData?.confirmed_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,
|
last_sign_in_at: userData?.last_sign_in_at || undefined,
|
||||||
created_at: userData?.created_at || undefined,
|
created_at: userData?.created_at || undefined,
|
||||||
updated_at: userData?.updated_at || undefined,
|
updated_at: userData?.updated_at || undefined,
|
||||||
is_anonymous: userData?.is_anonymous || false,
|
is_anonymous: userData?.is_anonymous || false,
|
||||||
profile: {
|
profile: {
|
||||||
id: userData?.profile?.id || "",
|
id: userData?.profile?.id || undefined,
|
||||||
user_id: userData?.profile?.user_id || "",
|
user_id: userData?.profile?.user_id || undefined,
|
||||||
avatar: userData?.profile?.avatar || "",
|
avatar: userData?.profile?.avatar || undefined,
|
||||||
username: userData?.profile?.username || "",
|
username: userData?.profile?.username || undefined,
|
||||||
first_name: userData?.profile?.first_name || "",
|
first_name: userData?.profile?.first_name || undefined,
|
||||||
last_name: userData?.profile?.last_name || "",
|
last_name: userData?.profile?.last_name || undefined,
|
||||||
bio: userData?.profile?.bio || "",
|
bio: userData?.profile?.bio || undefined,
|
||||||
address: userData?.profile?.address || {
|
address: userData?.profile?.address || {
|
||||||
street: "",
|
street: "",
|
||||||
city: "",
|
city: "",
|
||||||
|
@ -74,27 +67,26 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
||||||
mutationKey: ["updateUser"],
|
mutationKey: ["updateUser"],
|
||||||
mutationFn: (data: UserProfileFormValues) => {
|
mutationFn: (data: UserProfileFormValues) => {
|
||||||
if (!userData?.id) {
|
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) => {
|
onError: (error) => {
|
||||||
toast("Failed to update user");
|
toast("Failed to update user")
|
||||||
|
onOpenChange(false)
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast("User updated");
|
toast("User updated")
|
||||||
|
onUserUpdated()
|
||||||
|
onOpenChange(false)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
async function onSubmit(data: UserProfileFormValues) {
|
async function onSubmit(data: UserProfileFormValues) {
|
||||||
try {
|
try {
|
||||||
setIsSaving(true)
|
|
||||||
await updateUserMutation(data)
|
await updateUserMutation(data)
|
||||||
onOpenChange(false)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error saving user profile:", 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"
|
title="User Information"
|
||||||
description="Update the user information below. Fields marked with an asterisk (*) are required."
|
description="Update the user information below. Fields marked with an asterisk (*) are required."
|
||||||
>
|
>
|
||||||
|
|
||||||
<FormFieldWrapper
|
<FormFieldWrapper
|
||||||
name="email"
|
name="email"
|
||||||
label="Email"
|
label="Email"
|
||||||
|
@ -149,19 +140,13 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
||||||
booleanType="select"
|
booleanType="select"
|
||||||
/>
|
/>
|
||||||
<FormFieldWrapper
|
<FormFieldWrapper
|
||||||
name="password_hash"
|
name="encrypted_password_hash"
|
||||||
label="Password Hash"
|
label="Encrypted_password Hash"
|
||||||
type="string"
|
type="string"
|
||||||
control={form.control}
|
control={form.control}
|
||||||
placeholder="Password Hash"
|
placeholder="Encrypted_password Hash"
|
||||||
/>
|
|
||||||
<FormFieldWrapper
|
|
||||||
name="invited_at"
|
|
||||||
label="Invited At"
|
|
||||||
type="date"
|
|
||||||
control={form.control}
|
|
||||||
isDate={true}
|
|
||||||
/>
|
/>
|
||||||
|
<FormFieldWrapper name="invited_at" label="Invited At" type="date" control={form.control} isDate={true} />
|
||||||
<FormFieldWrapper
|
<FormFieldWrapper
|
||||||
name="confirmed_at"
|
name="confirmed_at"
|
||||||
label="Confirmed At"
|
label="Confirmed At"
|
||||||
|
@ -183,21 +168,8 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
||||||
control={form.control}
|
control={form.control}
|
||||||
isDate={true}
|
isDate={true}
|
||||||
/>
|
/>
|
||||||
<FormFieldWrapper
|
<FormFieldWrapper name="created_at" label="Created At" type="date" control={form.control} isDate={true} />
|
||||||
name="created_at"
|
<FormFieldWrapper name="updated_at" label="Updated At" type="date" control={form.control} isDate={true} />
|
||||||
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>
|
</FormSection>
|
||||||
|
|
||||||
{/* Profile Information Section */}
|
{/* Profile Information Section */}
|
||||||
|
@ -288,11 +260,17 @@ export function UserProfileSheet({ open, onOpenChange, userData }: UserProfileSh
|
||||||
|
|
||||||
{/* Action Buttons */}
|
{/* Action Buttons */}
|
||||||
<div className="flex justify-end space-x-4">
|
<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
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="xs" type="submit" disabled={isPending}>
|
<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"}
|
{isPending ? "Saving..." : "Save"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
|
@ -26,8 +26,8 @@ import {
|
||||||
DropdownMenuCheckboxItem,
|
DropdownMenuCheckboxItem,
|
||||||
} from "@/app/_components/ui/dropdown-menu";
|
} from "@/app/_components/ui/dropdown-menu";
|
||||||
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
||||||
import { fetchUsers } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
import { fetchUsers } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||||
import type { User } from "@/src/models/users/users.model";
|
import type { User } from "@/src/entities/models/users/users.model";
|
||||||
import { DataTable } from "./data-table";
|
import { DataTable } from "./data-table";
|
||||||
import { InviteUserDialog } from "./invite-user";
|
import { InviteUserDialog } from "./invite-user";
|
||||||
import { AddUserDialog } from "./add-user-dialog";
|
import { AddUserDialog } from "./add-user-dialog";
|
||||||
|
@ -668,7 +668,7 @@ export default function UserManagement() {
|
||||||
open={isUpdateOpen}
|
open={isUpdateOpen}
|
||||||
onOpenChange={setIsUpdateOpen}
|
onOpenChange={setIsUpdateOpen}
|
||||||
userData={updateUser}
|
userData={updateUser}
|
||||||
|
onUserUpdated={() => refetch()}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
|
@ -3,8 +3,8 @@
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { Card, CardContent } from "@/app/_components/ui/card";
|
import { Card, CardContent } from "@/app/_components/ui/card";
|
||||||
import { Users, UserCheck, UserX } from "lucide-react";
|
import { Users, UserCheck, UserX } from "lucide-react";
|
||||||
import { fetchUsers } from "@/app/(protected)/(admin)/dashboard/user-management/action";
|
import { fetchUsers } from "@/app/(pages)/(admin)/dashboard/user-management/action";
|
||||||
import { User } from "@/src/models/users/users.model";
|
import { User } from "@/src/entities/models/users/users.model";
|
||||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
|
@ -1,15 +1,15 @@
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
import db from "@/lib/db";
|
import db from "@/prisma/db";
|
||||||
import {
|
import {
|
||||||
CreateUserParams,
|
CreateUserParams,
|
||||||
InviteUserParams,
|
InviteUserParams,
|
||||||
UpdateUserParams,
|
UpdateUserParams,
|
||||||
User,
|
User,
|
||||||
UserResponse,
|
UserResponse,
|
||||||
} from "@/src/models/users/users.model";
|
} from "@/src/entities/models/users/users.model";
|
||||||
import { createClient } from "@/utils/supabase/server";
|
import { createClient } from "@/app/_utils/supabase/server";
|
||||||
import { createAdminClient } from "@/utils/supabase/admin";
|
import { createAdminClient } from "@/app/_utils/supabase/admin";
|
||||||
|
|
||||||
// Initialize Supabase client with admin key
|
// Initialize Supabase client with admin key
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ export async function createUser(
|
||||||
|
|
||||||
const { data, error } = await supabase.auth.admin.createUser({
|
const { data, error } = await supabase.auth.admin.createUser({
|
||||||
email: params.email,
|
email: params.email,
|
||||||
password: params.password,
|
password: params.encrypted_password,
|
||||||
phone: params.phone,
|
phone: params.phone,
|
||||||
email_confirm: params.email_confirm,
|
email_confirm: params.email_confirm,
|
||||||
});
|
});
|
||||||
|
@ -163,8 +163,8 @@ export async function updateUser(
|
||||||
const { data, error } = await supabase.auth.admin.updateUserById(userId, {
|
const { data, error } = await supabase.auth.admin.updateUserById(userId, {
|
||||||
email: params.email,
|
email: params.email,
|
||||||
email_confirm: params.email_confirmed_at,
|
email_confirm: params.email_confirmed_at,
|
||||||
password: params.password_hash ?? undefined,
|
password: params.encrypted_password ?? undefined,
|
||||||
password_hash: params.password_hash ?? undefined,
|
password_hash: params.encrypted_password ?? undefined,
|
||||||
phone: params.phone,
|
phone: params.phone,
|
||||||
phone_confirm: params.phone_confirmed_at,
|
phone_confirm: params.phone_confirmed_at,
|
||||||
role: params.role,
|
role: params.role,
|
||||||
|
@ -196,13 +196,13 @@ export async function updateUser(
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
role: params.role || user.role,
|
role: params.role || user.role,
|
||||||
invited_at: params.invited_at || user.role,
|
invited_at: params.invited_at || user.invited_at,
|
||||||
confirmed_at: params.confirmed_at || user.role,
|
confirmed_at: params.confirmed_at || user.confirmed_at,
|
||||||
recovery_sent_at: params.recovery_sent_at || user.role,
|
// recovery_sent_at: params.recovery_sent_at || user.recovery_sent_at,
|
||||||
last_sign_in_at: params.last_sign_in_at || user.role,
|
last_sign_in_at: params.last_sign_in_at || user.last_sign_in_at,
|
||||||
is_anonymous: params.is_anonymous || user.is_anonymous,
|
is_anonymous: params.is_anonymous || user.is_anonymous,
|
||||||
created_at: params.created_at || user.role,
|
created_at: params.created_at || user.created_at,
|
||||||
updated_at: params.updated_at || user.role,
|
updated_at: params.updated_at || user.updated_at,
|
||||||
profile: {
|
profile: {
|
||||||
update: {
|
update: {
|
||||||
avatar: params.profile?.avatar || user.profile?.avatar,
|
avatar: params.profile?.avatar || user.profile?.avatar,
|
|
@ -1,5 +1,5 @@
|
||||||
import UserManagement from "@/app/(protected)/(admin)/dashboard/user-management/_components/user-management";
|
import UserManagement from "@/app/(pages)/(admin)/dashboard/user-management/_components/user-management";
|
||||||
import { UserStats } from "@/app/(protected)/(admin)/dashboard/user-management/_components/user-stats";
|
import { UserStats } from "@/app/(pages)/(admin)/dashboard/user-management/_components/user-stats";
|
||||||
|
|
||||||
export default function UsersPage() {
|
export default function UsersPage() {
|
||||||
return (
|
return (
|
|
@ -26,8 +26,8 @@ import { ThemeSwitcher } from "@/app/_components/theme-switcher";
|
||||||
import { Separator } from "@/app/_components/ui/separator";
|
import { Separator } from "@/app/_components/ui/separator";
|
||||||
import { InboxDrawer } from "@/app/_components/inbox-drawer";
|
import { InboxDrawer } from "@/app/_components/inbox-drawer";
|
||||||
import FloatingActionSearchBar from "@/app/_components/floating-action-search-bar";
|
import FloatingActionSearchBar from "@/app/_components/floating-action-search-bar";
|
||||||
import { AppSidebar } from "@/app/(protected)/(admin)/_components/admin/app-sidebar";
|
import { AppSidebar } from "@/app/(pages)/(admin)/_components/app-sidebar";
|
||||||
import { createClient } from "@/utils/supabase/server";
|
import { createClient } from "@/app/_utils/supabase/server";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export default async function Layout({
|
export default async function Layout({
|
|
@ -3,11 +3,11 @@
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { Lock } from "lucide-react";
|
import { Lock } from "lucide-react";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../../../_components/ui/button";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../../../_components/ui/input";
|
||||||
import { SubmitButton } from "../submit-button";
|
import { SubmitButton } from "../../../_components/submit-button";
|
||||||
import Link from "next/link";
|
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";
|
import { useSignInForm } from "@/src/controller/auth/sign-in-controller";
|
||||||
|
|
||||||
export function SignInForm({
|
export function SignInForm({
|
|
@ -23,7 +23,7 @@ import {
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/app/_components/ui/card";
|
} 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";
|
import { useVerifyOtpForm } from "@/src/controller/auth/verify-otp.controller";
|
||||||
|
|
||||||
interface VerifyOtpFormProps extends React.HTMLAttributes<HTMLDivElement> {}
|
interface VerifyOtpFormProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
@ -1,12 +1,12 @@
|
||||||
// src/app/(auth-pages)/actions.ts
|
// src/app/(auth)/actions.ts
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
import db from "@/lib/db";
|
import db from "@/prisma/db";
|
||||||
import { SignInFormData } from "@/src/models/auth/sign-in.model";
|
import { SignInFormData } from "@/src/entities/models/auth/sign-in.model";
|
||||||
import { VerifyOtpFormData } from "@/src/models/auth/verify-otp.model";
|
import { VerifyOtpFormData } from "@/src/entities/models/auth/verify-otp.model";
|
||||||
import { User } from "@/src/models/users/users.model";
|
import { User } from "@/src/entities/models/users/users.model";
|
||||||
import { authRepository } from "@/src/repositories/authentication.repository";
|
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";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export async function signIn(
|
export async function signIn(
|
|
@ -1,6 +1,6 @@
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { checkSession } from "./_actions/session";
|
import { checkSession } from "./_actions/session";
|
||||||
import { createClient } from "@/utils/supabase/client";
|
import { createClient } from "@/app/_utils/supabase/client";
|
||||||
|
|
||||||
export default async function Layout({
|
export default async function Layout({
|
||||||
children,
|
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 { Message } from "@/app/_components/form-message";
|
||||||
import { Button } from "@/app/_components/ui/button";
|
import { Button } from "@/app/_components/ui/button";
|
||||||
import { GalleryVerticalEnd, Globe } from "lucide-react";
|
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";
|
import { GalleryVerticalEnd } from "lucide-react";
|
||||||
|
|
||||||
export default async function VerifyOtpPage() {
|
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 { Geist } from "next/font/google";
|
||||||
import { ThemeProvider } from "next-themes";
|
import { ThemeProvider } from "next-themes";
|
||||||
import Link from "next/link";
|
import "@/app/_styles/globals.css";
|
||||||
import "./globals.css";
|
import ReactQueryProvider from "@/app/_lib/react-query-provider";
|
||||||
import ReactQueryProvider from "@/providers/react-query-provider";
|
|
||||||
import { Toaster } from "@/app/_components/ui/sonner";
|
import { Toaster } from "@/app/_components/ui/sonner";
|
||||||
|
|
||||||
const defaultUrl = process.env.VERCEL_URL
|
const defaultUrl = process.env.VERCEL_URL
|
|
@ -1,7 +1,7 @@
|
||||||
import Hero from "@/app/_components/hero";
|
import Hero from "@/app/_components/hero";
|
||||||
import ConnectSupabaseSteps from "@/app/_components/tutorial/connect-supabase-steps";
|
import ConnectSupabaseSteps from "@/app/_components/tutorial/connect-supabase-steps";
|
||||||
import SignUpUserSteps from "@/app/_components/tutorial/sign-up-user-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() {
|
export default async function Home() {
|
||||||
return (
|
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";
|
} from "@/app/_components/ui/dropdown-menu";
|
||||||
import { Badge } from "@/app/_components/ui/badge";
|
import { Badge } from "@/app/_components/ui/badge";
|
||||||
import { Input } from "@/app/_components/ui/input";
|
import { Input } from "@/app/_components/ui/input";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
|
|
||||||
type Option<T> = {
|
type Option<T> = {
|
||||||
value: T;
|
value: T;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { ChevronLeft, ChevronRight, Clock } from "lucide-react"
|
||||||
import { DayPicker } from "react-day-picker"
|
import { DayPicker } from "react-day-picker"
|
||||||
import { useVirtualizer } from "@tanstack/react-virtual"
|
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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/app/_components/ui/select"
|
||||||
import { Input } from "@/app/_components/ui/input"
|
import { Input } from "@/app/_components/ui/input"
|
||||||
import { Button } from "@/app/_components/ui/button"
|
import { Button } from "@/app/_components/ui/button"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use client"
|
"use client"
|
||||||
import { format } from "date-fns"
|
import { format } from "date-fns"
|
||||||
import { CalendarIcon, ChevronLeft, ChevronRight } from "lucide-react"
|
import { CalendarIcon, ChevronLeft, ChevronRight } from "lucide-react"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
// UI Components
|
// UI Components
|
||||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription } from "@/app/_components/ui/form"
|
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 Link from "next/link";
|
||||||
import { Badge } from "./ui/badge";
|
import { Badge } from "./ui/badge";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { createClient } from "@/utils/supabase/server";
|
import { createClient } from "@/app/_utils/supabase/server";
|
||||||
import { signOutAction } from "@/app/(auth-pages)/_actions/sign-out";
|
import { signOutAction } from "@/app/(pages)/(auth)/_actions/sign-out";
|
||||||
|
|
||||||
export default async function AuthButton() {
|
export default async function AuthButton() {
|
||||||
const supabase = await createClient();
|
const supabase = await createClient();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
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";
|
import { buttonVariants } from "@/app/_components/ui/button";
|
||||||
|
|
||||||
const AlertDialog = AlertDialogPrimitive.Root;
|
const AlertDialog = AlertDialogPrimitive.Root;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Avatar = React.forwardRef<
|
const Avatar = React.forwardRef<
|
||||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
|
|
||||||
const badgeVariants = cva(
|
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",
|
"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 { Slot } from "@radix-ui/react-slot"
|
||||||
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Breadcrumb = React.forwardRef<
|
const Breadcrumb = React.forwardRef<
|
||||||
HTMLElement,
|
HTMLElement,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as React from "react"
|
||||||
import { Slot } from "@radix-ui/react-slot"
|
import { Slot } from "@radix-ui/react-slot"
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const buttonVariants = cva(
|
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",
|
"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 { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { DayPicker } from "react-day-picker";
|
import { DayPicker } from "react-day-picker";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
import { buttonVariants } from "@/app/_components/ui/button";
|
import { buttonVariants } from "@/app/_components/ui/button";
|
||||||
|
|
||||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Card = React.forwardRef<
|
const Card = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react";
|
||||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
||||||
import { Check } from "lucide-react";
|
import { Check } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
|
|
||||||
const Checkbox = React.forwardRef<
|
const Checkbox = React.forwardRef<
|
||||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
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 { format, getMonth, getYear, setMonth, setYear, setHours, setMinutes, setSeconds } from "date-fns"
|
||||||
import { Calendar as CalendarIcon, Clock } from "lucide-react"
|
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 { Button } from "@/app/_components/ui/button"
|
||||||
import { Calendar } from "@/app/_components/ui/calendar"
|
import { Calendar } from "@/app/_components/ui/calendar"
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react";
|
||||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||||
import { X } from "lucide-react";
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
|
|
||||||
const Dialog = DialogPrimitive.Root;
|
const Dialog = DialogPrimitive.Root;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { Drawer as DrawerPrimitive } from "vaul"
|
import { Drawer as DrawerPrimitive } from "vaul"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Drawer = ({
|
const Drawer = ({
|
||||||
shouldScaleBackground = true,
|
shouldScaleBackground = true,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react";
|
||||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||||
import { Check, ChevronRight, Circle } from "lucide-react";
|
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
|
|
||||||
const DropdownMenu = DropdownMenuPrimitive.Root;
|
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
useFormContext,
|
useFormContext,
|
||||||
} from "react-hook-form";
|
} from "react-hook-form";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
import { Label } from "@/app/_components/ui/label";
|
import { Label } from "@/app/_components/ui/label";
|
||||||
|
|
||||||
const Form = FormProvider;
|
const Form = FormProvider;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react"
|
||||||
import { OTPInput, OTPInputContext } from "input-otp"
|
import { OTPInput, OTPInputContext } from "input-otp"
|
||||||
import { Dot } from "lucide-react"
|
import { Dot } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const InputOTP = React.forwardRef<
|
const InputOTP = React.forwardRef<
|
||||||
React.ElementRef<typeof OTPInput>,
|
React.ElementRef<typeof OTPInput>,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||||
({ className, type, ...props }, ref) => {
|
({ className, type, ...props }, ref) => {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react"
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const labelVariants = cva(
|
const labelVariants = cva(
|
||||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
"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 React from "react"
|
||||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Popover = PopoverPrimitive.Root
|
const Popover = PopoverPrimitive.Root
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/app/_lib/utils";
|
||||||
|
|
||||||
const ScrollArea = React.forwardRef<
|
const ScrollArea = React.forwardRef<
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from "react"
|
||||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||||
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Select = SelectPrimitive.Root
|
const Select = SelectPrimitive.Root
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Separator = React.forwardRef<
|
const Separator = React.forwardRef<
|
||||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
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 { cva, type VariantProps } from "class-variance-authority"
|
||||||
import { X } from "lucide-react"
|
import { X } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Sheet = SheetPrimitive.Root
|
const Sheet = SheetPrimitive.Root
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { VariantProps, cva } from "class-variance-authority";
|
||||||
import { PanelLeft } from "lucide-react";
|
import { PanelLeft } from "lucide-react";
|
||||||
|
|
||||||
import { useIsMobile } from "@/app/_hooks/use-mobile";
|
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 { Button } from "@/app/_components/ui/button";
|
||||||
import { Input } from "@/app/_components/ui/input";
|
import { Input } from "@/app/_components/ui/input";
|
||||||
import { Separator } from "@/app/_components/ui/separator";
|
import { Separator } from "@/app/_components/ui/separator";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
function Skeleton({
|
function Skeleton({
|
||||||
className,
|
className,
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Switch = React.forwardRef<
|
const Switch = React.forwardRef<
|
||||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Table = React.forwardRef<
|
const Table = React.forwardRef<
|
||||||
HTMLTableElement,
|
HTMLTableElement,
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Tabs = TabsPrimitive.Root
|
const Tabs = TabsPrimitive.Root
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const Textarea = React.forwardRef<
|
const Textarea = React.forwardRef<
|
||||||
HTMLTextAreaElement,
|
HTMLTextAreaElement,
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/app/_lib/utils"
|
||||||
|
|
||||||
const TooltipProvider = TooltipPrimitive.Provider
|
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";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
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 { type NextRequest } from "next/server";
|
||||||
import { updateSession } from "@/utils/supabase/middleware";
|
import { updateSession } from "@/app/_utils/supabase/middleware";
|
||||||
|
|
||||||
export async function middleware(request: NextRequest) {
|
export async function middleware(request: NextRequest) {
|
||||||
return await updateSession(request);
|
return await updateSession(request);
|
||||||
|
|
|
@ -7,11 +7,11 @@ import {
|
||||||
defaultSignInValues,
|
defaultSignInValues,
|
||||||
SignInFormData,
|
SignInFormData,
|
||||||
signInSchema,
|
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 { useState, type FormEvent, type ChangeEvent } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
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>>;
|
type SignInFormErrors = Partial<Record<keyof SignInFormData, string>>;
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,12 @@ import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
|
||||||
import { verifyOtp } from "@/app/(auth-pages)/action";
|
import { verifyOtp } from "@/app/(pages)/(auth)/action";
|
||||||
import {
|
import {
|
||||||
defaultVerifyOtpValues,
|
defaultVerifyOtpValues,
|
||||||
VerifyOtpFormData,
|
VerifyOtpFormData,
|
||||||
verifyOtpSchema,
|
verifyOtpSchema,
|
||||||
} from "@/src/models/auth/verify-otp.model";
|
} from "@/src/entities/models/auth/verify-otp.model";
|
||||||
import { useNavigations } from "@/app/_hooks/use-navigations";
|
import { useNavigations } from "@/app/_hooks/use-navigations";
|
||||||
import { toast } from "sonner";
|
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(),
|
role: z.string().optional(),
|
||||||
email: z.string().email().optional(),
|
email: z.string().email().optional(),
|
||||||
email_confirmed_at: z.union([z.string(), z.date()]).nullable().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(),
|
invited_at: z.union([z.string(), z.date()]).nullable().optional(),
|
||||||
phone: z.string().nullable().optional(),
|
phone: z.string().nullable().optional(),
|
||||||
confirmed_at: z.union([z.string(), z.date()]).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({
|
export const CreateUserParamsSchema = z.object({
|
||||||
email: z.string().email(),
|
email: z.string().email(),
|
||||||
password: z.string(),
|
encrypted_password: z.string(),
|
||||||
phone: z.string().optional(),
|
phone: z.string().optional(),
|
||||||
user_metadata: z.record(z.any()).optional(),
|
user_metadata: z.record(z.any()).optional(),
|
||||||
email_confirm: z.boolean().optional(),
|
email_confirm: z.boolean().optional(),
|
||||||
|
@ -95,13 +95,13 @@ export type CreateUserParams = z.infer<typeof CreateUserParamsSchema>;
|
||||||
export const UpdateUserParamsSchema = z.object({
|
export const UpdateUserParamsSchema = z.object({
|
||||||
email: z.string().email().optional(),
|
email: z.string().email().optional(),
|
||||||
email_confirmed_at: z.boolean().optional(),
|
email_confirmed_at: z.boolean().optional(),
|
||||||
password_hash: z.string().optional(),
|
encrypted_password: z.string().optional(),
|
||||||
role: z.enum(["user", "staff", "admin"]).optional(),
|
role: z.enum(["user", "staff", "admin"]).optional(),
|
||||||
phone: z.string().optional(),
|
phone: z.string().optional(),
|
||||||
phone_confirmed_at: z.boolean().optional(),
|
phone_confirmed_at: z.boolean().optional(),
|
||||||
invited_at: z.union([z.string(), z.date()]).optional(),
|
invited_at: z.union([z.string(), z.date()]).optional(),
|
||||||
confirmed_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(),
|
last_sign_in_at: z.union([z.string(), z.date()]).optional(),
|
||||||
created_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(),
|
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