feat: implement internal auth user creation and update related functionalities

This commit is contained in:
Poyraz Avsever
2026-06-14 12:41:00 +03:00
parent 8fa89168c3
commit b1620d4748
19 changed files with 382 additions and 129 deletions
+5 -6
View File
@@ -5,6 +5,7 @@ import {
type ProjectFinanceItem,
type ProjectPlanningSectionItem,
} from "@/app/(dashboard)/projects/[id]/project-detail-client";
import { createServiceRoleClient } from "@/lib/supabase/admin";
import { createClient } from "@/lib/supabase/server";
import { notFound } from "next/navigation";
@@ -105,7 +106,7 @@ export default async function ProjectDetailPage({
const projectData = projectRow as unknown as ProjectRow;
const coverImageUrl = projectData.cover_image_path
? await createProjectImageUrl(supabase, projectData.cover_image_path)
? await createProjectImageUrl(projectData.cover_image_path)
: null;
const project: ProjectDetail = {
@@ -165,11 +166,9 @@ export default async function ProjectDetailPage({
);
}
async function createProjectImageUrl(
supabase: Awaited<ReturnType<typeof createClient>>,
path: string,
) {
const { data } = await supabase.storage
async function createProjectImageUrl(path: string) {
const admin = createServiceRoleClient();
const { data } = await admin.storage
.from("project-assets")
.createSignedUrl(path, 60 * 15);
+3 -5
View File
@@ -1,6 +1,7 @@
"use server";
import { createClient } from "@/lib/supabase/server";
import { createServiceRoleClient } from "@/lib/supabase/admin";
import { randomUUID } from "crypto";
import { revalidatePath } from "next/cache";
@@ -114,12 +115,10 @@ function sanitizeFileName(name: string) {
}
async function uploadCoverImage({
supabase,
userId,
projectId,
formData,
}: {
supabase: Awaited<ReturnType<typeof createClient>>;
userId: string;
projectId: string;
formData: FormData;
@@ -132,7 +131,8 @@ async function uploadCoverImage({
const fileName = `${Date.now()}-${sanitizeFileName(file.name) || "cover-image"}`;
const path = `${userId}/projects/${projectId}/${fileName}`;
const { error } = await supabase.storage
const admin = createServiceRoleClient();
const { error } = await admin.storage
.from(PROJECT_ASSETS_BUCKET)
.upload(path, file, {
cacheControl: "3600",
@@ -157,7 +157,6 @@ export async function createProjectRecord(formData: FormData) {
}
const coverImagePath = await uploadCoverImage({
supabase,
userId,
projectId,
formData,
@@ -187,7 +186,6 @@ export async function updateProjectRecord(formData: FormData) {
}
const coverImagePath = await uploadCoverImage({
supabase,
userId,
projectId: id,
formData,
+3 -3
View File
@@ -4,6 +4,7 @@ import {
type ProjectListItem,
} from "@/app/(dashboard)/projects/projects-client";
import { createClient } from "@/lib/supabase/server";
import { createServiceRoleClient } from "@/lib/supabase/admin";
type ProjectRow = {
id: string;
@@ -59,7 +60,6 @@ export default async function ProjectsPage() {
const taskStats = countTasksByProject((taskRows || []) as TaskRow[]);
const clients = (clientRows || []) as ProjectClientOption[];
const signedUrls = await createProjectImageUrls(
supabase,
((projectRows || []) as unknown as ProjectRow[])
.map((project) => project.cover_image_path)
.filter(Boolean) as string[],
@@ -93,15 +93,15 @@ export default async function ProjectsPage() {
}
async function createProjectImageUrls(
supabase: Awaited<ReturnType<typeof createClient>>,
paths: string[],
) {
const admin = createServiceRoleClient();
const urls = new Map<string, string>();
const uniquePaths = Array.from(new Set(paths));
await Promise.all(
uniquePaths.map(async (path) => {
const { data } = await supabase.storage
const { data } = await admin.storage
.from("project-assets")
.createSignedUrl(path, 60 * 15);
+13 -10
View File
@@ -19,6 +19,7 @@ import {
SelectItem,
SelectTrigger,
SelectValue,
toast,
} from "poyraz-ui/molecules";
import {
CalendarDays,
@@ -398,6 +399,13 @@ function ProjectDialog({
try {
await action(formData);
setOpen(false);
toast.success(mode === "create" ? "Proje eklendi." : "Proje güncellendi.");
} catch (error) {
toast.error(
error instanceof Error
? error.message
: "Proje kaydedilirken beklenmeyen bir hata oluştu.",
);
} finally {
setIsSubmitting(false);
}
@@ -506,14 +514,6 @@ function CoverImageInput({ project }: { project?: ProjectListItem }) {
</div>
)}
<div>
<div>
< ImageIcon className="h-6 w-6" />
</div>
</div>
{previewUrl ? (
<div className="absolute inset-x-0 bottom-0 bg-background/90 px-3 py-2 text-xs text-muted-foreground backdrop-blur">
Görseli değiştirmek için tıkla.
@@ -788,8 +788,11 @@ function AIProjectRiskDialog({ projectId }: { projectId?: string }) {
throw new Error(data.error || "Bilinmeyen bir hata oluştu.");
}
setResult(data.text);
} catch (err: any) {
setResult("Hata: " + err.message);
} catch (err) {
setResult(
"Hata: " +
(err instanceof Error ? err.message : "Bilinmeyen bir hata oluştu."),
);
} finally {
setLoading(false);
}