Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DO $$ BEGIN
CREATE TYPE "public"."fiat_provider" AS ENUM('monnify', 'flutterwave');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

ALTER TABLE "organizations"
ADD COLUMN IF NOT EXISTS "provider_preference" "fiat_provider" DEFAULT 'monnify' NOT NULL;
1 change: 1 addition & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { join } from "path";

const nextConfig: NextConfig = {
compress: true,
serverExternalPackages: ["ioredis"],
turbopack: {
root: join(__dirname), // Set the root to the current directory dynamically
rules: {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"google-auth-library": "^10.5.0",
"html2canvas": "^1.4.1",
"i18n-iso-countries": "^7.14.0",
"ioredis": "^5.10.1",
"jose": "^6.1.3",
"jsonwebtoken": "^9.0.3",
"jspdf": "^3.0.3",
Expand Down
67 changes: 67 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/app/api/v1/auth/register/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ describe("POST /api/v1/auth/register", () => {
firstName: "Test",
lastName: "User",
businessEmail: "test@example.com",
password: "Password123",
agreement: true,
});

const response = await POST(req);
Expand All @@ -46,6 +48,8 @@ describe("POST /api/v1/auth/register", () => {
firstName: "Test",
lastName: "User",
businessEmail: "invalid-email",
password: "Password123",
agreement: true,
});

const response = await POST(req);
Expand All @@ -60,6 +64,8 @@ describe("POST /api/v1/auth/register", () => {
const req = createMockRequest({
firstName: "T",
businessEmail: "test@example.com",
password: "Password123",
agreement: true,
});

const response = await POST(req);
Expand All @@ -79,6 +85,8 @@ describe("POST /api/v1/auth/register", () => {
firstName: "Test",
lastName: "User",
businessEmail: "existing@example.com",
password: "Password123",
agreement: true,
});

const response = await POST(req);
Expand All @@ -96,6 +104,8 @@ describe("POST /api/v1/auth/register", () => {
firstName: "Test",
lastName: "User",
businessEmail: "test@example.com",
password: "Password123",
agreement: true,
});

const response = await POST(req);
Expand Down
72 changes: 72 additions & 0 deletions src/app/api/v1/company/profile/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ApiResponse } from "@/server/utils/api-response";
import { AppError } from "@/server/utils/errors";
import { AuthUtils } from "@/server/utils/auth";
import { CompanyService } from "@/server/services/company.service";
import { updateCompanyProfileSchema } from "@/server/validations/company.schema";

/**
* @swagger
Expand All @@ -29,6 +30,9 @@ import { CompanyService } from "@/server/services/company.service";
* registrationNumber:
* type: string
* nullable: true
* providerPreference:
* type: string
* enum: [monnify, flutterwave]
* registered:
* type: object
* properties:
Expand Down Expand Up @@ -90,3 +94,71 @@ export async function GET(req: NextRequest) {
return ApiResponse.error("Internal server error", 500);
}
}

/**
* @swagger
* /company/profile:
* put:
* summary: Update company profile
* description: Update the authenticated user's organization profile and fiat provider preference
* tags: [General]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* name:
* type: string
* industry:
* type: string
* nullable: true
* registrationNumber:
* type: string
* nullable: true
* providerPreference:
* type: string
* enum: [monnify, flutterwave]
* registered:
* type: object
* billing:
* type: object
* responses:
* 200:
* description: Company profile updated successfully
* 400:
* description: Invalid request body
* 401:
* description: Unauthorized
* 404:
* description: User not associated with an organization
*/
export async function PUT(req: NextRequest) {
try {
const { userId } = await AuthUtils.authenticateRequest(req);
const payload = await req.json();

Comment on lines +142 to +143
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

req.json() can throw on malformed JSON, but the PUT handler currently treats this as an internal error and returns 500. Wrap JSON parsing and return a 400 response for malformed JSON (consistent with other API routes like auth/forgot-password).

Suggested change
const payload = await req.json();
let payload: unknown;
try {
payload = await req.json();
} catch (parseError) {
// Handle malformed JSON bodies as a client error (400)
console.error("[Update Company Profile Error] Malformed JSON body", parseError);
return ApiResponse.error("Invalid request body", 400);
}

Copilot uses AI. Check for mistakes.
const parsed = updateCompanyProfileSchema.safeParse(payload);
if (!parsed.success) {
return ApiResponse.error(
"Invalid request body",
400,
parsed.error.flatten().fieldErrors,
);
}

const profile = await CompanyService.updateCompanyProfile(userId, parsed.data);

return ApiResponse.success(profile, "Company profile updated successfully");
} catch (error) {
if (error instanceof AppError) {
return ApiResponse.error(error.message, error.statusCode, error.errors);
}

console.error("[Update Company Profile Error]", error);
return ApiResponse.error("Internal server error", 500);
}
}
Loading
Loading