From e90b8e8389547c268e2640951bcfaf17b873567d Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sun, 5 May 2024 15:34:06 +0700 Subject: [PATCH] feat: stage two --- apps/backend/src/api/api.module.ts | 2 + .../src/api/routes/marketplace.controller.ts | 67 +++++ .../src/api/routes/stripe.controller.ts | 2 + .../src/api/routes/users.controller.ts | 25 +- .../src/components/layout/layout.settings.tsx | 2 + .../components/layout/settings.component.tsx | 160 +++++++++++ .../src/components/marketplace/buyer.tsx | 270 ++++++++++++------ .../src/components/marketplace/seller.tsx | 110 ++++++- .../src/database/prisma/database.module.ts | 4 + .../marketplace/item.user.repository.ts | 43 +++ .../prisma/marketplace/item.user.service.ts | 17 ++ .../database/prisma/marketplace/tags.list.ts | 111 +++++++ .../src/database/prisma/prisma.service.ts | 25 +- .../src/database/prisma/schema.prisma | 21 +- .../subscriptions/subscription.repository.ts | 36 ++- .../subscriptions/subscription.service.ts | 12 + .../database/prisma/users/users.repository.ts | 106 ++++++- .../database/prisma/users/users.service.ts | 13 + .../dtos/marketplace/add.remove.item.dto.ts | 11 + .../src/dtos/marketplace/change.active.dto.ts | 6 + .../src/dtos/marketplace/items.dto.ts | 12 + .../src/services/stripe.service.ts | 55 +++- package-lock.json | 8 +- package.json | 2 +- 24 files changed, 1000 insertions(+), 120 deletions(-) create mode 100644 apps/backend/src/api/routes/marketplace.controller.ts create mode 100644 apps/frontend/src/components/layout/settings.component.tsx create mode 100644 libraries/nestjs-libraries/src/database/prisma/marketplace/item.user.repository.ts create mode 100644 libraries/nestjs-libraries/src/database/prisma/marketplace/item.user.service.ts create mode 100644 libraries/nestjs-libraries/src/database/prisma/marketplace/tags.list.ts create mode 100644 libraries/nestjs-libraries/src/dtos/marketplace/add.remove.item.dto.ts create mode 100644 libraries/nestjs-libraries/src/dtos/marketplace/change.active.dto.ts create mode 100644 libraries/nestjs-libraries/src/dtos/marketplace/items.dto.ts diff --git a/apps/backend/src/api/api.module.ts b/apps/backend/src/api/api.module.ts index 64f16b22..6104d9ee 100644 --- a/apps/backend/src/api/api.module.ts +++ b/apps/backend/src/api/api.module.ts @@ -20,6 +20,7 @@ import { ServeStaticModule } from '@nestjs/serve-static'; import { CommentsController } from '@gitroom/backend/api/routes/comments.controller'; import { BillingController } from '@gitroom/backend/api/routes/billing.controller'; import { NotificationsController } from '@gitroom/backend/api/routes/notifications.controller'; +import { MarketplaceController } from '@gitroom/backend/api/routes/marketplace.controller'; const authenticatedController = [ UsersController, @@ -31,6 +32,7 @@ const authenticatedController = [ CommentsController, BillingController, NotificationsController, + MarketplaceController ]; @Module({ imports: [ diff --git a/apps/backend/src/api/routes/marketplace.controller.ts b/apps/backend/src/api/routes/marketplace.controller.ts new file mode 100644 index 00000000..62342ed4 --- /dev/null +++ b/apps/backend/src/api/routes/marketplace.controller.ts @@ -0,0 +1,67 @@ +import { Body, Controller, Get, Post } from '@nestjs/common'; +import { Organization, User } from '@prisma/client'; +import { ApiTags } from '@nestjs/swagger'; +import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request'; +import { ItemUserService } from '@gitroom/nestjs-libraries/database/prisma/marketplace/item.user.service'; +import { AddRemoveItemDto } from '@gitroom/nestjs-libraries/dtos/marketplace/add.remove.item.dto'; +import { StripeService } from '@gitroom/nestjs-libraries/services/stripe.service'; +import { UsersService } from '@gitroom/nestjs-libraries/database/prisma/users/users.service'; +import { ChangeActiveDto } from '@gitroom/nestjs-libraries/dtos/marketplace/change.active.dto'; +import { ItemsDto } from '@gitroom/nestjs-libraries/dtos/marketplace/items.dto'; +import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request'; + +@ApiTags('Marketplace') +@Controller('/marketplace') +export class MarketplaceController { + constructor( + private _itemUserService: ItemUserService, + private _stripeService: StripeService, + private _userService: UsersService + ) {} + + @Post('/') + getInfluencers( + @GetOrgFromRequest() organization: Organization, + @GetUserFromRequest() user: User, + @Body() body: ItemsDto + ) { + return this._userService.getMarketplacePeople(organization.id, user.id, body); + } + + @Get('/bank') + connectBankAccount(@GetUserFromRequest() user: User) { + return this._stripeService.createAccountProcess(user.id, user.email); + } + + @Post('/item') + async addItems( + @GetUserFromRequest() user: User, + @Body() body: AddRemoveItemDto + ) { + return this._itemUserService.addOrRemoveItem(body.state, user.id, body.key); + } + + @Post('/active') + async changeActive( + @GetUserFromRequest() user: User, + @Body() body: ChangeActiveDto + ) { + await this._userService.changeMarketplaceActive(user.id, body.active); + } + + @Get('/item') + async getItems(@GetUserFromRequest() user: User) { + return this._itemUserService.getItems(user.id); + } + + @Get('/account') + async getAccount(@GetUserFromRequest() user: User) { + const { account, marketplace, connectedAccount } = + await this._userService.getUserByEmail(user.email); + return { + account, + marketplace, + connectedAccount, + }; + } +} diff --git a/apps/backend/src/api/routes/stripe.controller.ts b/apps/backend/src/api/routes/stripe.controller.ts index 160432e3..bebc29d5 100644 --- a/apps/backend/src/api/routes/stripe.controller.ts +++ b/apps/backend/src/api/routes/stripe.controller.ts @@ -27,6 +27,8 @@ export class StripeController { } switch (event.type) { + case 'account.updated': + return this._stripeService.updateAccount(event); case 'customer.subscription.created': return this._stripeService.createSubscription(event); case 'customer.subscription.updated': diff --git a/apps/backend/src/api/routes/users.controller.ts b/apps/backend/src/api/routes/users.controller.ts index d5d73a5c..fdce646b 100644 --- a/apps/backend/src/api/routes/users.controller.ts +++ b/apps/backend/src/api/routes/users.controller.ts @@ -20,9 +20,10 @@ import { AuthorizationActions, Sections, } from '@gitroom/backend/services/auth/permissions/permissions.service'; -import {removeSubdomain} from "@gitroom/helpers/subdomain/subdomain.management"; -import {pricing} from "@gitroom/nestjs-libraries/database/prisma/subscriptions/pricing"; -import {ApiTags} from "@nestjs/swagger"; +import { removeSubdomain } from '@gitroom/helpers/subdomain/subdomain.management'; +import { pricing } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/pricing'; +import { ApiTags } from '@nestjs/swagger'; +import { UsersService } from '@gitroom/nestjs-libraries/database/prisma/users/users.service'; @ApiTags('User') @Controller('/user') @@ -31,7 +32,8 @@ export class UsersController { private _subscriptionService: SubscriptionService, private _stripeService: StripeService, private _authService: AuthService, - private _orgService: OrganizationService + private _orgService: OrganizationService, + private _userService: UsersService ) {} @Get('/self') async getSelf( @@ -54,6 +56,14 @@ export class UsersController { }; } + @Get('/personal') + async getPersonal( + @GetUserFromRequest() user: User, + ) { + + return this._userService.getPersonal(user.id); + } + @Get('/subscription') @CheckPolicies([AuthorizationActions.Create, Sections.ADMIN]) async getSubscription(@GetOrgFromRequest() organization: Organization) { @@ -97,7 +107,9 @@ export class UsersController { @Get('/organizations') async getOrgs(@GetUserFromRequest() user: User) { - return (await this._orgService.getOrgsByUserId(user.id)).filter(f => !f.users[0].disabled); + return (await this._orgService.getOrgsByUserId(user.id)).filter( + (f) => !f.users[0].disabled + ); } @Post('/change-org') @@ -106,7 +118,8 @@ export class UsersController { @Res({ passthrough: true }) response: Response ) { response.cookie('showorg', id, { - domain: '.' + new URL(removeSubdomain(process.env.FRONTEND_URL!)).hostname, + domain: + '.' + new URL(removeSubdomain(process.env.FRONTEND_URL!)).hostname, secure: true, httpOnly: true, sameSite: 'none', diff --git a/apps/frontend/src/components/layout/layout.settings.tsx b/apps/frontend/src/components/layout/layout.settings.tsx index f370d857..14b1fd50 100644 --- a/apps/frontend/src/components/layout/layout.settings.tsx +++ b/apps/frontend/src/components/layout/layout.settings.tsx @@ -21,6 +21,7 @@ import weekOfYear from 'dayjs/plugin/weekOfYear'; import isoWeek from 'dayjs/plugin/isoWeek'; import isBetween from 'dayjs/plugin/isBetween'; import { ShowLinkedinCompany } from '@gitroom/frontend/components/launches/helpers/linkedin.component'; +import { SettingsComponent } from '@gitroom/frontend/components/layout/settings.component'; dayjs.extend(utc); dayjs.extend(weekOfYear); @@ -59,6 +60,7 @@ export const LayoutSettings = ({ children }: { children: ReactNode }) => { {user?.orgId ? :
}
+
diff --git a/apps/frontend/src/components/layout/settings.component.tsx b/apps/frontend/src/components/layout/settings.component.tsx new file mode 100644 index 00000000..98f84904 --- /dev/null +++ b/apps/frontend/src/components/layout/settings.component.tsx @@ -0,0 +1,160 @@ +import { useModals } from '@mantine/modals'; +import React, { FC, useCallback, useEffect } from 'react'; +import { Input } from '@gitroom/react/form/input'; +import { Button } from '@gitroom/react/form/button'; +import { Textarea } from '@gitroom/react/form/textarea'; +import { FormProvider, useForm } from 'react-hook-form'; +import { showMediaBox } from '@gitroom/frontend/components/media/media.component'; +import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; + +const SettingsPopup: FC = () => { + const fetch = useFetch(); + const form = useForm({}); + const modal = useModals(); + const close = useCallback(() => { + return modal.closeAll(); + }, []); + + const loadProfile = useCallback( async() => { + const personal = await (await fetch('/user/personal')).json(); + form.setValue('fullname', personal.name || ''); + form.setValue('bio', personal.bio || ''); + form.setValue('picture', personal.picture); + }, []); + + const openMedia = useCallback(() => { + showMediaBox((values) => { + console.log(values); + }) + }, []); + + const submit = useCallback((val: any) => { + console.log(val); + }, []); + + useEffect(() => { + loadProfile(); + }, []); + + return ( + +
+
+ +
Profile Settings
+
+
Profile
+
+ Add profile information +
+
+
+
+
+ +
+
+
+
+
Profile Picture
+
+ + +
+
+
+
+
+