feat: agencies

This commit is contained in:
Nevo David 2024-08-16 23:35:32 +07:00
parent 84e22203d9
commit 728a2a7a78
8 changed files with 203 additions and 29 deletions

View File

@ -1,8 +1,9 @@
import { Controller, Get } from '@nestjs/common';
import { Controller, Get, Post } from '@nestjs/common';
import { User } from '@prisma/client';
import { ApiTags } from '@nestjs/swagger';
import { AgenciesService } from '@gitroom/nestjs-libraries/database/prisma/agencies/agencies.service';
import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request';
import { CreateAgencyDto } from '@gitroom/nestjs-libraries/dtos/agencies/create.agency.dto';
@ApiTags('Agencies')
@Controller('/agencies')
@ -12,4 +13,9 @@ export class AgenciesController {
async generateImage(@GetUserFromRequest() user: User) {
return this._agenciesService.getAgencyByUser(user);
}
@Post('/')
async createAgency(@GetUserFromRequest() user: User, body: CreateAgencyDto) {
return this._agenciesService.createAgency(user, body);
}
}

View File

@ -5,6 +5,8 @@ export const dynamic = 'force-dynamic';
import { ReactNode } from 'react';
import Image from 'next/image';
import clsx from 'clsx';
import loadDynamic from 'next/dynamic';
const ReturnUrlComponent = loadDynamic(() => import('./return.url.component'));
export default async function AuthLayout({
children,
@ -13,6 +15,7 @@ export default async function AuthLayout({
}) {
return (
<>
<ReturnUrlComponent />
<div className="absolute left-0 top-0 z-[0] h-[100vh] w-[100vw] overflow-hidden bg-loginBg bg-contain bg-no-repeat bg-left-top" />
<div className="relative z-[1] pr-[100px] flex justify-end items-center h-[100vh] w-[100vw] overflow-hidden">
<div className="w-[557px] flex h-[614px] bg-loginBox bg-contain">

View File

@ -0,0 +1,27 @@
'use client';
import { useSearchParams } from 'next/navigation';
import { useCallback, useEffect } from 'react';
const ReturnUrlComponent = () => {
const params = useSearchParams();
const url = params.get('returnUrl');
useEffect(() => {
if (url?.indexOf?.('http')! > -1) {
localStorage.setItem('returnUrl', url!);
}
}, [url]);
return null;
}
export const useReturnUrl = () => {
return {
getAndClear: useCallback(() => {
const data = localStorage.getItem('returnUrl');
localStorage.removeItem('returnUrl');
return data;
}, [])
}
}
export default ReturnUrlComponent;

View File

@ -4,6 +4,7 @@ import { ReactNode, useCallback } from 'react';
import { FetchWrapperComponent } from '@gitroom/helpers/utils/custom.fetch';
import { deleteDialog } from '@gitroom/react/helpers/delete.dialog';
import { isGeneral } from '@gitroom/react/helpers/is.general';
import { useReturnUrl } from '@gitroom/frontend/app/auth/return.url.component';
export default function LayoutContext(params: { children: ReactNode }) {
if (params?.children) {
@ -14,16 +15,33 @@ export default function LayoutContext(params: { children: ReactNode }) {
return <></>;
}
function LayoutContextInner(params: { children: ReactNode }) {
const returnUrl = useReturnUrl();
const afterRequest = useCallback(
async (url: string, options: RequestInit, response: Response) => {
const reloadOrOnboarding =
response?.headers?.get('reload') ||
response?.headers?.get('onboarding');
if (reloadOrOnboarding) {
const getAndClear = returnUrl.getAndClear();
if (getAndClear) {
window.location.href = getAndClear;
return true;
}
}
if (response?.headers?.get('onboarding')) {
window.location.href = isGeneral()
? '/launches?onboarding=true'
: '/analytics?onboarding=true';
return true;
}
if (response?.headers?.get('reload')) {
window.location.reload();
return true;
}
if (response.status === 401) {

View File

@ -1,11 +1,13 @@
import { PrismaRepository } from '@gitroom/nestjs-libraries/database/prisma/prisma.service';
import { Injectable } from '@nestjs/common';
import { User } from '@prisma/client';
import { CreateAgencyDto } from '@gitroom/nestjs-libraries/dtos/agencies/create.agency.dto';
@Injectable()
export class AgenciesRepository {
constructor(
private _socialMediaAgencies: PrismaRepository<'socialMediaAgency'>
private _socialMediaAgencies: PrismaRepository<'socialMediaAgency'>,
private _socialMediaAgenciesNiche: PrismaRepository<'socialMediaAgencyNiche'>
) {}
getAgencyByUser(user: User) {
@ -16,4 +18,87 @@ export class AgenciesRepository {
},
});
}
async createAgency(user: User, body: CreateAgencyDto) {
const insertAgency =
await this._socialMediaAgencies.model.socialMediaAgency.upsert({
where: {
userId: user.id,
},
update: {
userId: user.id,
name: body.name,
website: body.website,
facebook: body.facebook,
instagram: body.instagram,
twitter: body.twitter,
linkedIn: body.linkedin,
youtube: body.youtube,
tiktok: body.tiktok,
logoId: body.logo,
shortDescription: body.shortDescription,
description: body.description,
niches: {
create: body.niche.map((n) => ({
niche: n,
})),
},
},
create: {
userId: user.id,
name: body.name,
website: body.website,
facebook: body.facebook,
instagram: body.instagram,
twitter: body.twitter,
linkedIn: body.linkedin,
youtube: body.youtube,
tiktok: body.tiktok,
logoId: body.logo,
shortDescription: body.shortDescription,
description: body.description,
},
select: {
id: true,
},
});
await this._socialMediaAgenciesNiche.model.socialMediaAgencyNiche.deleteMany(
{
where: {
agencyId: insertAgency.id,
niche: {
notIn: body.niche,
},
},
}
);
const currentNiche =
await this._socialMediaAgenciesNiche.model.socialMediaAgencyNiche.findMany(
{
where: {
agencyId: insertAgency.id,
},
select: {
niche: true,
},
}
);
const addNewNiche = body.niche.filter(
(n) => !currentNiche.some((c) => c.niche === n)
);
await this._socialMediaAgenciesNiche.model.socialMediaAgencyNiche.createMany(
{
data: addNewNiche.map((n) => ({
agencyId: insertAgency.id,
niche: n,
})),
}
);
return insertAgency;
}
}

View File

@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import { AgenciesRepository } from '@gitroom/nestjs-libraries/database/prisma/agencies/agencies.repository';
import { User } from '@prisma/client';
import { CreateAgencyDto } from '@gitroom/nestjs-libraries/dtos/agencies/create.agency.dto';
@Injectable()
export class AgenciesService {
@ -8,4 +9,8 @@ export class AgenciesService {
getAgencyByUser(user: User) {
return this._agenciesRepository.getAgencyByUser(user);
}
createAgency(user: User, body: CreateAgencyDto) {
return this._agenciesRepository.createAgency(user, body);
}
}

View File

@ -174,14 +174,10 @@ model Media {
model SocialMediaAgency {
id String @id @default(uuid())
user User @relation(fields: [userId], references: [id])
userId String
userId String @unique()
name String
logoId String?
logo Media? @relation(fields: [logoId], references: [id])
tagline String?
address String?
phoneNumber String?
emailAddress String?
website String?
facebook String?
@ -189,30 +185,13 @@ model SocialMediaAgency {
twitter String?
linkedIn String?
youtube String?
tiktok String?
otherSocialMedia String?
primaryServices String
specialties String?
packages String?
caseStudies String?
yearEstablished Int?
teamSize Int?
languagesSupported String?
clientTypes String?
clientTestimonials String?
certifications String?
awards String?
blog String?
faqs String?
events String?
freeConsultation Boolean @default(false)
businessHours String?
serviceArea String?
termsAndConditions String?
shortDescription String
description String
niches SocialMediaAgencyNiche[]
approved Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@ -223,6 +202,14 @@ model SocialMediaAgency {
@@index([id])
}
model SocialMediaAgencyNiche {
agencyId String
agency SocialMediaAgency @relation(fields: [agencyId], references: [id])
niche String
@@id([agencyId, niche])
}
model Credits {
id String @id @default(uuid())
organization Organization @relation(fields: [organizationId], references: [id])

View File

@ -0,0 +1,43 @@
import { IsDefined, IsString, IsUrl, MinLength } from 'class-validator';
export class CreateAgencyDto {
@IsString()
@MinLength(3)
name: string;
@IsUrl()
@IsDefined()
website: string;
@IsUrl()
facebook: string;
@IsString()
instagram: string;
@IsString()
twitter: string;
@IsUrl()
linkedin: string;
@IsUrl()
youtube: string;
@IsUrl()
tiktok: string;
@IsString()
logo: string;
@IsString()
shortDescription: string;
@IsString()
description: string;
@IsString({
each: true
})
niche: string[];
}