diff --git a/prisma/migrations/20260430000000_restructure_career_description/migration.sql b/prisma/migrations/20260430000000_restructure_career_description/migration.sql new file mode 100644 index 0000000..1a247e7 --- /dev/null +++ b/prisma/migrations/20260430000000_restructure_career_description/migration.sql @@ -0,0 +1,51 @@ +-- Migration: restructure_career_description +-- Replaces the single `description` TEXT column with proper structured columns. +-- Includes a data migration that parses existing JSON descriptions into the new columns. + +-- Step 1: Add new columns (nullable first so existing rows don't fail) +ALTER TABLE "careers" + ADD COLUMN "about_role" TEXT NOT NULL DEFAULT '', + ADD COLUMN "responsibilities" TEXT[] NOT NULL DEFAULT '{}', + ADD COLUMN "nice_to_have" TEXT[] NOT NULL DEFAULT '{}', + ADD COLUMN "what_we_offer" TEXT[] NOT NULL DEFAULT '{}', + ADD COLUMN "how_to_apply" TEXT NOT NULL DEFAULT '', + ADD COLUMN "duration" TEXT; + +-- Step 2: Data migration — parse existing JSON descriptions into the new columns. +-- Rows that contain valid JSON with an "aboutRole" key are migrated field by field. +-- Rows with legacy plain text are moved into about_role as-is. +UPDATE "careers" +SET + "about_role" = CASE + WHEN description ~ '^\s*\{' AND description::jsonb ? 'aboutRole' + THEN (description::jsonb ->> 'aboutRole') + ELSE description + END, + "responsibilities" = CASE + WHEN description ~ '^\s*\{' AND description::jsonb ? 'responsibilities' + THEN ARRAY(SELECT jsonb_array_elements_text(description::jsonb -> 'responsibilities')) + ELSE '{}' + END, + "nice_to_have" = CASE + WHEN description ~ '^\s*\{' AND description::jsonb ? 'niceToHave' + THEN ARRAY(SELECT jsonb_array_elements_text(description::jsonb -> 'niceToHave')) + ELSE '{}' + END, + "what_we_offer" = CASE + WHEN description ~ '^\s*\{' AND description::jsonb ? 'whatWeOffer' + THEN ARRAY(SELECT jsonb_array_elements_text(description::jsonb -> 'whatWeOffer')) + ELSE '{}' + END, + "how_to_apply" = CASE + WHEN description ~ '^\s*\{' AND description::jsonb ? 'howToApply' + THEN (description::jsonb ->> 'howToApply') + ELSE '' + END, + "duration" = CASE + WHEN description ~ '^\s*\{' AND description::jsonb ? 'duration' + THEN NULLIF(description::jsonb ->> 'duration', '') + ELSE NULL + END; + +-- Step 3: Drop the old description column +ALTER TABLE "careers" DROP COLUMN "description"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4ce75e2..2ac8056 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -163,19 +163,24 @@ model NewsletterDeliveryLog { } model Career { - id Int @id @default(autoincrement()) - title String - company String @default("Codetopia") - type String - location String - description String @db.Text - requirements String[] - link String? - expiryDate DateTime @map("expiry_date") - isFeatured Boolean @default(false) @map("is_featured") - status String @default("open") - createdAt DateTime @default(now()) @map("created_at") - updatedAt DateTime @updatedAt @map("updated_at") + id Int @id @default(autoincrement()) + title String + company String @default("Codetopia") + type String + location String + aboutRole String @default("") @map("about_role") @db.Text + responsibilities String[] @map("responsibilities") + niceToHave String[] @map("nice_to_have") + whatWeOffer String[] @map("what_we_offer") + howToApply String @default("") @map("how_to_apply") @db.Text + duration String? + requirements String[] + link String? + expiryDate DateTime @map("expiry_date") + isFeatured Boolean @default(false) @map("is_featured") + status String @default("open") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") @@map("careers") } diff --git a/src/app/(site)/careers/[id]/page.tsx b/src/app/(site)/careers/[id]/page.tsx index baa5fd2..05bb8eb 100644 --- a/src/app/(site)/careers/[id]/page.tsx +++ b/src/app/(site)/careers/[id]/page.tsx @@ -5,11 +5,13 @@ import { Briefcase, Building2, Calendar, + CheckCircle2, Clock, MapPin, + Sparkles, Star, + Timer, } from "lucide-react"; -import { marked } from "marked"; import Link from "next/link"; import { notFound } from "next/navigation"; import { prisma } from "@/../prisma/prisma"; @@ -38,10 +40,7 @@ export default async function CareerDetailPage({ const daysLeft = differenceInDays(expiry, now); const isUrgent = daysLeft <= 7; - const descriptionHtml = await marked.parse(career.description, { - gfm: true, - breaks: true, - }); + const desc = career; return (
+ {desc.aboutRole} +
+ {desc.howToApply} +
+