AeThex-OS/temp-forge-extract/aethex-forge-main/api/applications.ts
MrPiglr b3c308b2c8 Add functional marketplace modules, bottom nav bar, root terminal, arcade games
- ModuleManager: Central tracking for installed marketplace modules
- DataAnalyzerWidget: Real-time CPU/RAM/Battery/Storage widget (unlocked by Data Analyzer module)
- BottomNavBar: Navigation bar for Projects/Chat/Marketplace/Settings
- RootShell: Real root command execution utility
- TerminalActivity: Full root shell with neofetch, sysinfo, real Linux commands
- Terminal Pro module: Adds aliases (ll, la, h), command history
- ArcadeActivity + SnakeGame: Pixel Arcade module unlocks retro games
- fade_in/fade_out animations for smooth transitions
2026-02-18 22:03:50 -07:00

348 lines
9.2 KiB
TypeScript

import { createClient } from "@supabase/supabase-js";
const supabaseUrl = process.env.VITE_SUPABASE_URL || "";
const supabaseServiceRole = process.env.SUPABASE_SERVICE_ROLE || "";
const supabase = createClient(supabaseUrl, supabaseServiceRole);
export async function getMyApplications(req: Request, userId: string) {
const url = new URL(req.url);
const page = parseInt(url.searchParams.get("page") || "1");
const limit = parseInt(url.searchParams.get("limit") || "10");
const status = url.searchParams.get("status");
try {
// Get creator ID for this user
const { data: creator } = await supabase
.from("aethex_creators")
.select("id")
.eq("user_id", userId)
.single();
if (!creator) {
return new Response(
JSON.stringify({ error: "Creator profile not found" }),
{ status: 404, headers: { "Content-Type": "application/json" } },
);
}
let query = supabase
.from("aethex_applications")
.select(
`
id,
creator_id,
opportunity_id,
status,
cover_letter,
response_message,
applied_at,
updated_at,
aethex_opportunities(id, title, arm_affiliation, job_type, posted_by_id, aethex_creators!aethex_opportunities_posted_by_id_fkey(username, avatar_url))
`,
{ count: "exact" },
)
.eq("creator_id", creator.id);
if (status) {
query = query.eq("status", status);
}
query = query.order("applied_at", { ascending: false });
const start = (page - 1) * limit;
query = query.range(start, start + limit - 1);
const { data, error, count } = await query;
if (error) throw error;
return new Response(
JSON.stringify({
data,
pagination: {
page,
limit,
total: count || 0,
pages: Math.ceil((count || 0) / limit),
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
},
);
} catch (error) {
console.error("Error fetching applications:", error);
return new Response(
JSON.stringify({ error: "Failed to fetch applications" }),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
}
export async function getApplicationsForOpportunity(
opportunityId: string,
userId: string,
) {
try {
// Verify user owns this opportunity
const { data: opportunity } = await supabase
.from("aethex_opportunities")
.select("posted_by_id")
.eq("id", opportunityId)
.single();
if (!opportunity) {
return new Response(JSON.stringify({ error: "Opportunity not found" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}
const { data: creator } = await supabase
.from("aethex_creators")
.select("id")
.eq("user_id", userId)
.single();
if (creator?.id !== opportunity.posted_by_id) {
return new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 403,
headers: { "Content-Type": "application/json" },
});
}
const { data, error } = await supabase
.from("aethex_applications")
.select(
`
id,
creator_id,
status,
cover_letter,
applied_at,
aethex_creators(username, avatar_url, bio, skills)
`,
)
.eq("opportunity_id", opportunityId)
.order("applied_at", { ascending: false });
if (error) throw error;
return new Response(JSON.stringify({ data }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error("Error fetching opportunity applications:", error);
return new Response(
JSON.stringify({ error: "Failed to fetch applications" }),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
}
export async function submitApplication(req: Request, userId: string) {
try {
const body = (await req.json()) as {
opportunity_id?: string;
cover_letter?: string;
};
const { opportunity_id, cover_letter } = body;
// Get creator ID for this user
const { data: creator } = await supabase
.from("aethex_creators")
.select("id")
.eq("user_id", userId)
.single();
if (!creator) {
return new Response(
JSON.stringify({ error: "Creator profile not found" }),
{ status: 404, headers: { "Content-Type": "application/json" } },
);
}
// Check if opportunity exists and is open
const { data: opportunity } = await supabase
.from("aethex_opportunities")
.select("id")
.eq("id", opportunity_id)
.eq("status", "open")
.single();
if (!opportunity) {
return new Response(
JSON.stringify({ error: "Opportunity not found or closed" }),
{ status: 404, headers: { "Content-Type": "application/json" } },
);
}
// Check if already applied
const { data: existing } = await supabase
.from("aethex_applications")
.select("id")
.eq("creator_id", creator.id)
.eq("opportunity_id", opportunity_id)
.single();
if (existing) {
return new Response(
JSON.stringify({
error: "You have already applied to this opportunity",
}),
{ status: 400, headers: { "Content-Type": "application/json" } },
);
}
const { data, error } = await supabase
.from("aethex_applications")
.insert({
creator_id: creator.id,
opportunity_id,
cover_letter,
status: "submitted",
})
.select()
.single();
if (error) throw error;
return new Response(JSON.stringify(data), {
status: 201,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error("Error submitting application:", error);
return new Response(
JSON.stringify({ error: "Failed to submit application" }),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
}
export async function updateApplicationStatus(
req: Request,
applicationId: string,
userId: string,
) {
try {
const body = await req.json();
const { status, response_message } = body;
// Get the application and verify user owns the opportunity
const { data: application } = await supabase
.from("aethex_applications")
.select(
`
id,
opportunity_id,
aethex_opportunities(posted_by_id)
`,
)
.eq("id", applicationId)
.single();
if (!application) {
return new Response(JSON.stringify({ error: "Application not found" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}
const { data: creator } = await supabase
.from("aethex_creators")
.select("id")
.eq("user_id", userId)
.single();
const opportunityData = Array.isArray(application.aethex_opportunities)
? application.aethex_opportunities[0]
: application.aethex_opportunities;
if (creator?.id !== opportunityData?.posted_by_id) {
return new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 403,
headers: { "Content-Type": "application/json" },
});
}
const { data, error } = await supabase
.from("aethex_applications")
.update({
status,
response_message,
updated_at: new Date().toISOString(),
})
.eq("id", applicationId)
.select()
.single();
if (error) throw error;
return new Response(JSON.stringify(data), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error("Error updating application:", error);
return new Response(
JSON.stringify({ error: "Failed to update application" }),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
}
export async function withdrawApplication(
applicationId: string,
userId: string,
) {
try {
// Verify user owns this application
const { data: application } = await supabase
.from("aethex_applications")
.select("creator_id")
.eq("id", applicationId)
.single();
if (!application) {
return new Response(JSON.stringify({ error: "Application not found" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}
const { data: creator } = await supabase
.from("aethex_creators")
.select("id")
.eq("user_id", userId)
.single();
if (creator?.id !== application.creator_id) {
return new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 403,
headers: { "Content-Type": "application/json" },
});
}
const { error } = await supabase
.from("aethex_applications")
.delete()
.eq("id", applicationId);
if (error) throw error;
return new Response(JSON.stringify({ success: true }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error("Error withdrawing application:", error);
return new Response(
JSON.stringify({ error: "Failed to withdraw application" }),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
}