diff --git a/apps/backend/src/api/routes/billing.controller.ts b/apps/backend/src/api/routes/billing.controller.ts index 8c30c1b8..9913f30f 100644 --- a/apps/backend/src/api/routes/billing.controller.ts +++ b/apps/backend/src/api/routes/billing.controller.ts @@ -33,7 +33,7 @@ export class BillingController { return this._stripeService.subscribe(org.id, body); } - @Post('/modify') + @Get('/portal') async modifyPayment(@GetOrgFromRequest() org: Organization) { const customer = await this._stripeService.getCustomerByOrganizationId( org.id diff --git a/apps/backend/src/api/routes/integrations.controller.ts b/apps/backend/src/api/routes/integrations.controller.ts index dd4bd8e1..10b0149a 100644 --- a/apps/backend/src/api/routes/integrations.controller.ts +++ b/apps/backend/src/api/routes/integrations.controller.ts @@ -132,6 +132,7 @@ export class IntegrationsController { throw new Error('Invalid api key'); } + console.log('asd'); return this._integrationService.createOrUpdateIntegration( org.id, name, diff --git a/apps/frontend/src/app/global.css b/apps/frontend/src/app/global.css index 1b874d79..e8e06b4a 100644 --- a/apps/frontend/src/app/global.css +++ b/apps/frontend/src/app/global.css @@ -278,3 +278,6 @@ html { font-size: 20px !important; font-weight: 400 !important; } +.auto-width { + width: auto !important; +} \ No newline at end of file diff --git a/apps/frontend/src/components/analytics/stars.and.forks.tsx b/apps/frontend/src/components/analytics/stars.and.forks.tsx index 4c2c01d8..79cf75f6 100644 --- a/apps/frontend/src/components/analytics/stars.and.forks.tsx +++ b/apps/frontend/src/components/analytics/stars.and.forks.tsx @@ -1,8 +1,7 @@ import { FC } from 'react'; import { StarsAndForksInterface } from '@gitroom/frontend/components/analytics/stars.and.forks.interface'; import { Chart } from '@gitroom/frontend/components/analytics/chart'; -import Image from 'next/image'; -import { UtcToLocalDateRender } from '../../../../../libraries/react-shared-libraries/src/helpers/utc.date.render'; +import { UtcToLocalDateRender } from '@gitroom/react/helpers/utc.date.render'; import clsx from 'clsx'; export const StarsAndForks: FC = (props) => { @@ -11,47 +10,91 @@ export const StarsAndForks: FC = (props) => { <> {list.map((item) => (
- {[1, 2].map((p) => ( -
-
-
- Stars +
+
+ + -
-
- {item.login - .split('/')[1] - .split('') - .map((char, index) => - index === 0 ? char.toUpperCase() : char - ) - .join('')}{' '} - {p === 1 ? 'Stars' : 'Forks'} -
+
-
-
- {item.stars.length ? ( - - ) : ( -
- Processing stars... -
- )} -
-
-
- {item?.stars[item.stars.length - 1]?.totalStars} +
+ {item.login + .split('/')[1] + .split('') + .map((char, index) => + index === 0 ? char.toUpperCase() : char + ) + .join('')}{' '} + Stars
- ))} +
+
+ {item.stars.length ? ( + + ) : ( +
+ Processing stars... +
+ )} +
+
+
+ {item?.stars[item.stars.length - 1]?.totalStars} +
+
+ +
+
+
+ + + +
+
+ {item.login + .split('/')[1] + .split('') + .map((char, index) => + index === 0 ? char.toUpperCase() : char + ) + .join('')}{' '} + Forks +
+
+
+
+ {item.stars.length ? ( + + ) : ( +
+ Processing stars... +
+ )} +
+
+
+ {item?.stars[item.stars.length - 1]?.totalStars} +
+
))}
@@ -61,13 +104,34 @@ export const StarsAndForks: FC = (props) => { className="flex-1 bg-secondary py-[24px] px-[16px] gap-[16px] flex flex-col" >
-
- Trending +
+ {p === 0 ? ( + + + + ) : ( + + + + )}
{p === 0 diff --git a/apps/frontend/src/components/billing/billing.component.tsx b/apps/frontend/src/components/billing/billing.component.tsx index b1b3a824..9ff5cca0 100644 --- a/apps/frontend/src/components/billing/billing.component.tsx +++ b/apps/frontend/src/components/billing/billing.component.tsx @@ -1,10 +1,10 @@ 'use client'; -import {useCallback, useEffect, useState} from 'react'; -import { NoBillingComponent } from '@gitroom/frontend/components/billing/no.billing.component'; +import { useCallback } from 'react'; import useSWR from 'swr'; import { LoadingComponent } from '@gitroom/frontend/components/layout/loading'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; +import { MainBillingComponent } from './main.billing.component'; export const BillingComponent = () => { const fetch = useFetch(); @@ -26,5 +26,7 @@ export const BillingComponent = () => { return ; } - return ; + return ( + + ); }; diff --git a/apps/frontend/src/components/billing/no.billing.component.tsx b/apps/frontend/src/components/billing/main.billing.component.tsx similarity index 95% rename from apps/frontend/src/components/billing/no.billing.component.tsx rename to apps/frontend/src/components/billing/main.billing.component.tsx index 02cf4974..a303be93 100644 --- a/apps/frontend/src/components/billing/no.billing.component.tsx +++ b/apps/frontend/src/components/billing/main.billing.component.tsx @@ -150,7 +150,7 @@ export const Features: FC<{ ); }; -export const NoBillingComponent: FC<{ +export const MainBillingComponent: FC<{ tiers: Tiers; sub?: Subscription; }> = (props) => { @@ -191,6 +191,11 @@ export const NoBillingComponent: FC<{ setSubscription(sub); }, [sub]); + const updatePayment = useCallback(async () => { + const { portal } = await (await fetch('/billing/portal')).json(); + window.location.href = portal; + }, []); + const currentPackage = useMemo(() => { if (!subscription) { return 'FREE'; @@ -226,9 +231,7 @@ export const NoBillingComponent: FC<{ const beforeTotalChannels = pricing[billing].channel || initialChannels; if (totalChannels < beforeTotalChannels) { - messages.push( - `Some of the channels will be disabled` - ); + messages.push(`Some of the channels will be disabled`); } if ( @@ -244,7 +247,9 @@ export const NoBillingComponent: FC<{ if ( subscription?.cancelAt || (await deleteDialog( - `Are you sure you want to cancel your subscription? ${messages.join(', ')}`, + `Are you sure you want to cancel your subscription? ${messages.join( + ', ' + )}`, 'Yes, cancel', 'Cancel Subscription' )) @@ -266,8 +271,11 @@ export const NoBillingComponent: FC<{ return; } - if (messages.length && !await deleteDialog(messages.join(', '), 'Yes, continue')) { - return ; + if ( + messages.length && + !(await deleteDialog(messages.join(', '), 'Yes, continue')) + ) { + return; } setLoading(true); @@ -419,6 +427,11 @@ export const NoBillingComponent: FC<{
))}
+ {!!subscription?.id && ( +
+ +
+ )}
); diff --git a/apps/frontend/src/components/launches/add.provider.component.tsx b/apps/frontend/src/components/launches/add.provider.component.tsx index 7761209f..795de7cf 100644 --- a/apps/frontend/src/components/launches/add.provider.component.tsx +++ b/apps/frontend/src/components/launches/add.provider.component.tsx @@ -1,7 +1,7 @@ 'use client'; import { useModals } from '@mantine/modals'; -import { FC, useCallback } from 'react'; +import React, { FC, useCallback } from 'react'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; import { Input } from '@gitroom/react/form/input'; import { FieldValues, FormProvider, useForm } from 'react-hook-form'; @@ -9,34 +9,43 @@ import { Button } from '@gitroom/react/form/button'; import { classValidatorResolver } from '@hookform/resolvers/class-validator'; import { ApiKeyDto } from '@gitroom/nestjs-libraries/dtos/integrations/api.key.dto'; import { useRouter } from 'next/navigation'; +import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component'; const resolver = classValidatorResolver(ApiKeyDto); -export const useAddProvider = () => { +export const useAddProvider = (update?: () => void) => { const modal = useModals(); const fetch = useFetch(); return useCallback(async () => { const data = await (await fetch('/integrations')).json(); modal.openModal({ - title: 'Add Channel', - children: , + title: '', + withCloseButton: false, + classNames: { + modal: 'bg-transparent text-white', + }, + children: , + size: 'auto', }); }, []); }; -export const AddProviderButton = () => { - const add = useAddProvider(); +export const AddProviderButton: FC<{ update?: () => void }> = (props) => { + const { update } = props; + const add = useAddProvider(update); return ( - ); }; -export const ApiModal: FC<{ identifier: string; name: string }> = (props) => { +export const ApiModal: FC<{ + identifier: string; + name: string; + update?: () => void; +}> = (props) => { + const { update, name } = props; const fetch = useFetch(); const router = useRouter(); const modal = useModals(); @@ -45,6 +54,10 @@ export const ApiModal: FC<{ identifier: string; name: string }> = (props) => { resolver, }); + const close = useCallback(() => { + modal.closeAll(); + }, []); + const submit = useCallback(async (data: FieldValues) => { const add = await fetch( `/integrations/article/${props.identifier}/connect`, @@ -57,6 +70,7 @@ export const ApiModal: FC<{ identifier: string; name: string }> = (props) => { if (add.ok) { modal.closeAll(); router.refresh(); + if (update) update(); return; } @@ -66,25 +80,51 @@ export const ApiModal: FC<{ identifier: string; name: string }> = (props) => { }, []); return ( - -
+ + -
- - + + + + + +
+
+ +
+
+ +
+
+
+
); }; export const AddProviderComponent: FC<{ social: Array<{ identifier: string; name: string }>; article: Array<{ identifier: string; name: string }>; + update?: () => void; }> = (props) => { + const { update } = props; + const fetch = useFetch(); const modal = useModals(); const { social, article } = props; @@ -98,41 +138,84 @@ export const AddProviderComponent: FC<{ [] ); + const close = useCallback(() => { + modal.closeAll(); + }, []); + const showApiButton = useCallback( (identifier: string, name: string) => async () => { modal.openModal({ - title: `Add ${name}`, - children: , + title: '', + withCloseButton: false, + classNames: { + modal: 'bg-transparent text-white', + }, + children: ( + + ), }); }, [] ); return ( -
+
-

Social

+ + +

Social

{social.map((item) => (
- {item.name} +
+ +
+
{item.name}
))}
-

Articles

+

Articles

{article.map((item) => (
- {item.name} +
+ +
+
{item.name}
))}
diff --git a/apps/frontend/src/components/launches/calendar.tsx b/apps/frontend/src/components/launches/calendar.tsx index fbfe6d19..5edd098c 100644 --- a/apps/frontend/src/components/launches/calendar.tsx +++ b/apps/frontend/src/components/launches/calendar.tsx @@ -265,7 +265,7 @@ const CalendarColumnRender: FC<{ day: number; hour: string }> = (props) => { closeOnEscape: false, withCloseButton: false, classNames: { - modal: 'bg-transparent text-white', + modal: 'bg-transparent text-white !w-[auto]', }, children: ( @@ -277,7 +277,7 @@ const CalendarColumnRender: FC<{ day: number; hour: string }> = (props) => { /> ), - size: '80%', + size: 'dynamic', title: ``, }); }, @@ -293,7 +293,7 @@ const CalendarColumnRender: FC<{ day: number; hour: string }> = (props) => { modal: 'bg-transparent text-white', }, children: , - size: '80%', + size: '80%' // title: `Adding posts for ${getDate.format('DD/MM/YYYY HH:mm')}`, }); }, []); diff --git a/apps/frontend/src/components/launches/launches.component.tsx b/apps/frontend/src/components/launches/launches.component.tsx index c7d3218e..00f59a25 100644 --- a/apps/frontend/src/components/launches/launches.component.tsx +++ b/apps/frontend/src/components/launches/launches.component.tsx @@ -125,7 +125,7 @@ export const LaunchesComponent = () => {
))}
- + update(true)} />
diff --git a/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts b/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts index 60d2908a..e7409014 100644 --- a/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts @@ -52,6 +52,7 @@ export class IntegrationRepository { : {}), internalId, organizationId: org, + deletedAt: null, }, }); } diff --git a/libraries/nestjs-libraries/src/services/stripe.service.ts b/libraries/nestjs-libraries/src/services/stripe.service.ts index 9f0cb7e7..ca6e16e1 100644 --- a/libraries/nestjs-libraries/src/services/stripe.service.ts +++ b/libraries/nestjs-libraries/src/services/stripe.service.ts @@ -191,6 +191,12 @@ export class StripeService { return stripe.billingPortal.sessions.create({ customer, flow_data: { + after_completion: { + type: 'redirect', + redirect: { + return_url: process.env['FRONTEND_URL'] + '/billing', + }, + }, type: 'payment_method_update', }, });