generated from pagevamp/copilot-custom-app-starter-kit
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature client profile updates api (#10)
* update client profile * save client profile updates ongoing * save ongoing * update profile ongoing * fetch updates ongoing * parse updates ongoing * changed db * custom field access changes * save updates * get updates * profile update history ongoing * update history ongoing * update history order fix * clean migrations * settings * cleanup * Bug fixes and PR changes * setting changes
- Loading branch information
1 parent
4a93d1b
commit e5dab64
Showing
24 changed files
with
561 additions
and
58 deletions.
There are no files selected for viewing
5 changes: 0 additions & 5 deletions
5
prisma/migrations/20240122084806_change_custom_field_access_table/migration.sql
This file was deleted.
Oops, something went wrong.
13 changes: 0 additions & 13 deletions
13
prisma/migrations/20240122105731_change_custom_field_access_table/migration.sql
This file was deleted.
Oops, something went wrong.
10 changes: 0 additions & 10 deletions
10
prisma/migrations/20240122135813_change_custom_field_access_table/migration.sql
This file was deleted.
Oops, something went wrong.
11 changes: 6 additions & 5 deletions
11
...e_custom_field_access_table/migration.sql → ...e_custom_field_access_table/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
-- CreateEnum | ||
CREATE TYPE "Permission" AS ENUM ('VIEW', 'EDIT'); | ||
|
||
-- CreateTable | ||
CREATE TABLE "CustomFieldAccess" ( | ||
"id" UUID NOT NULL DEFAULT gen_random_uuid(), | ||
"customFieldId" UUID, | ||
"permissions" JSONB, | ||
"customFieldId" UUID NOT NULL, | ||
"portalId" TEXT NOT NULL, | ||
"permissions" "Permission"[], | ||
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updatedAt" TIMESTAMPTZ NOT NULL, | ||
|
||
CONSTRAINT "CustomFieldAccess_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "CustomFieldAccess_customFieldId_key" ON "CustomFieldAccess"("customFieldId"); |
12 changes: 12 additions & 0 deletions
12
prisma/migrations/20240127105945_create_client_profile_updates_table/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
-- CreateTable | ||
CREATE TABLE "ClientProfileUpdates" ( | ||
"id" UUID NOT NULL DEFAULT gen_random_uuid(), | ||
"clientId" UUID NOT NULL, | ||
"companyId" UUID NOT NULL, | ||
"customFields" JSONB NOT NULL, | ||
"changedFields" JSONB NOT NULL, | ||
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updatedAt" TIMESTAMPTZ NOT NULL, | ||
|
||
CONSTRAINT "ClientProfileUpdates_pkey" PRIMARY KEY ("id") | ||
); |
10 changes: 10 additions & 0 deletions
10
prisma/migrations/20240127115634_create_setting_table/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
-- CreateTable | ||
CREATE TABLE "Setting" ( | ||
"id" UUID NOT NULL DEFAULT gen_random_uuid(), | ||
"portalId" TEXT NOT NULL, | ||
"profileLinks" JSONB NOT NULL, | ||
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updatedAt" TIMESTAMPTZ NOT NULL, | ||
|
||
CONSTRAINT "Setting_pkey" PRIMARY KEY ("id") | ||
); |
8 changes: 8 additions & 0 deletions
8
prisma/migrations/20240129075218_add_portal_id_to_client_profile_updates_table/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
Warnings: | ||
- Added the required column `portalId` to the `ClientProfileUpdates` table without a default value. This is not possible if the table is not empty. | ||
*/ | ||
-- AlterTable | ||
ALTER TABLE "ClientProfileUpdates" ADD COLUMN "portalId" TEXT NOT NULL; |
10 changes: 10 additions & 0 deletions
10
prisma/migrations/20240129090605_rename_column_in_setting_table/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
Warnings: | ||
- You are about to drop the column `profileLinks` on the `Setting` table. All the data in the column will be lost. | ||
- Added the required column `data` to the `Setting` table without a default value. This is not possible if the table is not empty. | ||
*/ | ||
-- AlterTable | ||
ALTER TABLE "Setting" DROP COLUMN "profileLinks", | ||
ADD COLUMN "data" JSONB NOT NULL; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import { ClientProfileUpdatesRequestSchema, ParsedClientProfileUpdatesResponse } from '@/types/clientProfileUpdates'; | ||
import { CopilotAPI } from '@/utils/copilotApiUtils'; | ||
import { handleError, respondError } from '@/utils/common'; | ||
import { ClientProfileUpdatesService } from '@/app/api/client-profile-updates/services/clientProfileUpdates.service'; | ||
import { ClientResponse, CompanyResponse } from '@/types/common'; | ||
import { z } from 'zod'; | ||
import { createLookup, getObjectDifference, getSelectedOptions } from '@/lib/helper'; | ||
|
||
export async function POST(request: NextRequest) { | ||
const data = await request.json(); | ||
const clientProfileUpdateRequest = ClientProfileUpdatesRequestSchema.safeParse(data); | ||
if (!clientProfileUpdateRequest.success) { | ||
return NextResponse.json(clientProfileUpdateRequest.error.issues, { status: 422 }); | ||
} | ||
try { | ||
//todo: check access | ||
const copilotClient = new CopilotAPI(clientProfileUpdateRequest.data.token); | ||
const client: ClientResponse = await copilotClient.getClient(clientProfileUpdateRequest.data.clientId); | ||
const clientUpdateResponse = await copilotClient.updateClient(clientProfileUpdateRequest.data.clientId, { | ||
customFields: clientProfileUpdateRequest.data.form, | ||
}); | ||
const changedFields = getObjectDifference(clientUpdateResponse.customFields ?? {}, client.customFields ?? {}); | ||
if (Object.keys(changedFields).length === 0) { | ||
return NextResponse.json({}); | ||
} | ||
|
||
const service = new ClientProfileUpdatesService(); | ||
await service.save({ | ||
clientId: clientProfileUpdateRequest.data.clientId, | ||
companyId: clientProfileUpdateRequest.data.companyId, | ||
portalId: clientProfileUpdateRequest.data.portalId, | ||
customFields: clientUpdateResponse.customFields ?? {}, | ||
changedFields, | ||
}); | ||
|
||
return NextResponse.json({}); | ||
} catch (error) { | ||
return handleError(error); | ||
} | ||
} | ||
|
||
export async function GET(request: NextRequest) { | ||
const token = request.nextUrl.searchParams.get('token'); | ||
const portalId = request.nextUrl.searchParams.get('portalId'); | ||
|
||
if (!token) { | ||
return respondError('Missing token', 422); | ||
} | ||
if (!portalId) { | ||
return respondError('Missing portalId', 422); | ||
} | ||
|
||
try { | ||
const copilotClient = new CopilotAPI(z.string().parse(token)); | ||
|
||
const [currentUser, clients, companies, portalCustomFields] = await Promise.all([ | ||
copilotClient.me(), | ||
copilotClient.getClients(), | ||
copilotClient.getCompanies(), | ||
copilotClient.getCustomFields(), | ||
]); | ||
//todo:: filter companyIds based on currentUser restrictions | ||
const clientProfileUpdates = await new ClientProfileUpdatesService().findMany(portalId, []); | ||
|
||
const clientLookup = createLookup(clients.data, 'id'); | ||
const companyLookup = createLookup(companies.data, 'id'); | ||
|
||
const parsedClientProfileUpdates: ParsedClientProfileUpdatesResponse[] = clientProfileUpdates.map((update) => { | ||
const client = clientLookup[update.clientId]; | ||
const company = companyLookup[update.companyId]; | ||
|
||
const customFields = portalCustomFields.data?.map((portalCustomField) => { | ||
const value = update.customFields[portalCustomField.key] ?? null; | ||
const options = getSelectedOptions(portalCustomField, value); | ||
|
||
return { | ||
name: portalCustomField.name, | ||
type: portalCustomField.type, | ||
key: portalCustomField.key, | ||
value: options.length > 0 ? options : value, | ||
isChanged: !!update.changedFields[portalCustomField.key], | ||
}; | ||
}); | ||
|
||
return { | ||
id: update.id, | ||
client: getClientDetails(client), | ||
company: getCompanyDetails(company), | ||
lastUpdated: update.createdAt, | ||
customFields, | ||
}; | ||
}); | ||
|
||
return NextResponse.json(parsedClientProfileUpdates); | ||
} catch (error) { | ||
return handleError(error); | ||
} | ||
} | ||
|
||
function getClientDetails(client: ClientResponse) { | ||
return { | ||
id: client.id, | ||
name: `${client.givenName} ${client.familyName}`, | ||
email: client.email, | ||
avatarImageUrl: client.avatarImageUrl, | ||
}; | ||
} | ||
|
||
function getCompanyDetails(company: CompanyResponse) { | ||
return { | ||
id: company.id, | ||
name: company.name, | ||
iconImageUrl: company.iconImageUrl, | ||
}; | ||
} |
58 changes: 58 additions & 0 deletions
58
src/app/api/client-profile-updates/services/clientProfileUpdates.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { PrismaClient } from '@prisma/client'; | ||
import DBClient from '@/lib/db'; | ||
import { | ||
ClientProfileUpdates, | ||
ClientProfileUpdatesResponse, | ||
ClientProfileUpdatesResponseSchema, | ||
UpdateHistory, | ||
} from '@/types/clientProfileUpdates'; | ||
|
||
export class ClientProfileUpdatesService { | ||
private prismaClient: PrismaClient = DBClient.getInstance(); | ||
|
||
async save(requestData: ClientProfileUpdates): Promise<void> { | ||
await this.prismaClient.clientProfileUpdates.create({ | ||
data: { | ||
clientId: requestData.clientId, | ||
companyId: requestData.companyId, | ||
portalId: requestData.portalId, | ||
customFields: requestData.customFields, | ||
changedFields: requestData.changedFields, | ||
}, | ||
}); | ||
} | ||
|
||
// Company Filter is not applied if companyIds is empty | ||
async findMany(portalId: string, companyIds: Array<string>): Promise<ClientProfileUpdatesResponse> { | ||
let clientProfileUpdates = []; | ||
if (companyIds.length > 0) { | ||
clientProfileUpdates = await this.prismaClient.clientProfileUpdates.findMany({ | ||
where: { | ||
portalId: portalId, | ||
companyId: { | ||
in: companyIds, | ||
}, | ||
}, | ||
}); | ||
} else { | ||
clientProfileUpdates = await this.prismaClient.clientProfileUpdates.findMany({ | ||
where: { | ||
portalId: portalId, | ||
}, | ||
}); | ||
} | ||
|
||
return ClientProfileUpdatesResponseSchema.parse(clientProfileUpdates); | ||
} | ||
|
||
async getUpdateHistory(customFieldKey: string, clientId: string, lastUpdated: Date): Promise<UpdateHistory[]> { | ||
return this.prismaClient.$queryRaw` | ||
SELECT "changedFields" | ||
FROM "ClientProfileUpdates" | ||
WHERE "clientId" = ${clientId}::uuid | ||
AND "createdAt" <= ${lastUpdated} | ||
AND "changedFields" ->> ${customFieldKey} IS NOT NULL | ||
ORDER BY "createdAt" DESC; | ||
`; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.