Create API endpoint to save profile updates
cgen-1527d4c3e77a4b4791fb5efc924554cb
This commit is contained in:
parent
becbf850c8
commit
e6f685df85
2 changed files with 199 additions and 0 deletions
106
api/user/arm-affiliations.ts
Normal file
106
api/user/arm-affiliations.ts
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import { supabase } from "../_supabase";
|
||||
|
||||
const VALID_ARMS = ["foundation", "gameforge", "labs", "corp", "devlink"];
|
||||
const VALID_TYPES = ["courses", "projects", "research", "opportunities", "manual"];
|
||||
|
||||
export default async (req: Request) => {
|
||||
try {
|
||||
const authHeader = req.headers.get("Authorization");
|
||||
if (!authHeader?.startsWith("Bearer ")) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
const token = authHeader.slice(7);
|
||||
const { data: userData } = await supabase.auth.getUser(token);
|
||||
|
||||
if (!userData.user) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
const userId = userData.user.id;
|
||||
|
||||
// GET - Fetch user's arm affiliations
|
||||
if (req.method === "GET") {
|
||||
const { data, error } = await supabase
|
||||
.from("user_arm_affiliations")
|
||||
.select("*")
|
||||
.eq("user_id", userId)
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
if (error) {
|
||||
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify(data), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
// POST - Add or confirm arm affiliation
|
||||
if (req.method === "POST") {
|
||||
const body = await req.json();
|
||||
const { arm, affiliation_type, affiliation_data, confirmed } = body;
|
||||
|
||||
if (!VALID_ARMS.includes(arm) || !VALID_TYPES.includes(affiliation_type)) {
|
||||
return new Response("Invalid arm or affiliation type", { status: 400 });
|
||||
}
|
||||
|
||||
// Upsert to handle duplicates
|
||||
const { data, error } = await supabase
|
||||
.from("user_arm_affiliations")
|
||||
.upsert(
|
||||
{
|
||||
user_id: userId,
|
||||
arm,
|
||||
affiliation_type,
|
||||
affiliation_data: affiliation_data || {},
|
||||
confirmed: confirmed === true,
|
||||
},
|
||||
{ onConflict: "user_id,arm,affiliation_type" }
|
||||
)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify(data), {
|
||||
status: 201,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - Remove arm affiliation
|
||||
if (req.method === "DELETE") {
|
||||
const body = await req.json();
|
||||
const { arm, affiliation_type } = body;
|
||||
|
||||
if (!VALID_ARMS.includes(arm)) {
|
||||
return new Response("Invalid arm", { status: 400 });
|
||||
}
|
||||
|
||||
const { error } = await supabase
|
||||
.from("user_arm_affiliations")
|
||||
.delete()
|
||||
.eq("user_id", userId)
|
||||
.eq("arm", arm)
|
||||
.eq("affiliation_type", affiliation_type || null);
|
||||
|
||||
if (error) {
|
||||
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
return new Response("Method not allowed", { status: 405 });
|
||||
} catch (error: any) {
|
||||
console.error("Arm affiliations error:", error);
|
||||
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||
}
|
||||
};
|
||||
93
api/user/profile-update.ts
Normal file
93
api/user/profile-update.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import { supabase } from "../_supabase";
|
||||
|
||||
export default async (req: Request) => {
|
||||
if (req.method !== "PUT" && req.method !== "POST") {
|
||||
return new Response("Method not allowed", { status: 405 });
|
||||
}
|
||||
|
||||
try {
|
||||
const authHeader = req.headers.get("Authorization");
|
||||
if (!authHeader?.startsWith("Bearer ")) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
const token = authHeader.slice(7);
|
||||
const { data: userData } = await supabase.auth.getUser(token);
|
||||
|
||||
if (!userData.user) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const userId = userData.user.id;
|
||||
|
||||
// Sanitize and validate input
|
||||
const updates: any = {};
|
||||
|
||||
// Profile fields
|
||||
if ("bio_detailed" in body) updates.bio_detailed = body.bio_detailed || null;
|
||||
if ("twitter_url" in body) updates.twitter_url = body.twitter_url || null;
|
||||
if ("linkedin_url" in body) updates.linkedin_url = body.linkedin_url || null;
|
||||
if ("github_url" in body) updates.github_url = body.github_url || null;
|
||||
if ("portfolio_url" in body) updates.portfolio_url = body.portfolio_url || null;
|
||||
if ("youtube_url" in body) updates.youtube_url = body.youtube_url || null;
|
||||
if ("twitch_url" in body) updates.twitch_url = body.twitch_url || null;
|
||||
|
||||
// Professional info
|
||||
if ("hourly_rate" in body)
|
||||
updates.hourly_rate = body.hourly_rate ? parseFloat(body.hourly_rate) : null;
|
||||
if ("availability_status" in body)
|
||||
updates.availability_status =
|
||||
["available", "limited", "unavailable"].includes(body.availability_status) ?
|
||||
body.availability_status : "available";
|
||||
if ("timezone" in body) updates.timezone = body.timezone || null;
|
||||
if ("location" in body) updates.location = body.location || null;
|
||||
|
||||
// Arrays
|
||||
if ("languages" in body) {
|
||||
updates.languages = Array.isArray(body.languages) ? body.languages : [];
|
||||
}
|
||||
if ("skills_detailed" in body) {
|
||||
updates.skills_detailed = Array.isArray(body.skills_detailed) ? body.skills_detailed : [];
|
||||
}
|
||||
if ("work_experience" in body) {
|
||||
updates.work_experience = Array.isArray(body.work_experience) ? body.work_experience : [];
|
||||
}
|
||||
if ("portfolio_items" in body) {
|
||||
updates.portfolio_items = Array.isArray(body.portfolio_items) ? body.portfolio_items : [];
|
||||
}
|
||||
if ("arm_affiliations" in body) {
|
||||
const validArms = ["foundation", "gameforge", "labs", "corp", "devlink"];
|
||||
updates.arm_affiliations = Array.isArray(body.arm_affiliations) ?
|
||||
body.arm_affiliations.filter((a: string) => validArms.includes(a)) : [];
|
||||
}
|
||||
|
||||
// Nexus specific
|
||||
if ("nexus_profile_complete" in body) updates.nexus_profile_complete = body.nexus_profile_complete === true;
|
||||
if ("nexus_headline" in body) updates.nexus_headline = body.nexus_headline || null;
|
||||
if ("nexus_categories" in body) {
|
||||
updates.nexus_categories = Array.isArray(body.nexus_categories) ? body.nexus_categories : [];
|
||||
}
|
||||
|
||||
// Update the profile
|
||||
const { data, error } = await supabase
|
||||
.from("user_profiles")
|
||||
.update(updates)
|
||||
.eq("id", userId)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error("Profile update error:", error);
|
||||
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify(data), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error("Profile update error:", error);
|
||||
return new Response(JSON.stringify({ error: error.message }), { status: 500 });
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue