├── apps ├── evoque-web │ ├── public │ │ ├── .gitkeep │ │ └── favicon.ico │ ├── src │ │ ├── app │ │ │ ├── favicon.ico │ │ │ ├── (dashboard) │ │ │ │ └── admin │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── dashboard │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── layout.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── layout-server.tsx │ │ │ │ │ └── live-editor │ │ │ │ │ └── page.tsx │ │ │ ├── page.tsx │ │ │ ├── layout.tsx │ │ │ └── [slug] │ │ │ │ └── page.tsx │ │ ├── components │ │ │ ├── navigation │ │ │ │ └── index.ts │ │ │ ├── ui │ │ │ │ ├── aspect-ratio.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── skeleton.tsx │ │ │ │ ├── collapsible.tsx │ │ │ │ ├── textarea.tsx │ │ │ │ ├── label.tsx │ │ │ │ ├── input.tsx │ │ │ │ ├── separator.tsx │ │ │ │ ├── progress.tsx │ │ │ │ ├── toaster.tsx │ │ │ │ ├── sonner.tsx │ │ │ │ ├── slider.tsx │ │ │ │ ├── checkbox.tsx │ │ │ │ ├── switch.tsx │ │ │ │ ├── badge.tsx │ │ │ │ ├── hover-card.tsx │ │ │ │ ├── tooltip.tsx │ │ │ │ ├── popover.tsx │ │ │ │ ├── radio-group.tsx │ │ │ │ ├── avatar.tsx │ │ │ │ ├── toggle.tsx │ │ │ │ ├── alert.tsx │ │ │ │ ├── scroll-area.tsx │ │ │ │ ├── toggle-group.tsx │ │ │ │ ├── tabs.tsx │ │ │ │ ├── button.tsx │ │ │ │ ├── card.tsx │ │ │ │ └── accordion.tsx │ │ │ ├── sections │ │ │ │ ├── backgrounds │ │ │ │ │ ├── AboutBackground.tsx │ │ │ │ │ ├── CompetitiveAdvantageBackground.tsx │ │ │ │ │ ├── BeyondStandardsBackground.tsx │ │ │ │ │ └── HeroBackground.tsx │ │ │ │ └── SpacerSection.tsx │ │ │ ├── shared │ │ │ │ └── skeletons │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── PageTransitionSkeleton.tsx │ │ │ │ │ └── FormsManagementPageSkeleton.tsx │ │ │ ├── video │ │ │ │ └── VideoPreview.tsx │ │ │ ├── admin │ │ │ │ ├── (studio) │ │ │ │ │ └── pages │ │ │ │ │ │ └── live-editor │ │ │ │ │ │ ├── preview │ │ │ │ │ │ ├── PreviewPage.tsx │ │ │ │ │ │ └── PreviewLayout.tsx │ │ │ │ │ │ └── editors │ │ │ │ │ │ ├── MDXEditor.tsx │ │ │ │ │ │ └── JSONEditor.tsx │ │ │ │ ├── shared │ │ │ │ │ ├── DashboardStatsCardItem.tsx │ │ │ │ │ └── DashboardStatsCard.tsx │ │ │ │ └── live-editor │ │ │ │ │ ├── PreviewPanel.tsx │ │ │ │ │ └── Header.tsx │ │ │ └── render │ │ │ │ ├── SectionContentWrapper.tsx │ │ │ │ ├── ClientPageRenderer.tsx │ │ │ │ ├── SectionRenderer.tsx │ │ │ │ ├── DeferredContent.tsx │ │ │ │ ├── SectionContentRenderer.tsx │ │ │ │ ├── MenuSectionsRenderer.tsx │ │ │ │ ├── SectionWrapper.tsx │ │ │ │ └── VideoPreload.tsx │ │ ├── lib │ │ │ ├── utils.ts │ │ │ ├── cors.ts │ │ │ └── prisma.ts │ │ ├── data │ │ │ ├── sections │ │ │ │ ├── evoque-spacer.json │ │ │ │ ├── sign-in-hero.json │ │ │ │ ├── join-us-hero.json │ │ │ │ ├── services-hero.json │ │ │ │ ├── sign-in-form.json │ │ │ │ ├── join-us-form.json │ │ │ │ ├── about-hero.json │ │ │ │ ├── evoque-beyond-standards-mdx.json │ │ │ │ ├── about-mission.json │ │ │ │ ├── about-vision.json │ │ │ │ ├── sign-in-page-mdx.json │ │ │ │ ├── evoque-advantage-mdx.json │ │ │ │ ├── evoque-solutions-mdx.json │ │ │ │ ├── evoque-hero-mdx.json │ │ │ │ ├── evoque-we-know-our-people-mdx.json │ │ │ │ ├── evoque-about-mdx.json │ │ │ │ ├── evoque-location-mdx.json │ │ │ │ ├── about-page-mdx.json │ │ │ │ ├── evoque-why-peru-mdx.json │ │ │ │ ├── evoque-training-mdx.json │ │ │ │ ├── evoque-contact-mdx.json │ │ │ │ ├── contact-page-mdx.json │ │ │ │ ├── evoque-hr-mdx.json │ │ │ │ ├── join-us-page-mdx.json │ │ │ │ ├── about-values.json │ │ │ │ └── evoque-opportunities-mdx.json │ │ │ ├── pages │ │ │ │ ├── sign-in.json │ │ │ │ ├── contact.json │ │ │ │ ├── join-us.json │ │ │ │ ├── services.json │ │ │ │ ├── about.json │ │ │ │ └── evoque.json │ │ │ └── menu-sections │ │ │ │ ├── header-1.json │ │ │ │ └── footer-1.json │ │ ├── contexts │ │ │ ├── VideoLoadingContext.tsx │ │ │ ├── SearchContext.tsx │ │ │ ├── HeaderContext.tsx │ │ │ ├── PageActionsContext.tsx │ │ │ └── AdminSidebarContext.tsx │ │ └── config │ │ │ └── brand-colors.ts │ ├── index.d.ts │ ├── next-env.d.ts │ ├── vercel.json │ ├── specs │ │ └── index.spec.tsx │ ├── eslint.config.mjs │ ├── jest.config.cts │ ├── postcss.config.js │ ├── tsconfig.spec.json │ ├── .swcrc │ ├── next.config.js │ ├── tsconfig.json │ ├── VERCEL_FIX.md │ └── project.json ├── evoque-api │ ├── src │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── app │ │ │ ├── app.service.ts │ │ │ ├── app.controller.ts │ │ │ ├── app.service.spec.ts │ │ │ ├── app.module.ts │ │ │ └── app.controller.spec.ts │ │ ├── auth │ │ │ ├── dto │ │ │ │ ├── login.dto.ts │ │ │ │ ├── auth-response.dto.ts │ │ │ │ └── register.dto.ts │ │ │ ├── auth.module.ts │ │ │ └── controllers │ │ │ │ └── auth.controller.ts │ │ ├── roles │ │ │ ├── dto │ │ │ │ ├── update-role.dto.ts │ │ │ │ └── create-role.dto.ts │ │ │ ├── entities │ │ │ │ └── role.entity.ts │ │ │ ├── roles.module.ts │ │ │ ├── controllers │ │ │ │ └── roles.controller.ts │ │ │ ├── repositories │ │ │ │ └── roles.repository.ts │ │ │ └── services │ │ │ │ └── roles.service.ts │ │ ├── permissions │ │ │ ├── dto │ │ │ │ ├── update-permission.dto.ts │ │ │ │ └── create-permission.dto.ts │ │ │ ├── entities │ │ │ │ └── permission.entity.ts │ │ │ ├── permissions.module.ts │ │ │ └── controllers │ │ │ │ └── permissions.controller.ts │ │ ├── main.ts │ │ └── prisma │ │ │ └── prisma.service.ts │ ├── eslint.config.mjs │ ├── tsconfig.json │ ├── jest.config.cts │ ├── tsconfig.spec.json │ ├── tsconfig.app.json │ ├── webpack.config.js │ └── project.json ├── evoque-api-e2e │ ├── eslint.config.mjs │ ├── tsconfig.spec.json │ ├── tsconfig.json │ ├── src │ │ ├── evoque-api │ │ │ └── evoque-api.spec.ts │ │ └── support │ │ │ ├── test-setup.ts │ │ │ ├── global-teardown.ts │ │ │ └── global-setup.ts │ ├── project.json │ └── jest.config.cts ├── websocket │ ├── src │ │ ├── app │ │ │ ├── app.service.ts │ │ │ ├── app.controller.ts │ │ │ └── app.module.ts │ │ ├── pusher │ │ │ ├── pusher.module.ts │ │ │ └── pusher.service.ts │ │ ├── events │ │ │ ├── dto │ │ │ │ └── trigger-event.dto.ts │ │ │ ├── events.module.ts │ │ │ ├── events.service.ts │ │ │ └── events.controller.ts │ │ ├── auth │ │ │ ├── decorators │ │ │ │ └── current-user.decorator.ts │ │ │ ├── auth.module.ts │ │ │ ├── services │ │ │ │ └── auth.service.ts │ │ │ ├── guards │ │ │ │ └── jwt-auth.guard.ts │ │ │ ├── repositories │ │ │ │ └── auth.repository.ts │ │ │ └── strategies │ │ │ │ └── session.strategy.ts │ │ ├── pusher-auth │ │ │ ├── pusher-auth.module.ts │ │ │ ├── pusher-auth.controller.ts │ │ │ └── pusher-auth.service.ts │ │ ├── prisma │ │ │ └── prisma.service.ts │ │ └── main.ts │ ├── railway.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tsconfig.app.json │ ├── .railwayignore │ ├── webpack.config.js │ ├── fix-paths.js │ ├── README.md │ ├── package.json │ └── project.json └── evoque-web-e2e │ ├── src │ └── example.spec.ts │ ├── eslint.config.mjs │ ├── tsconfig.json │ ├── project.json │ └── playwright.config.ts ├── .prettierrc ├── error.log ├── jest.preset.js ├── .prettierignore ├── .vercelignore ├── .vercelrc ├── jest.config.ts ├── .vscode ├── extensions.json └── launch.json ├── vercel.json ├── railway.json ├── .editorconfig ├── .railwayignore ├── tsconfig.base.json ├── prisma.config.ts ├── .gitignore ├── eslint.config.mjs ├── .github └── workflows │ └── ci.yml ├── RAILWAY_DEPLOYMENT.md ├── VERCEL_SETUP.md ├── nx.json └── Dockerfile /apps/evoque-web/public/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/evoque-api/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /error.log: -------------------------------------------------------------------------------- 1 | 2 | /bin/sh: gh: command not found 3 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /apps/evoque-api/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [...baseConfig]; 4 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '../../eslint.config.mjs'; 2 | 3 | export default [...baseConfig]; 4 | -------------------------------------------------------------------------------- /apps/evoque-web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/disruption-hub/evoque-web/main/apps/evoque-web/public/favicon.ico -------------------------------------------------------------------------------- /apps/evoque-web/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/disruption-hub/evoque-web/main/apps/evoque-web/src/app/favicon.ico -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | /dist 3 | /coverage 4 | /.nx/cache 5 | /.nx/workspace-data -------------------------------------------------------------------------------- /.vercelignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | dist 4 | .nyc_output 5 | coverage 6 | *.log 7 | .env.local 8 | .env*.local 9 | 10 | -------------------------------------------------------------------------------- /.vercelrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectId": "", 3 | "orgId": "", 4 | "settings": { 5 | "rootDirectory": "evoque-api" 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/navigation/index.ts: -------------------------------------------------------------------------------- 1 | export { default as NavigationHeader } from './NavigationHeader'; 2 | export { default as BrandFooter } from './BrandFooter'; 3 | 4 | -------------------------------------------------------------------------------- /apps/evoque-web/src/app/(dashboard)/admin/page.tsx: -------------------------------------------------------------------------------- 1 | import AdminDashboardPage from '@/components/admin'; 2 | 3 | export default function AdminPage() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /apps/evoque-web/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | declare module '*.svg' { 3 | const content: any; 4 | export const ReactComponent: any; 5 | export default content; 6 | } 7 | -------------------------------------------------------------------------------- /apps/evoque-web/src/app/(dashboard)/admin/dashboard/page.tsx: -------------------------------------------------------------------------------- 1 | import AdminDashboardPage from '@/components/admin'; 2 | 3 | export default function DashboardPage() { 4 | return ; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | import { getJestProjectsAsync } from '@nx/jest'; 3 | 4 | export default async (): Promise => ({ 5 | projects: await getJestProjectsAsync(), 6 | }); 7 | -------------------------------------------------------------------------------- /apps/evoque-web/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 4 | 5 | const AspectRatio = AspectRatioPrimitive.Root 6 | 7 | export { AspectRatio } 8 | -------------------------------------------------------------------------------- /apps/evoque-api/src/app/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getData(): { message: string } { 6 | return { message: 'Hello API' }; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /apps/evoque-api/src/auth/dto/login.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsEmail } from 'class-validator'; 2 | 3 | export class LoginDto { 4 | @IsEmail() 5 | email: string; 6 | 7 | @IsString() 8 | password: string; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /apps/evoque-api/src/roles/dto/update-role.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateRoleDto } from './create-role.dto'; 3 | 4 | export class UpdateRoleDto extends PartialType(CreateRoleDto) {} 5 | 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "esbenp.prettier-vscode", 5 | "dbaeumer.vscode-eslint", 6 | "firsttris.vscode-jest-runner", 7 | "ms-playwright.playwright" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/sections/evoque-spacer.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "evoque-spacer", 3 | "sectionKey": "spacer", 4 | "title": "Spacer", 5 | "type": "SPACER", 6 | "sectionData": {}, 7 | "order": 1.5, 8 | "isActive": true 9 | } 10 | 11 | -------------------------------------------------------------------------------- /apps/websocket/src/app/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getData(): { message: string } { 6 | return { message: 'WebSocket Pusher API' }; 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evoque-web", 3 | "buildCommand": "npm run build:vercel", 4 | "outputDirectory": "dist/apps/evoque-web/.next", 5 | "installCommand": "NODE_ENV=development npm install --legacy-peer-deps", 6 | "framework": "nextjs" 7 | } 8 | -------------------------------------------------------------------------------- /railway.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://railway.app/railway.schema.json", 3 | "build": { 4 | "builder": "DOCKERFILE" 5 | }, 6 | "deploy": { 7 | "restartPolicyType": "ON_FAILURE", 8 | "restartPolicyMaxRetries": 10 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /apps/evoque-api/src/permissions/dto/update-permission.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreatePermissionDto } from './create-permission.dto'; 3 | 4 | export class UpdatePermissionDto extends PartialType(CreatePermissionDto) {} 5 | 6 | -------------------------------------------------------------------------------- /apps/websocket/railway.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://railway.app/railway.schema.json", 3 | "build": { 4 | "builder": "DOCKERFILE" 5 | }, 6 | "deploy": { 7 | "restartPolicyType": "ON_FAILURE", 8 | "restartPolicyMaxRetries": 10 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /apps/websocket/src/pusher/pusher.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PusherService } from './pusher.service'; 3 | 4 | @Module({ 5 | providers: [PusherService], 6 | exports: [PusherService], 7 | }) 8 | export class PusherModule {} 9 | 10 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "src/**/*.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/ui/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ColorCircle } from './ColorCircle'; 2 | export { default as ImageCircle } from './ImageCircle'; 3 | export type { ColorCircleProps } from './ColorCircle'; 4 | export type { ImageCircleProps } from './ImageCircle'; 5 | 6 | -------------------------------------------------------------------------------- /apps/evoque-web-e2e/src/example.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | 3 | test('has title', async ({ page }) => { 4 | await page.goto('/'); 5 | 6 | // Expect h1 to contain a substring. 7 | expect(await page.locator('h1').innerText()).toContain('Welcome'); 8 | }); 9 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.spec.json" 8 | } 9 | ], 10 | "compilerOptions": { 11 | "esModuleInterop": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /apps/evoque-web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | import "./.next/dev/types/routes.d.ts"; 4 | 5 | // NOTE: This file should not be edited 6 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 7 | -------------------------------------------------------------------------------- /apps/evoque-api/src/roles/entities/role.entity.ts: -------------------------------------------------------------------------------- 1 | import { Role } from '@generated/prisma'; 2 | 3 | export class RoleEntity implements Role { 4 | id: string; 5 | name: string; 6 | description: string | null; 7 | isActive: boolean; 8 | createdAt: Date; 9 | updatedAt: Date; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /apps/evoque-web/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand": "NODE_ENV=development npm install --legacy-peer-deps && npx nx build evoque-web --skip-nx-cache", 3 | "outputDirectory": "dist/apps/evoque-web/.next", 4 | "installCommand": "NODE_ENV=development npm install --legacy-peer-deps", 5 | "framework": "nextjs" 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/src/evoque-api/evoque-api.spec.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | describe('GET /api', () => { 4 | it('should return a message', async () => { 5 | const res = await axios.get(`/api`); 6 | 7 | expect(res.status).toBe(200); 8 | expect(res.data).toEqual({ message: 'Hello API' }); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/src/support/test-setup.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import axios from 'axios'; 3 | 4 | module.exports = async function () { 5 | // Configure axios for tests to use. 6 | const host = process.env.HOST ?? 'localhost'; 7 | const port = process.env.PORT ?? '3000'; 8 | axios.defaults.baseURL = `http://${host}:${port}`; 9 | }; 10 | -------------------------------------------------------------------------------- /apps/evoque-api/src/roles/dto/create-role.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsOptional, IsBoolean } from 'class-validator'; 2 | 3 | export class CreateRoleDto { 4 | @IsString() 5 | name: string; 6 | 7 | @IsOptional() 8 | @IsString() 9 | description?: string; 10 | 11 | @IsOptional() 12 | @IsBoolean() 13 | isActive?: boolean; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /apps/evoque-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "esModuleInterop": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apps/evoque-web/specs/index.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import Page from '../src/app/page'; 4 | 5 | describe('Page', () => { 6 | it('should render successfully', () => { 7 | const { baseElement } = render(); 8 | expect(baseElement).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /apps/evoque-api/src/app/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getData() { 10 | return this.appService.getData(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /apps/evoque-api/src/permissions/entities/permission.entity.ts: -------------------------------------------------------------------------------- 1 | import { Permission } from '@generated/prisma'; 2 | 3 | export class PermissionEntity implements Permission { 4 | id: string; 5 | name: string; 6 | resource: string; 7 | action: string; 8 | description: string | null; 9 | createdAt: Date; 10 | updatedAt: Date; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /apps/websocket/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "esModuleInterop": true 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /apps/evoque-web-e2e/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import playwright from 'eslint-plugin-playwright'; 2 | import baseConfig from '../../eslint.config.mjs'; 3 | 4 | export default [ 5 | playwright.configs['flat/recommended'], 6 | ...baseConfig, 7 | { 8 | files: ['**/*.ts', '**/*.js'], 9 | // Override or add rules here 10 | rules: {}, 11 | }, 12 | ]; 13 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/pages/sign-in.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "page-sign-in", 3 | "slug": "sign-in", 4 | "title": "Sign In", 5 | "description": "Sign in to your E-Voque client portal account.", 6 | "sections": [ 7 | "sign-in-form" 8 | ], 9 | "menuSections": [ 10 | "header-1", 11 | "footer-1" 12 | ], 13 | "isActive": true 14 | } 15 | 16 | -------------------------------------------------------------------------------- /apps/websocket/src/app/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getData() { 10 | return this.appService.getData(); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /apps/websocket/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | 16 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/sections/backgrounds/AboutBackground.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** 4 | * Deprecated: White background 5 | * This background was used in About.tsx before video background was implemented 6 | */ 7 | export function AboutBackground() { 8 | return ( 9 |
10 | ); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /apps/websocket/src/events/dto/trigger-event.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsNotEmpty, IsObject, IsOptional } from 'class-validator'; 2 | 3 | export class TriggerEventDto { 4 | @IsString() 5 | @IsNotEmpty() 6 | channel: string; 7 | 8 | @IsString() 9 | @IsNotEmpty() 10 | event: string; 11 | 12 | @IsObject() 13 | @IsOptional() 14 | data?: any; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /apps/evoque-api/jest.config.cts: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'evoque-api', 3 | preset: '../../jest.preset.js', 4 | testEnvironment: 'node', 5 | transform: { 6 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 7 | }, 8 | moduleFileExtensions: ['ts', 'js', 'html'], 9 | coverageDirectory: '../../coverage/apps/evoque-api', 10 | }; 11 | -------------------------------------------------------------------------------- /apps/evoque-api/src/permissions/dto/create-permission.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsOptional } from 'class-validator'; 2 | 3 | export class CreatePermissionDto { 4 | @IsString() 5 | name: string; 6 | 7 | @IsString() 8 | resource: string; 9 | 10 | @IsString() 11 | action: string; 12 | 13 | @IsOptional() 14 | @IsString() 15 | description?: string; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /apps/evoque-web/src/app/(dashboard)/admin/dashboard/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function DashboardLayout({ 2 | children, 3 | }: { 4 | children: React.ReactNode; 5 | }) { 6 | return ( 7 |
8 |
9 | {children} 10 |
11 |
12 | ); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/pages/contact.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "page-contact", 3 | "slug": "contact", 4 | "title": "Contact Us", 5 | "description": "Get in touch with E-Voque to discuss how we can help your business.", 6 | "sections": [ 7 | "contact-page-mdx" 8 | ], 9 | "menuSections": [ 10 | "header-1", 11 | "footer-1" 12 | ], 13 | "isActive": true 14 | } 15 | 16 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/pages/join-us.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "page-join-us", 3 | "slug": "join-us", 4 | "title": "Join Our Team", 5 | "description": "Explore career opportunities at E-Voque and join our growing team.", 6 | "sections": [ 7 | "join-us-form" 8 | ], 9 | "menuSections": [ 10 | "header-1", 11 | "footer-1" 12 | ], 13 | "isActive": true 14 | } 15 | 16 | -------------------------------------------------------------------------------- /apps/evoque-web/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import nextEslintPluginNext from '@next/eslint-plugin-next'; 2 | import nx from '@nx/eslint-plugin'; 3 | import baseConfig from '../../eslint.config.mjs'; 4 | 5 | export default [ 6 | { plugins: { '@next/next': nextEslintPluginNext } }, 7 | ...baseConfig, 8 | ...nx.configs['flat/react-typescript'], 9 | { 10 | ignores: ['.next/**/*'], 11 | }, 12 | ]; 13 | -------------------------------------------------------------------------------- /apps/websocket/src/auth/decorators/current-user.decorator.ts: -------------------------------------------------------------------------------- 1 | import { createParamDecorator, ExecutionContext } from '@nestjs/common'; 2 | import { User } from '@generated/prisma'; 3 | 4 | export const CurrentUser = createParamDecorator( 5 | (data: unknown, ctx: ExecutionContext): User => { 6 | const request = ctx.switchToHttp().getRequest(); 7 | return request.user; 8 | }, 9 | ); 10 | 11 | -------------------------------------------------------------------------------- /apps/evoque-api/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "moduleResolution": "node10", 7 | "types": ["jest", "node"] 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "jest.config.cts", 12 | "src/**/*.test.ts", 13 | "src/**/*.spec.ts", 14 | "src/**/*.d.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 4 | 5 | const Collapsible = CollapsiblePrimitive.Root 6 | 7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger 8 | 9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent 10 | 11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 12 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/pages/services.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "page-services", 3 | "slug": "services", 4 | "title": "Our Services", 5 | "description": "Discover the comprehensive business process outsourcing services offered by E-Voque.", 6 | "sections": [ 7 | "services-hero", 8 | "evoque-solutions-mdx" 9 | ], 10 | "menuSections": [ 11 | "header-1", 12 | "footer-1" 13 | ], 14 | "isActive": true 15 | } 16 | 17 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/sections/sign-in-hero.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "sign-in-hero", 3 | "sectionKey": "sign-in-hero", 4 | "title": "Sign In", 5 | "type": "HERO", 6 | "sectionData": { 7 | "title": "Sign In", 8 | "description": "Sign in to your E-Voque client portal account.", 9 | "content": "# Sign In\n\nSign in to your E-Voque client portal account.\n\n" 10 | }, 11 | "order": 0, 12 | "isActive": true 13 | } 14 | 15 | -------------------------------------------------------------------------------- /apps/evoque-api/src/auth/dto/auth-response.dto.ts: -------------------------------------------------------------------------------- 1 | 2 | export class AuthResponseDto { 3 | user: { 4 | id: string; 5 | email: string; 6 | firstName: string; 7 | lastName: string; 8 | roleId: string; 9 | isActive: boolean; 10 | emailVerified: boolean; 11 | }; 12 | token: string; 13 | } 14 | 15 | export class LoginResponseDto extends AuthResponseDto {} 16 | 17 | export class RegisterResponseDto extends AuthResponseDto {} 18 | 19 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/shared/skeletons/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Skeleton Loaders Components 3 | * Centralized export for all skeleton loading components 4 | */ 5 | 6 | export { PagesManagementPageSkeleton } from './PagesManagementPageSkeleton'; 7 | export { PageTransitionSkeleton } from './PageTransitionSkeleton'; 8 | export { MenuPageSkeleton } from './MenuPageSkeleton'; 9 | export { FormsManagementPageSkeleton } from './FormsManagementPageSkeleton'; 10 | 11 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/src/support/global-teardown.ts: -------------------------------------------------------------------------------- 1 | import { killPort } from '@nx/node/utils'; 2 | /* eslint-disable */ 3 | 4 | module.exports = async function () { 5 | // Put clean up logic here (e.g. stopping services, docker-compose, etc.). 6 | // Hint: `globalThis` is shared between setup and teardown. 7 | const port = process.env.PORT ? Number(process.env.PORT) : 3000; 8 | await killPort(port); 9 | console.log(globalThis.__TEARDOWN_MESSAGE__); 10 | }; 11 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/pages/about.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "page-about", 3 | "slug": "about", 4 | "title": "About E-Voque", 5 | "description": "Learn more about E-Voque, our mission, vision, and values.", 6 | "sections": [ 7 | "about-hero", 8 | "evoque-about-mdx", 9 | "about-mission", 10 | "about-vision", 11 | "about-values" 12 | ], 13 | "menuSections": [ 14 | "header-1", 15 | "footer-1" 16 | ], 17 | "isActive": true 18 | } 19 | 20 | -------------------------------------------------------------------------------- /apps/evoque-web-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "outDir": "../../dist/out-tsc", 6 | "sourceMap": false, 7 | "module": "commonjs" 8 | }, 9 | "include": [ 10 | "**/*.ts", 11 | "**/*.js", 12 | "playwright.config.ts", 13 | "src/**/*.spec.ts", 14 | "src/**/*.spec.js", 15 | "src/**/*.test.ts", 16 | "src/**/*.test.js", 17 | "src/**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /apps/evoque-api/src/auth/dto/register.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString, IsEmail, IsOptional, MinLength } from 'class-validator'; 2 | 3 | export class RegisterDto { 4 | @IsEmail() 5 | email: string; 6 | 7 | @IsString() 8 | @MinLength(8) 9 | password: string; 10 | 11 | @IsString() 12 | firstName: string; 13 | 14 | @IsString() 15 | lastName: string; 16 | 17 | @IsOptional() 18 | @IsString() 19 | phone?: string; 20 | 21 | @IsString() 22 | roleId: string; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /apps/evoque-api/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"], 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "target": "es2021" 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "exclude": [ 13 | "jest.config.ts", 14 | "jest.config.cts", 15 | "src/**/*.spec.ts", 16 | "src/**/*.test.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/evoque-web/src/app/(dashboard)/admin/layout.tsx: -------------------------------------------------------------------------------- 1 | // Server component wrapper for admin layout - allows route segment config 2 | export const dynamic = 'force-dynamic'; 3 | export const dynamicParams = true; 4 | export const revalidate = 0; 5 | 6 | import AdminLayoutClient from './layout-client'; 7 | 8 | export default function AdminLayout({ 9 | children, 10 | }: { 11 | children: React.ReactNode; 12 | }) { 13 | return {children}; 14 | } 15 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/sections/backgrounds/CompetitiveAdvantageBackground.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { getBrandColor } from '@/config/brand-colors'; 3 | 4 | /** 5 | * Deprecated: White background 6 | * This background was used in CompetitiveAdvantage.tsx before video background was implemented 7 | */ 8 | export function CompetitiveAdvantageBackground() { 9 | return ( 10 |
11 | ); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/sections/join-us-hero.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "join-us-hero", 3 | "sectionKey": "join-us-hero", 4 | "title": "Join Our Team", 5 | "type": "HERO", 6 | "sectionData": { 7 | "title": "Join Our Team", 8 | "description": "Explore career opportunities at E-Voque and join our growing team.", 9 | "content": "# Join Our Team\n\nExplore career opportunities at E-Voque and join our growing team.\n\n" 10 | }, 11 | "order": 0, 12 | "isActive": true 13 | } 14 | 15 | -------------------------------------------------------------------------------- /apps/websocket/src/events/events.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { EventsController } from './events.controller'; 3 | import { EventsService } from './events.service'; 4 | import { PusherModule } from '../pusher/pusher.module'; 5 | import { AuthModule } from '../auth/auth.module'; 6 | 7 | @Module({ 8 | imports: [PusherModule, AuthModule], 9 | controllers: [EventsController], 10 | providers: [EventsService], 11 | }) 12 | export class EventsModule {} 13 | 14 | -------------------------------------------------------------------------------- /apps/websocket/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"], 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "target": "es2021" 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "exclude": [ 13 | "jest.config.ts", 14 | "jest.config.cts", 15 | "src/**/*.spec.ts", 16 | "src/**/*.test.ts" 17 | ] 18 | } 19 | 20 | -------------------------------------------------------------------------------- /apps/evoque-web/src/app/(dashboard)/admin/layout-server.tsx: -------------------------------------------------------------------------------- 1 | // Server component wrapper for admin layout - allows route segment config 2 | export const dynamic = 'force-dynamic'; 3 | export const dynamicParams = true; 4 | export const revalidate = 0; 5 | 6 | import AdminLayoutClient from './layout-client'; 7 | 8 | export default function AdminLayout({ 9 | children, 10 | }: { 11 | children: React.ReactNode; 12 | }) { 13 | return {children}; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/sections/services-hero.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "services-hero", 3 | "sectionKey": "services-hero", 4 | "title": "Our Services", 5 | "type": "HERO", 6 | "sectionData": { 7 | "title": "Our Services", 8 | "description": "Discover the comprehensive business process outsourcing services offered by E-Voque.", 9 | "content": "# Our Services\n\nDiscover the comprehensive business process outsourcing services offered by E-Voque.\n\n" 10 | }, 11 | "order": 0, 12 | "isActive": true 13 | } 14 | 15 | -------------------------------------------------------------------------------- /apps/websocket/src/pusher-auth/pusher-auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PusherAuthController } from './pusher-auth.controller'; 3 | import { PusherAuthService } from './pusher-auth.service'; 4 | import { PusherModule } from '../pusher/pusher.module'; 5 | import { AuthModule } from '../auth/auth.module'; 6 | 7 | @Module({ 8 | imports: [PusherModule, AuthModule], 9 | controllers: [PusherAuthController], 10 | providers: [PusherAuthService], 11 | }) 12 | export class PusherAuthModule {} 13 | 14 | -------------------------------------------------------------------------------- /apps/evoque-api/src/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PrismaService } from '../prisma/prisma.service'; 3 | import { AuthService } from './services/auth.service'; 4 | import { AuthController } from './controllers/auth.controller'; 5 | import { AuthRepository } from './repositories/auth.repository'; 6 | 7 | @Module({ 8 | controllers: [AuthController], 9 | providers: [AuthService, AuthRepository, PrismaService], 10 | exports: [AuthService, AuthRepository], 11 | }) 12 | export class AuthModule {} 13 | 14 | -------------------------------------------------------------------------------- /apps/evoque-web/jest.config.cts: -------------------------------------------------------------------------------- 1 | const nextJest = require('next/jest.js'); 2 | 3 | const createJestConfig = nextJest({ 4 | dir: './', 5 | }); 6 | 7 | const config = { 8 | displayName: 'evoque-web', 9 | preset: '../../jest.preset.js', 10 | transform: { 11 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 14 | coverageDirectory: '../../coverage/evoque-web', 15 | testEnvironment: 'jsdom', 16 | }; 17 | 18 | module.exports = createJestConfig(config); 19 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/sections/SpacerSection.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React from 'react'; 4 | 5 | export default function SpacerSection() { 6 | // Empty section that just takes up space - shared background is already fixed 7 | return ( 8 |
13 | {/* No content - just space for the shared background to show through */} 14 |
15 | ); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /apps/evoque-api/src/roles/roles.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PrismaService } from '../prisma/prisma.service'; 3 | import { RolesService } from './services/roles.service'; 4 | import { RolesController } from './controllers/roles.controller'; 5 | import { RolesRepository } from './repositories/roles.repository'; 6 | 7 | @Module({ 8 | controllers: [RolesController], 9 | providers: [RolesService, RolesRepository, PrismaService], 10 | exports: [RolesService, RolesRepository], 11 | }) 12 | export class RolesModule {} 13 | 14 | -------------------------------------------------------------------------------- /apps/evoque-web/postcss.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path'); 2 | 3 | // Note: If you use library-specific PostCSS/Tailwind configuration then you should remove the `postcssConfig` build 4 | // option from your application's configuration (i.e. project.json). 5 | // 6 | // See: https://nx.dev/guides/using-tailwind-css-in-react#step-4:-applying-configuration-to-libraries 7 | 8 | module.exports = { 9 | plugins: { 10 | tailwindcss: { 11 | config: join(__dirname, 'tailwind.config.js'), 12 | }, 13 | autoprefixer: {}, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/sections/sign-in-form.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "sign-in-form", 3 | "sectionKey": "sign-in-form", 4 | "title": "Sign In", 5 | "type": "FORM", 6 | "sectionData": { 7 | "title": "Sign In", 8 | "description": "Enter your credentials to access your account.", 9 | "formType": "signin", 10 | "layout": "horizontal", 11 | "formPosition": "left", 12 | "heroTitle": "Sign In", 13 | "heroDescription": "Sign in to your E-Voque client portal account." 14 | }, 15 | "order": 0, 16 | "isActive": true 17 | } 18 | 19 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/sections/join-us-form.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "join-us-form", 3 | "sectionKey": "join-us-form", 4 | "title": "Join Our Team", 5 | "type": "FORM", 6 | "sectionData": { 7 | "title": "Apply Now", 8 | "description": "Fill out the form below to submit your application.", 9 | "formType": "joinus", 10 | "layout": "horizontal", 11 | "heroTitle": "Join Our Team", 12 | "heroDescription": "Explore career opportunities at E-Voque and join our growing team." 13 | }, 14 | "order": 0, 15 | "isActive": true 16 | } 17 | 18 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evoque-api-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "implicitDependencies": ["evoque-api"], 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/jest:jest", 9 | "outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"], 10 | "options": { 11 | "jestConfig": "apps/evoque-api-e2e/jest.config.cts", 12 | "passWithNoTests": true 13 | }, 14 | "dependsOn": ["evoque-api:build", "evoque-api:serve"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/evoque-api/src/app/app.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test } from '@nestjs/testing'; 2 | import { AppService } from './app.service'; 3 | 4 | describe('AppService', () => { 5 | let service: AppService; 6 | 7 | beforeAll(async () => { 8 | const app = await Test.createTestingModule({ 9 | providers: [AppService], 10 | }).compile(); 11 | 12 | service = app.get(AppService); 13 | }); 14 | 15 | describe('getData', () => { 16 | it('should return "Hello API"', () => { 17 | expect(service.getData()).toEqual({ message: 'Hello API' }); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/video/VideoPreview.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React from 'react'; 4 | 5 | interface VideoPreviewProps { 6 | videoUrl: string; 7 | } 8 | 9 | export default function VideoPreview({ videoUrl }: VideoPreviewProps) { 10 | return ( 11 |
12 | 20 |
21 | ); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /apps/evoque-web/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc", 5 | "module": "commonjs", 6 | "moduleResolution": "node10", 7 | "jsx": "react", 8 | "types": ["jest", "node"] 9 | }, 10 | "include": [ 11 | "jest.config.ts", 12 | "jest.config.cts", 13 | "src/**/*.test.ts", 14 | "src/**/*.spec.ts", 15 | "src/**/*.test.tsx", 16 | "src/**/*.spec.tsx", 17 | "src/**/*.test.js", 18 | "src/**/*.spec.js", 19 | "src/**/*.test.jsx", 20 | "src/**/*.spec.jsx", 21 | "src/**/*.d.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /apps/websocket/src/events/events.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { PusherService } from '../pusher/pusher.service'; 3 | 4 | @Injectable() 5 | export class EventsService { 6 | constructor(private readonly pusherService: PusherService) {} 7 | 8 | async triggerEvent(channel: string, event: string, data: any): Promise { 9 | await this.pusherService.trigger(channel, event, data); 10 | } 11 | 12 | async triggerBatch(events: Array<{ channel: string; name: string; data: any }>): Promise { 13 | await this.pusherService.triggerBatch(events); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/jest.config.cts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'evoque-api-e2e', 3 | preset: '../../jest.preset.js', 4 | globalSetup: '/src/support/global-setup.ts', 5 | globalTeardown: '/src/support/global-teardown.ts', 6 | setupFiles: ['/src/support/test-setup.ts'], 7 | testEnvironment: 'node', 8 | transform: { 9 | '^.+\\.[tj]s$': [ 10 | 'ts-jest', 11 | { 12 | tsconfig: '/tsconfig.spec.json', 13 | }, 14 | ], 15 | }, 16 | moduleFileExtensions: ['ts', 'js', 'html'], 17 | coverageDirectory: '../../coverage/evoque-api-e2e', 18 | }; 19 | -------------------------------------------------------------------------------- /apps/evoque-web/src/app/(dashboard)/admin/live-editor/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export default function LiveEditorPage() { 4 | return ( 5 |
6 |
7 |

Live Editor

8 |

Select a page from the sidebar to start editing

9 |

10 | Choose a page, section, or component to edit 11 |

12 |
13 |
14 | ); 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /apps/evoque-api/src/permissions/permissions.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PrismaService } from '../prisma/prisma.service'; 3 | import { PermissionsService } from './services/permissions.service'; 4 | import { PermissionsController } from './controllers/permissions.controller'; 5 | import { PermissionsRepository } from './repositories/permissions.repository'; 6 | 7 | @Module({ 8 | controllers: [PermissionsController], 9 | providers: [PermissionsService, PermissionsRepository, PrismaService], 10 | exports: [PermissionsService, PermissionsRepository], 11 | }) 12 | export class PermissionsModule {} 13 | 14 | -------------------------------------------------------------------------------- /apps/evoque-api/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { PrismaService } from '../prisma/prisma.service'; 5 | import { AuthModule } from '../auth/auth.module'; 6 | import { RolesModule } from '../roles/roles.module'; 7 | import { PermissionsModule } from '../permissions/permissions.module'; 8 | 9 | @Module({ 10 | imports: [AuthModule, RolesModule, PermissionsModule], 11 | controllers: [AppController], 12 | providers: [AppService, PrismaService], 13 | exports: [PrismaService], 14 | }) 15 | export class AppModule {} 16 | -------------------------------------------------------------------------------- /apps/evoque-web-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evoque-web-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "sourceRoot": "apps/evoque-web-e2e/src", 6 | "tags": [], 7 | "implicitDependencies": ["evoque-web"], 8 | "// targets": "to see all targets run: nx show project evoque-web-e2e --web", 9 | "targets": { 10 | "e2e": { 11 | "executor": "@nx/playwright:playwright", 12 | "outputs": ["{workspaceRoot}/dist/.playwright/apps/evoque-web-e2e"], 13 | "options": { 14 | "config": "apps/evoque-web-e2e/playwright.config.ts" 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/evoque-api-e2e/src/support/global-setup.ts: -------------------------------------------------------------------------------- 1 | import { waitForPortOpen } from '@nx/node/utils'; 2 | 3 | /* eslint-disable */ 4 | var __TEARDOWN_MESSAGE__: string; 5 | 6 | module.exports = async function () { 7 | // Start services that that the app needs to run (e.g. database, docker-compose, etc.). 8 | console.log('\nSetting up...\n'); 9 | 10 | const host = process.env.HOST ?? 'localhost'; 11 | const port = process.env.PORT ? Number(process.env.PORT) : 3000; 12 | await waitForPortOpen(port, { host }); 13 | 14 | // Hint: Use `globalThis` to pass variables to global teardown. 15 | globalThis.__TEARDOWN_MESSAGE__ = '\nTearing down...\n'; 16 | }; 17 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/sections/backgrounds/BeyondStandardsBackground.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { getBrandColor } from '@/config/brand-colors'; 3 | 4 | /** 5 | * Deprecated: Split background (50% blue left, 50% white right) 6 | * This background was used in BeyondStandards.tsx before video background was implemented 7 | */ 8 | export function BeyondStandardsBackground() { 9 | return ( 10 |
11 |
12 |
13 |
14 | ); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /.railwayignore: -------------------------------------------------------------------------------- 1 | # Standard ignores 2 | node_modules 3 | .git 4 | .github 5 | *.log 6 | .DS_Store 7 | coverage 8 | .nyc_output 9 | 10 | # E2E tests (don't trigger deployments) 11 | dist/apps/evoque-api-e2e 12 | apps/evoque-api-e2e/** 13 | 14 | # Web app (separate service) 15 | apps/evoque-web/** 16 | 17 | # Web app E2E tests 18 | apps/evoque-web-e2e/** 19 | 20 | # WebSocket app (separate service at monorepo root) 21 | ../apps/websocket/** 22 | 23 | # WebSocket app (old location if still exists) 24 | apps/websocket/** 25 | 26 | # Root level apps (if any) 27 | ../apps/** 28 | 29 | # Only watch evoque-api related files 30 | # This service should only deploy when evoque-api changes 31 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "Debug evoque-api with Nx", 8 | "runtimeExecutable": "npx", 9 | "runtimeArgs": ["nx", "serve", "evoque-api"], 10 | "env": { 11 | "NODE_OPTIONS": "--inspect=9229" 12 | }, 13 | "console": "integratedTerminal", 14 | "internalConsoleOptions": "neverOpen", 15 | "skipFiles": ["/**"], 16 | "sourceMaps": true, 17 | "outFiles": [ 18 | "${workspaceFolder}/apps/evoque-api/dist/**/*.(m|c|)js", 19 | "!**/node_modules/**" 20 | ] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/admin/(studio)/pages/live-editor/preview/PreviewPage.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React from 'react'; 4 | import { Page, Section, MenuSection } from '@/types'; 5 | import ClientPageRenderer from '@/components/render/ClientPageRenderer'; 6 | 7 | interface PreviewPageProps { 8 | page: Page; 9 | sections: Section[]; 10 | menuSections: MenuSection[]; 11 | } 12 | 13 | export default function PreviewPage({ page, sections, menuSections }: PreviewPageProps) { 14 | return ( 15 | 20 | ); 21 | } 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /apps/evoque-web/.swcrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsc": { 3 | "target": "es2017", 4 | "parser": { 5 | "syntax": "typescript", 6 | "decorators": true, 7 | "dynamicImport": true 8 | }, 9 | "transform": { 10 | "decoratorMetadata": true, 11 | "legacyDecorator": true 12 | }, 13 | "keepClassNames": true, 14 | "externalHelpers": true, 15 | "loose": true 16 | }, 17 | "module": { 18 | "type": "commonjs" 19 | }, 20 | "sourceMaps": true, 21 | "exclude": [ 22 | "jest.config.[ct]s", 23 | ".*\\.spec.tsx?$", 24 | ".*\\.test.tsx?$", 25 | "./src/jest-setup.ts$", 26 | "./**/jest-setup.ts$", 27 | ".*.js$", 28 | ".*.d.ts$" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/shared/skeletons/PageTransitionSkeleton.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from '@/components/ui/skeleton'; 2 | 3 | export function PageTransitionSkeleton() { 4 | return ( 5 |
6 |
7 |
8 | 9 | 10 |
11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 | ); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /apps/evoque-api/src/app/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let app: TestingModule; 7 | 8 | beforeAll(async () => { 9 | app = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | }); 14 | 15 | describe('getData', () => { 16 | it('should return "Hello API"', () => { 17 | const appController = app.get(AppController); 18 | expect(appController.getData()).toEqual({ message: 'Hello API' }); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/pages/evoque.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "page-evoque", 3 | "slug": "", 4 | "title": "E-Voque Corporate Brochure", 5 | "description": "E-Voque - Beyond interpretation. Business process and marketing services outsourcing.", 6 | "sections": [ 7 | "evoque-hero-mdx", 8 | "evoque-about-mdx", 9 | "evoque-beyond-standards-mdx", 10 | "evoque-solutions-mdx", 11 | "evoque-hr-mdx", 12 | "evoque-why-peru-mdx", 13 | "evoque-we-know-our-people-mdx", 14 | "evoque-opportunities-mdx", 15 | "evoque-training-mdx", 16 | "evoque-advantage-mdx", 17 | "evoque-contact-mdx" 18 | ], 19 | "menuSections": [ 20 | "header-1", 21 | "footer-1" 22 | ], 23 | "isActive": true 24 | } 25 | 26 | -------------------------------------------------------------------------------- /apps/websocket/.railwayignore: -------------------------------------------------------------------------------- 1 | # Standard ignores 2 | node_modules 3 | .git 4 | .github 5 | *.log 6 | .DS_Store 7 | coverage 8 | .nyc_output 9 | 10 | # Evoque API main app (separate service) 11 | evoque-api/apps/evoque-api/** 12 | 13 | # Evoque API E2E tests 14 | evoque-api/apps/evoque-api-e2e/** 15 | 16 | # Web app (separate service) 17 | evoque-api/apps/evoque-web/** 18 | 19 | # Web app E2E tests 20 | evoque-api/apps/evoque-web-e2e/** 21 | 22 | # Nuo app (separate service) 23 | apps/nuo/** 24 | 25 | # Other apps at root (if any) 26 | apps/** 27 | 28 | # Only watch websocket related files 29 | # This service should only deploy when websocket changes 30 | # Note: We keep evoque-api/prisma/** and evoque-api/generated/** 31 | # as they are needed for the build 32 | 33 | -------------------------------------------------------------------------------- /apps/evoque-web/src/data/menu-sections/header-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "header-1", 3 | "type": "HEADER", 4 | "name": "Main Header", 5 | "content": { 6 | "logo": "/logo-evoque.png", 7 | "logoAlt": "E-Voque Logo", 8 | "menuId": "main-menu", 9 | "links": [ 10 | { "label": "Home", "url": "/", "isExternal": false }, 11 | { "label": "About", "url": "/about", "isExternal": false }, 12 | { "label": "Services", "url": "/services", "isExternal": false }, 13 | { "label": "Contact", "url": "/contact", "isExternal": false }, 14 | { "label": "Join Us", "url": "/join-us", "isExternal": false }, 15 | { "label": "Sign In", "url": "/sign-in", "isExternal": false } 16 | ] 17 | }, 18 | "order": 0, 19 | "isActive": true 20 | } 21 | 22 | -------------------------------------------------------------------------------- /apps/websocket/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); 2 | const { join } = require('path'); 3 | 4 | module.exports = { 5 | output: { 6 | path: join(__dirname, '../../dist/apps/websocket'), 7 | clean: true, 8 | ...(process.env.NODE_ENV !== 'production' && { 9 | devtoolModuleFilenameTemplate: '[absolute-resource-path]', 10 | }), 11 | }, 12 | plugins: [ 13 | new NxAppWebpackPlugin({ 14 | target: 'node', 15 | compiler: 'tsc', 16 | main: './src/main.ts', 17 | tsConfig: './tsconfig.app.json', 18 | assets: [], 19 | optimization: false, 20 | outputHashing: 'none', 21 | generatePackageJson: true, 22 | sourceMaps: true, 23 | }), 24 | ], 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /apps/evoque-web/src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |