From 7ca48dfc43c32dab6d66e77d49db6f3c8b628ed9 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 20 Dec 2024 11:54:08 +0700 Subject: [PATCH] feat: refresh for analytics --- .../src/api/routes/analytics.controller.ts | 4 -- .../src/api/routes/integrations.controller.ts | 2 +- .../components/launches/calendar.context.tsx | 2 +- .../launches/launches.component.tsx | 2 + .../src/components/launches/menu/menu.tsx | 33 ++++++++++++++- .../platform-analytics/render.analytics.tsx | 40 ++++++++++++++----- .../integrations/integration.service.ts | 25 +++++++++--- 7 files changed, 85 insertions(+), 23 deletions(-) diff --git a/apps/backend/src/api/routes/analytics.controller.ts b/apps/backend/src/api/routes/analytics.controller.ts index dbe35036..706be96a 100644 --- a/apps/backend/src/api/routes/analytics.controller.ts +++ b/apps/backend/src/api/routes/analytics.controller.ts @@ -15,9 +15,6 @@ import { StarsListDto } from '@gitroom/nestjs-libraries/dtos/analytics/stars.lis import { ApiTags } from '@nestjs/swagger'; import { IntegrationService } from '@gitroom/nestjs-libraries/database/prisma/integrations/integration.service'; import { IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager'; -import { ioRedis } from '@gitroom/nestjs-libraries/redis/redis.service'; -import { RefreshToken } from '@gitroom/nestjs-libraries/integrations/social.abstract'; -import { timer } from '@gitroom/helpers/utils/timer'; @ApiTags('Analytics') @Controller('/analytics') @@ -25,7 +22,6 @@ export class AnalyticsController { constructor( private _starsService: StarsService, private _integrationService: IntegrationService, - private _integrationManager: IntegrationManager ) {} @Get('/') async getStars(@GetOrgFromRequest() org: Organization) { diff --git a/apps/backend/src/api/routes/integrations.controller.ts b/apps/backend/src/api/routes/integrations.controller.ts index ae587603..abb4de6e 100644 --- a/apps/backend/src/api/routes/integrations.controller.ts +++ b/apps/backend/src/api/routes/integrations.controller.ts @@ -444,7 +444,7 @@ export class IntegrationsController { throw new NotEnoughScopes('Invalid API key'); } - if (refresh && id !== refresh) { + if (refresh && String(id) !== String(refresh)) { throw new NotEnoughScopes( 'Please refresh the channel that needs to be refreshed' ); diff --git a/apps/frontend/src/components/launches/calendar.context.tsx b/apps/frontend/src/components/launches/calendar.context.tsx index 574981f4..c4c6a702 100644 --- a/apps/frontend/src/components/launches/calendar.context.tsx +++ b/apps/frontend/src/components/launches/calendar.context.tsx @@ -29,7 +29,7 @@ export const CalendarContext = createContext({ currentYear: dayjs().year(), currentMonth: dayjs().month(), comments: [] as Array<{ date: string; total: number }>, - integrations: [] as Integrations[], + integrations: [] as (Integrations & {refreshNeeded?: boolean})[], trendings: [] as string[], posts: [] as Array, reloadCalendarView: () => { diff --git a/apps/frontend/src/components/launches/launches.component.tsx b/apps/frontend/src/components/launches/launches.component.tsx index cf528836..5eb95a46 100644 --- a/apps/frontend/src/components/launches/launches.component.tsx +++ b/apps/frontend/src/components/launches/launches.component.tsx @@ -101,6 +101,7 @@ export const MenuComponent: FC< identifier: string; changeProfilePicture: boolean; changeNickName: boolean; + refreshNeeded?: boolean; }; } > = (props) => { @@ -201,6 +202,7 @@ export const MenuComponent: FC< () => void; id: string; mutate: () => void; onChange: (shouldReload: boolean) => void; @@ -27,6 +31,7 @@ export const Menu: FC<{ mutate, canChangeProfilePicture, canChangeNickName, + refreshChannel } = props; const fetch = useFetch(); const { integrations } = useCalendar(); @@ -37,6 +42,10 @@ export const Menu: FC<{ setShow(false); }); + const findIntegration: any = useMemo(() => { + return integrations.find((integration) => integration.id === id); + }, [integrations, id]); + const changeShow: MouseEventHandler = useCallback( (e) => { e.stopPropagation(); @@ -194,6 +203,28 @@ export const Menu: FC<{ onClick={(e) => e.stopPropagation()} className={`absolute top-[100%] left-0 p-[8px] px-[20px] bg-fifth flex flex-col gap-[16px] z-[100] rounded-[8px] border border-tableBorder ${interClass} text-nowrap`} > + {canDisable && findIntegration?.refreshNeeded && ( +
+
+ + + +
+
Refresh channel
+
+ )} {(canChangeProfilePicture || canChangeNickName) && (
= ( revalidateOnMount: true, }); + const refreshChannel = useCallback( + (integration: Integration & { identifier: string }) => async () => { + const { url } = await ( + await fetch( + `/integrations/social/${integration.identifier}?refresh=${integration.internalId}`, + { + method: 'GET', + } + ) + ).json(); + + window.location.href = url; + }, + [] + ); + const total = useMemo(() => { - return data?.map( - (p: any) => { - const value = (p?.data.reduce((acc: number, curr: any) => acc + curr.total, 0) || 0) / - (p.average ? p.data.length : 1); + return data?.map((p: any) => { + const value = + (p?.data.reduce((acc: number, curr: any) => acc + curr.total, 0) || 0) / + (p.average ? p.data.length : 1); - if (p.average) { - return value.toFixed(2) + '%'; - } - - return value; + if (p.average) { + return value.toFixed(2) + '%'; } - ); + + return value; + }); }, [data]); if (loading) { @@ -58,7 +73,10 @@ export const RenderAnalytics: FC<{ integration: Integration; date: number }> = ( return (
{data?.length === 0 && ( -
This channel needs to be refreshed
+
+ This channel needs to be refreshed,{' '} +
click here to refresh
+
)} {data?.map((p: any, index: number) => (
diff --git a/libraries/nestjs-libraries/src/database/prisma/integrations/integration.service.ts b/libraries/nestjs-libraries/src/database/prisma/integrations/integration.service.ts index f2306dba..ae4cccb0 100644 --- a/libraries/nestjs-libraries/src/database/prisma/integrations/integration.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/integrations/integration.service.ts @@ -5,6 +5,7 @@ import { InstagramProvider } from '@gitroom/nestjs-libraries/integrations/social import { FacebookProvider } from '@gitroom/nestjs-libraries/integrations/social/facebook.provider'; import { AnalyticsData, + AuthTokenDetails, SocialProvider, } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface'; import { Integration, Organization } from '@prisma/client'; @@ -329,7 +330,21 @@ export class IntegrationService { forceRefresh ) { const { accessToken, expiresIn, refreshToken } = - await integrationProvider.refreshToken(getIntegration.refreshToken!); + await new Promise((res) => { + return integrationProvider + .refreshToken(getIntegration.refreshToken!) + .then((r) => res(r)) + .catch(() => { + res({ + error: '', + accessToken: '', + id: '', + name: '', + picture: '', + username: '', + }); + }); + }); if (accessToken) { await this.createOrUpdateIntegration( @@ -380,7 +395,7 @@ export class IntegrationService { return loadAnalytics; } catch (e) { if (e instanceof RefreshToken) { - return this.checkAnalytics(org, integration, date); + return this.checkAnalytics(org, integration, date, true); } } } @@ -408,7 +423,7 @@ export class IntegrationService { }) { const getPlugById = await this._integrationRepository.getPlug(data.plugId); if (!getPlugById) { - return ; + return; } const integration = this._integrationManager.getSocialIntegration( @@ -434,11 +449,11 @@ export class IntegrationService { ); if (process) { - return ; + return; } if (data.totalRuns === data.currentRun) { - return ; + return; } this._workerServiceProducer.emit('plugs', {