Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OUT-46 Integrate APIs #11

Merged
merged 29 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0bf24d9
data plotting of table
aatbip Jan 31, 2024
de90790
data plotting of table
aatbip Jan 31, 2024
3236564
integrated custom field access and save apis
aatbip Feb 1, 2024
f0b535f
fix custom field access issues
aatbip Feb 2, 2024
77c70f6
added client api
aatbip Feb 2, 2024
9460e0a
added manage page
aatbip Feb 2, 2024
38d9b69
added history popup
aatbip Feb 2, 2024
ff7c3b1
added sorting feature
aatbip Feb 5, 2024
3b763f3
added searching feature
aatbip Feb 5, 2024
5c884ec
added searching for all fields
aatbip Feb 5, 2024
ef9cfdc
added chip color variations
aatbip Feb 5, 2024
3a5e5b0
fix bug
aatbip Feb 5, 2024
5804da2
added empty state fallback
aatbip Feb 5, 2024
abdf684
fix bug
aatbip Feb 5, 2024
c45c6ac
fix design issues
aatbip Feb 5, 2024
692d55c
fix design issues
aatbip Feb 5, 2024
f3e7e65
adds tooltip on disabled field
aatbip Feb 6, 2024
7e1f923
removed image if company image icon is not present
aatbip Feb 6, 2024
795574b
fix bugs
aatbip Feb 6, 2024
1e57eb9
added enums for ProfileLinks
aatbip Feb 8, 2024
ea24ab7
added enums for Permissions
aatbip Feb 8, 2024
d0ed649
removed unnecessary if/else comparisions
aatbip Feb 8, 2024
06f2a26
adds server action
aatbip Feb 8, 2024
c0e3213
fix issue with server action
aatbip Feb 8, 2024
8ebda6a
fix issue with server action
aatbip Feb 8, 2024
abb68f7
added token and portalId
aatbip Feb 8, 2024
361cb7e
stringified in client component
aatbip Feb 8, 2024
b6d7909
stringified in client component
aatbip Feb 8, 2024
414bff3
reverted from server action for now
aatbip Feb 8, 2024
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
17 changes: 13 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
COPILOT_API_KEY=""
POSTGRES_PRISMA_URL=""
POSTGRES_URL_NON_POOLING=""
COPILOT_API_KEY="b4fa0b79be594f91a2c72c63216d45ec.6463d9dc556351b6"

# Vercel Database
POSTGRES_PRISMA_URL="postgres://default:2tCAVY7Npmyc@ep-morning-mountain-74331247-pooler.us-east-1.postgres.vercel-storage.com/verceldb?pgbouncer=true&connect_timeout=15"
POSTGRES_URL_NON_POOLING="postgres://default:2tCAVY7Npmyc@ep-morning-mountain-74331247.us-east-1.postgres.vercel-storage.com/verceldb"
aatbip marked this conversation as resolved.
Show resolved Hide resolved

# Local Database
; POSTGRES_PRISMA_URL="postgresql://db:[email protected]:59004/db?schema=public"
; POSTGRES_URL_NON_POOLING="postgresql://db:[email protected]:59004/db?schema=public"
aatbip marked this conversation as resolved.
Show resolved Hide resolved

COPILOT_API_URL="https://api-beta.copilot.com"
COPILOT_ENV="local"
COPILOT_API_URL=""
VERCEL_URL="localhost:3000"
VERCEL_ENV="development"
20 changes: 11 additions & 9 deletions src/app/api/client-profile-updates/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,19 @@ export async function GET(request: NextRequest) {
const client = clientLookup[update.clientId];
const company = companyLookup[update.companyId];

const customFields = portalCustomFields.data?.map((portalCustomField) => {
let parsedClientProfileUpdate: ParsedClientProfileUpdatesResponse = {
id: update.id,
client: getClientDetails(client),
company: getCompanyDetails(company),
lastUpdated: update.createdAt,
};

portalCustomFields.data?.forEach((portalCustomField) => {
const value = update.customFields[portalCustomField.key] ?? null;
const options = getSelectedOptions(portalCustomField, value);

return {
// @ts-ignore
parsedClientProfileUpdate[portalCustomField.name] = {
name: portalCustomField.name,
type: portalCustomField.type,
key: portalCustomField.key,
Expand All @@ -83,13 +91,7 @@ export async function GET(request: NextRequest) {
};
});

return {
id: update.id,
client: getClientDetails(client),
company: getCompanyDetails(company),
lastUpdated: update.createdAt,
customFields,
};
return parsedClientProfileUpdate;
});

return NextResponse.json(parsedClientProfileUpdates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export class ClientProfileUpdatesService {
WHERE "clientId" = ${clientId}::uuid
AND "createdAt" <= ${lastUpdated}
AND "changedFields" ->> ${customFieldKey} IS NOT NULL
ORDER BY "createdAt" DESC;
ORDER BY "createdAt" DESC
LIMIT 5;
`;
}
}
25 changes: 25 additions & 0 deletions src/app/api/client/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { respondError } from '@/utils/common';
import { CopilotAPI } from '@/utils/copilotApiUtils';
import { NextResponse, NextRequest } from 'next/server';
import { z } from 'zod';

export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const clientId = searchParams.get('clientId');
const token = searchParams.get('token');
if (!token) {
return respondError('Missing token', 422);
}
if (!clientId) {
respondError('Missing client Id', 422);
}
const copilotClient = new CopilotAPI(z.string().parse(token));

Choose a reason for hiding this comment

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

why this is not inside try/catch?

try {
const client = await copilotClient.getClient(z.string().parse(clientId));

return NextResponse.json({ data: client });
} catch (error) {
console.log(error);
return respondError('Client not found.', 404);
}
}
6 changes: 5 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import './globals.css';
import ThemeRegistry from './ThemeRegistry';
import { AppContextProvider } from '@/context';
import { ToggleDecider } from '@/hoc/ToggleDecider';
import { Footer } from '@/layouts/Footer';

const inter = Inter({ subsets: ['latin'] });

Expand All @@ -18,7 +19,10 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<AppContextProvider>
<body className={inter.className}>
<ThemeRegistry options={{ key: 'mui' }}>
<ToggleDecider>{children}</ToggleDecider>
<ToggleDecider>
{children}
<Footer />
</ToggleDecider>
</ThemeRegistry>
</body>
</AppContextProvider>
Expand Down
81 changes: 72 additions & 9 deletions src/app/manage/page.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,90 @@
import { Box, Stack, Typography } from '@mui/material';
import { ManagePageContainer } from './views/ManagePageContainer';
import { SimpleButton } from '@/components/styled/SimpleButton';
import { apiUrl } from '@/config';
import { CustomFieldAccessResponse } from '@/types/customFieldAccess';

export const revalidate = 0;

async function getSettings({ token, portalId }: { token: string; portalId: string }) {
const res = await fetch(`${apiUrl}/api/settings?token=${token}&portalId=${portalId}`);

if (!res.ok) {
throw new Error('Something went wrong in getSettings');
}

const { data } = await res.json();

return data;
}

async function getCustomFieldAccess({
token,
portalId,
}: {
token: string;
portalId: string;
}): Promise<CustomFieldAccessResponse> {
const res = await fetch(`${apiUrl}/api/custom-field-access?token=${token}&portalId=${portalId}`);

if (!res.ok) {
throw new Error('Something went wrong in getCustomFieldAccess');
}

const { data } = await res.json();

return data;
}

async function getClient(clientId: string, token: string) {
const res = await fetch(`${apiUrl}/api/client?clientId=${clientId}&token=${token}`);
if (!res.ok) {
throw new Error(`No client found with '${token}' token`);
}
const { data } = await res.json();
return data;
}

export default async function ManagePage({ searchParams }: { searchParams: { token: string; portalId: string } }) {
const { token, portalId } = searchParams;

const settings = await getSettings({ token, portalId }).then((s) => s.profileLinks);
const customFieldAccess = await getCustomFieldAccess({ token, portalId });
// static for now, will be dynamic later after some API decisions are made
const clientId = 'a583a0d0-de70-4d14-8bb1-0aacf7424e2c';
const companyId = '52eb75a9-2790-4e37-aa7a-c13f7bc3aa91';
const client = await getClient(clientId, token);

export default function ManagePage() {
return (
<Box
sx={{
padding: { xs: '32px 16px', md: '124px 236px' },
padding: { xs: '32px 16px', md: '90px 236px' },
}}
>
<Typography variant="xl">Manage your profile</Typography>

<ManagePageContainer />
<ManagePageContainer
customFieldAccess={customFieldAccess}
client={client}
token={token}
companyId={companyId}
clientId={clientId}
portalId={portalId}
/>

<Stack direction="column" mt={16} rowGap={4}>
<Typography variant="xl">Other settings</Typography>
<Stack direction="row" columnGap={4}>
<SimpleButton>
<Typography variant="md">Set a payment method</Typography>
</SimpleButton>
<SimpleButton>
<Typography variant="md">Go to account settings</Typography>
</SimpleButton>
{settings && settings.includes('profile_settings') && (
<SimpleButton>
<Typography variant="md">Set a payment method</Typography>
</SimpleButton>
)}
{settings && settings.includes('payment_method') && (
<SimpleButton>
<Typography variant="md">Go to account settings</Typography>
</SimpleButton>
)}
</Stack>
</Stack>
</Box>
Expand Down
Loading
Loading