diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..78a0604 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules/ +.next +.idea +Dockerfile +.dockerignore +npm-debug.log +README.md +.git \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 0000000..ebaf4f7 --- /dev/null +++ b/.env @@ -0,0 +1,10 @@ +NEXT_PUBLIC_SERVER_BASE_URL=https://api.bbuddy.expert/api +NEXT_PUBLIC_AGORA_APPID=ed90c9dc42634e5687d4e2e0766b363f +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51LVB3LK5pVGxNPeKk4gedt5NW4cb8k7BVXvgOMPTK4x1nnbGTD8BCqDqgInboT6N72YwrTl4tOsVz8rAjbUadX1m00y4Aq5qE8 +STRIPE_SECRET_KEY=sk_test_51LVB3LK5pVGxNPeK6j0wCsPqYMoGfcuwf1LpwGEBsr1dUx4NngukyjYL2oMZer5EOlW3lqnVEPjNDruN0OkUohIf00fWFUHN5O +STRIPE_PAYMENT_DESCRIPTION='BBuddy services' + +NEXT_PUBLIC_CONTENTFUL_SPACE_ID = voxpxjq7y7vf +NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN = s99GWKfpDKkNwiEJ3pN7US_tmqsGvDlaex-sOJwpzuc +NEXT_PUBLIC_CONTENTFUL_PREVIEW_ACCESS_TOKEN = Z9WOKpLDbKNj7xVOmT_VXYNLH0AZwISFvQsq0PQlHfE + diff --git a/Dockerfile b/Dockerfile index 820ce10..2e74df7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,23 @@ -FROM node:bookworm AS build -RUN node -v +FROM node:20.10.0 as dependencies +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm ci --verbose + +FROM node:20.10.0 as builder WORKDIR /app COPY . . -FROM nginx -COPY --from=build /app/dist /usr/share/nginx/html/ -RUN rm /etc/nginx/conf.d/default.conf -COPY _nginx/nginx.conf /etc/nginx/conf.d \ No newline at end of file +COPY --from=dependencies /app/node_modules ./node_modules +RUN npm run build --debug --verbose + +FROM node:20.10.0 as runner +WORKDIR /app +COPY . . + +ENV NODE_ENV production +COPY --from=builder /app/public ./public +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/.next ./.next +COPY --from=dependencies /app/node_modules ./node_modules + +EXPOSE 4200 +CMD ["npm", "start"] diff --git a/Dockerfile_standalone b/Dockerfile_standalone new file mode 100644 index 0000000..00d25f0 --- /dev/null +++ b/Dockerfile_standalone @@ -0,0 +1,34 @@ +FROM node:18-alpine AS base + +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn install --frozen-lockfile + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN yarn build + +FROM base AS runner +WORKDIR /app +ENV NODE_ENV production +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs +COPY --from=builder /app/public ./public + +RUN mkdir .next +RUN chown nextjs:nodejs .next + +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 4200 + +ENV PORT 4200 + +CMD HOSTNAME="0.0.0.0" node server.js diff --git a/Jenkinsfile b/Jenkinsfile index 2c6da33..9731ebd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,18 +1,18 @@ pipeline { agent { label 'jenkins-nodejs-agent' } - - - + environment { + RELEASE = "latest" + } stages { stage('Build static content') { steps { sh ''' - npm install - npm run build - pwd - echo - docker build --progress=plain -t bbuddy/bbuddy_ui:latest . + #npm install + #npm run build + #pwd + #echo + docker build --progress=plain -t bbuddy/bbuddy_ui:${RELEASE} . ''' } } @@ -20,10 +20,10 @@ pipeline { steps { sh ''' sudo docker login https://harbor-wtkp3fsbv6.vertexa.devbay.tech/ -u 'robot$jenkins' -p 'ZrzsVIAeueW1p0alpAnPfM5CDtaRVVKz' - sudo docker tag bbuddy/bbuddy_ui:latest harbor-wtkp3fsbv6.vertexa.devbay.tech/bbuddy/bbuddy_ui:latest - sudo docker push harbor-wtkp3fsbv6.vertexa.devbay.tech/bbuddy/bbuddy_ui:latest + sudo docker tag bbuddy/bbuddy_ui:${RELEASE} harbor-wtkp3fsbv6.vertexa.devbay.tech/bbuddy/bbuddy_ui:${RELEASE} + sudo docker push harbor-wtkp3fsbv6.vertexa.devbay.tech/bbuddy/bbuddy_ui:${RELEASE} ''' } } } -} \ No newline at end of file +} diff --git a/messages/de.json b/messages/de.json index 5ca66b1..27ce487 100644 --- a/messages/de.json +++ b/messages/de.json @@ -1,20 +1,10 @@ { - "Header": { - "registration": "Registration", - "enter": "Enter", - "account": "My Account", - "menu": { - "bb-client": "Start grow with BB", - "bb-expert": "Become BB Expert", - "blog": "Blog&News" - } - }, "Main": { "title": "Bbuddy - Main", "description": "Bbuddy desc", - "header": "Mentorship, Career\nDevelopment & Coaching.", - "header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.", - "news": "Professional Articles & Project News", + "header": "BBuddy: Plattform für persönlichen und beruflichen Erfolg", + "header-desc": "Erhalten Sie Beratungen von führenden Coaches und Mentoren auf BBuddy. Unsere Experten helfen Ihnen, sich zu entwickeln, zu lernen und Ihre persönlichen und beruflichen Ziele zu erreichen. Nutzen Sie unsere Web-Plattform und mobile App für professionelle Unterstützung und Wachstum.", + "news": "Fachartikel & Projektneuigkeiten", "popular": "Popular Topics" }, "BbClient": { @@ -89,7 +79,7 @@ } }, "Experts": { - "title": "Find a expert", + "title": "Einen Experten finden", "filter": { "price": "Price from {from}€ to {to}€", "duration": "Duration from {from}min to {to}min", diff --git a/messages/en.json b/messages/en.json index cbee258..1765bc8 100644 --- a/messages/en.json +++ b/messages/en.json @@ -2,8 +2,8 @@ "Main": { "title": "Bbuddy - Main", "description": "Bbuddy desc", - "header": "Mentorship, Career\nDevelopment & Coaching.", - "header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.", + "header": "BBuddy: Platform for Personal and Career Success", + "header-desc": "Receive consultations from leading coaches and mentors on BBuddy. Our experts will help you develop, learn, and achieve your personal and career goals. Use our web platform and mobile app for professional support and growth.", "news": "Professional Articles & Project News", "popular": "Popular Topics" }, @@ -69,7 +69,7 @@ } }, "Experts": { - "title": "Find a expert", + "title": "Find an expert", "filter": { "price": "Price from {from}€ to {to}€", "duration": "Duration from {from}min to {to}min", diff --git a/messages/es.json b/messages/es.json index 5ca66b1..3f7470b 100644 --- a/messages/es.json +++ b/messages/es.json @@ -1,20 +1,10 @@ { - "Header": { - "registration": "Registration", - "enter": "Enter", - "account": "My Account", - "menu": { - "bb-client": "Start grow with BB", - "bb-expert": "Become BB Expert", - "blog": "Blog&News" - } - }, "Main": { "title": "Bbuddy - Main", "description": "Bbuddy desc", - "header": "Mentorship, Career\nDevelopment & Coaching.", - "header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.", - "news": "Professional Articles & Project News", + "header": "BBuddy: Plataforma para el éxito personal y profesional", + "header-desc": "Reciba consultas de entrenadores y mentores líderes en BBuddy. Nuestros expertos le ayudarán a desarrollarse, aprender y alcanzar sus objetivos personales y profesionales. Utilice nuestra plataforma web y aplicación móvil para apoyo profesional y crecimiento.", + "news": "Artículos profesionales y Noticias de proyectos", "popular": "Popular Topics" }, "BbClient": { @@ -89,7 +79,7 @@ } }, "Experts": { - "title": "Find a expert", + "title": "Encontrar un experto", "filter": { "price": "Price from {from}€ to {to}€", "duration": "Duration from {from}min to {to}min", diff --git a/messages/fr.json b/messages/fr.json index 5ca66b1..bad196d 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -1,20 +1,10 @@ { - "Header": { - "registration": "Registration", - "enter": "Enter", - "account": "My Account", - "menu": { - "bb-client": "Start grow with BB", - "bb-expert": "Become BB Expert", - "blog": "Blog&News" - } - }, "Main": { "title": "Bbuddy - Main", "description": "Bbuddy desc", - "header": "Mentorship, Career\nDevelopment & Coaching.", - "header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.", - "news": "Professional Articles & Project News", + "header": "BBuddy: Plateforme pour le succès personnel et professionnel", + "header-desc": "Recevez des consultations de coachs et mentors de premier plan sur BBuddy. Nos experts vous aideront à développer, apprendre et atteindre vos objectifs personnels et professionnels. Utilisez notre plateforme web et notre application mobile pour un soutien professionnel et une croissance.", + "news": "Articles professionnels et actualités des projets", "popular": "Popular Topics" }, "BbClient": { @@ -89,7 +79,7 @@ } }, "Experts": { - "title": "Find a expert", + "title": "Trouver un expert", "filter": { "price": "Price from {from}€ to {to}€", "duration": "Duration from {from}min to {to}min", diff --git a/messages/it.json b/messages/it.json index 5ca66b1..0874d7a 100644 --- a/messages/it.json +++ b/messages/it.json @@ -1,20 +1,10 @@ { - "Header": { - "registration": "Registration", - "enter": "Enter", - "account": "My Account", - "menu": { - "bb-client": "Start grow with BB", - "bb-expert": "Become BB Expert", - "blog": "Blog&News" - } - }, "Main": { "title": "Bbuddy - Main", "description": "Bbuddy desc", - "header": "Mentorship, Career\nDevelopment & Coaching.", - "header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.", - "news": "Professional Articles & Project News", + "header": "BBuddy: Piattaforma per il successo personale e professionale", + "header-desc": "Ricevi consulenze da coach e mentori leader su BBuddy. I nostri esperti ti aiuteranno a svilupparti, imparare e raggiungere i tuoi obiettivi personali e professionali. Usa la nostra piattaforma web e l'app mobile per supporto professionale e crescita.", + "news": "Articoli professionali e novità sui progetti", "popular": "Popular Topics" }, "BbClient": { @@ -89,7 +79,7 @@ } }, "Experts": { - "title": "Find a expert", + "title": "Trova un esperto", "filter": { "price": "Price from {from}€ to {to}€", "duration": "Duration from {from}min to {to}min", diff --git a/messages/ru.json b/messages/ru.json index 64fb88a..94d8e2e 100644 --- a/messages/ru.json +++ b/messages/ru.json @@ -1,20 +1,10 @@ { - "Header": { - "registration": "Регистрация", - "enter": "Вход", - "account": "Мой аккаунт", - "menu": { - "bb-client": "Начни вместе с BB", - "bb-expert": "Стань BB экспертом", - "blog": "Блог&Новости" - } - }, "Main": { "title": "Bbuddy - Главная", "description": "Bbuddy описание", - "header": "Mentorship, Career\nDevelopment & Coaching.", - "header-desc": "The ins-and-outs of building a career in tech, gaining experience from a mentor, and getting your feet wet with coaching.", - "news": "Professional Articles & Project News", + "header": "BBuddy: Платформа для Личного и Карьерного Успеха", + "header-desc": "Получайте консультации от ведущих коучей и менторов в BBuddy. Наши эксперты помогут вам развиваться, обучаться и достигать личных и карьерных целей. Используйте нашу веб-платформу и мобильное приложение для получения профессиональной поддержки и роста.", + "news": "Профессиональные статьи и новости проекта", "popular": "Popular Topics" }, "BbClient": { diff --git a/next.config.js b/next.config.js index 466969a..0cfa5f5 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,7 @@ // @ts-check const withNextIntl = require('next-intl/plugin')(); const path = require('path'); +const json = require('./package.json'); /** @type {import('next').NextConfig} */ const nextConfig = { @@ -14,6 +15,9 @@ const nextConfig = { sassOptions: { includePaths: [path.join(__dirname, 'styles')], }, + env: { + version: json.version + }, typescript: { // !! WARN !! // Dangerously allow production builds to successfully complete even if @@ -28,11 +32,9 @@ const nextConfig = { taint: true, // typedRoutes: true }, - output: 'export', - distDir: 'dist', + // output: 'standalone', poweredByHeader: false, - productionBrowserSourceMaps: true, - trailingSlash: true + productionBrowserSourceMaps: true }; module.exports = withNextIntl(nextConfig); diff --git a/package.json b/package.json index d48b35e..531f7c1 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "bbuddy-ui", - "version": "0.0.1", + "version": "0.3.0", "private": true, "scripts": { "dev": "next dev -p 4200", "build": "next build", - "start": "next start", + "start": "next start -p 4200", "lint": "next lint" }, "dependencies": { @@ -14,9 +14,17 @@ "@ant-design/nextjs-registry": "^1.0.0", "@greatsumini/react-facebook-login": "^3.3.3", "@react-oauth/google": "^0.12.1", + "@contentful/rich-text-react-renderer": "^15.22.9", + "@microsoft/signalr": "^8.0.7", + "@stripe/react-stripe-js": "^2.7.3", + "@stripe/stripe-js": "^4.1.0", + "agora-rtc-react": "2.1.0", + "agora-rtc-sdk-ng": "^4.20.2", "antd": "^5.12.1", "antd-img-crop": "^4.21.0", + "antd-style": "^3.6.2", "axios": "^1.6.5", + "contentful": "^10.13.3", "dayjs": "^1.11.10", "lodash": "^4.17.21", "next": "14.0.3", @@ -24,8 +32,11 @@ "react": "^18", "react-apple-login": "^1.1.6", "react-dom": "^18", + "react-signalr": "^0.2.24", "react-slick": "^0.29.0", + "react-stripe-js": "^1.1.5", "slick-carousel": "^1.8.1", + "stripe": "^16.2.0", "styled-components": "^6.1.1" }, "devDependencies": { diff --git a/public/.well-known/apple-app-site-association b/public/.well-known/apple-app-site-association new file mode 100644 index 0000000..90ddeb9 --- /dev/null +++ b/public/.well-known/apple-app-site-association @@ -0,0 +1,11 @@ +{ + "applinks": { + "apps": [], + "details": [ + { + "appID": "GTYAM4FYH3.com.bbuddy.whistle", + "paths": ["/en/experts/*"] + } + ] + } +} \ No newline at end of file diff --git a/public/.well-known/assetlinks.json b/public/.well-known/assetlinks.json new file mode 100644 index 0000000..ddaf1a5 --- /dev/null +++ b/public/.well-known/assetlinks.json @@ -0,0 +1,14 @@ +[ + { + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "com.bbuddy.whistle", + "sha256_cert_fingerprints": [ + "87:A2:49:9A:F4:05:9C:06:3C:3D:F3:10:88:F5:49:6D:5F:F2:BC:1E:90:0D:F2:37:A5:BA:37:19:5C:A3:75:C2", + "D0:28:97:E7:64:5D:ED:8D:7F:F1:41:B2:E8:F6:AB:7B:EE:FB:A3:1A:A2:D7:92:D4:C5:41:9A:3C:47:CE:EB:43", + "86:42:FE:EA:44:22:9D:16:7F:FC:70:92:A6:39:9D:B1:C3:F1:DE:21:32:4A:45:8C:07:98:39:55:AF:47:32:66" + ] + } + } +] diff --git a/public/favicon.ico b/public/favicon.ico index 718d6fe..f285885 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/images/decline-sign.svg b/public/images/decline-sign.svg new file mode 100644 index 0000000..4be8a74 --- /dev/null +++ b/public/images/decline-sign.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/actions/auth.ts b/src/actions/auth.ts index 2da04c6..b136f7c 100644 --- a/src/actions/auth.ts +++ b/src/actions/auth.ts @@ -1,26 +1,14 @@ -import { AxiosResponse } from 'axios'; -import { apiClient } from '../lib/apiClient'; +import { apiRequest } from './helpers'; -export const getAuth = (locale: string, data: { login: string, password: string }): Promise> => ( - apiClient.post( - '/auth/login', - data, - { - headers: { - 'X-User-Language': locale - } - } - ) -); +export const getAuth = (locale: string, data: { login: string, password: string }): Promise<{ jwtToken: string }> => apiRequest({ + url: '/auth/login', + method: 'post', + data, + locale +}); -export const getRegister = (locale: string): Promise> => ( - apiClient.post( - '/auth/register', - {}, - { - headers: { - 'X-User-Language': locale - } - } - ) -); +export const getRegister = (locale: string): Promise<{ jwtToken: string }> => apiRequest({ + url: '/auth/register', + method: 'post', + locale +}); diff --git a/src/actions/chat/groups.ts b/src/actions/chat/groups.ts new file mode 100644 index 0000000..0409c88 --- /dev/null +++ b/src/actions/chat/groups.ts @@ -0,0 +1,16 @@ +import {apiRequest} from "../helpers"; + + +export const getChatList = (locale: string, token: string): Promise => apiRequest({ + url: '/chat/chatList', + method: 'get', + locale, + token +}); + +export const getChatMessages = (locale: string, token: string, group: number): Promise => apiRequest({ + url: '/chat/chat_messages/'+group, + method: 'get', + locale, + token +}); diff --git a/src/actions/experts.ts b/src/actions/experts.ts index 5c24bdc..3b7cd51 100644 --- a/src/actions/experts.ts +++ b/src/actions/experts.ts @@ -1,30 +1,31 @@ -import { apiClient } from '../lib/apiClient'; -import { GeneralFilter, ExpertsData, ExpertDetails } from '../types/experts'; +import { apiRequest } from './helpers'; +import { GeneralFilter, ExpertsData, ExpertDetails, ExpertScheduler, ExpertSchedulerSession, SignupSessionData } from '../types/experts'; -export const getExpertsList = async (filter: GeneralFilter, locale: string) => { - const response = await apiClient.post( - '/home/coachsearch1', - { ...filter }, - { - headers: { - 'X-User-Language': locale - } - } - ); +export const getExpertsList = (locale: string, filter?: GeneralFilter): Promise => apiRequest({ + url: '/home/coachsearch1', + method: 'post', + data: { ...filter }, + locale +}); - return response.data as ExpertsData || null; -}; +export const getExpertById = (id: string, locale: string): Promise => apiRequest({ + url: '/home/coachdetails', + method: 'post', + data: { id }, + locale +}); -export const getExpertById = async (id: string, locale: string) => { - const response = await apiClient.post( - '/home/coachdetails', - { id }, - { - headers: { - 'X-User-Language': locale - } - } - ); +export const getSchedulerByExpertId = (id: string, locale: string): Promise => apiRequest({ + url: '/home/sessionsignupdata', + method: 'post', + data: { id }, + locale +}); - return response.data as ExpertDetails || null; -}; +export const getSchedulerSession = (data: SignupSessionData, locale: string, token: string): Promise => apiRequest({ + url: '/home/sessionsignupsubmit', + method: 'post', + data, + locale, + token +}); diff --git a/src/actions/helpers.ts b/src/actions/helpers.ts new file mode 100644 index 0000000..812980d --- /dev/null +++ b/src/actions/helpers.ts @@ -0,0 +1,44 @@ +import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'; +import { apiClient } from '../lib/apiClient'; + +type RequiredConfigParams = Required> & Pick, 'data'>; +export type PageRequestConfig = RequiredConfigParams & Partial> & { locale?: string, token?: string }; + +export const apiRequest = async ( + baseParams: PageRequestConfig, +): Promise => { + try { + const config = { + url: baseParams.url, + method: baseParams.method, + data: baseParams?.data, + headers: { + 'X-User-Language': baseParams?.locale || 'en', + 'X-Referrer-Channel': 'site', + ...(baseParams?.token ? { Authorization: `Bearer ${baseParams.token}` } : {}), + ...(baseParams.headers || {}) + } + }; + const response: AxiosResponse = await apiClient.request, T>(config as AxiosRequestConfig); + + return response.data; + } catch (err) { + const { + response: { + status: responseCode = null, + statusText = '', + data, + } = {}, + code: statusCode = '', + } = err as AxiosError; + + throw new Error( + JSON.stringify({ + statusCode, + statusMessage: statusText, + responseCode, + details: data + }), + ); + } +}; diff --git a/src/actions/hooks/useProfileSettings.ts b/src/actions/hooks/useProfileSettings.ts index 14a67d1..365d08d 100644 --- a/src/actions/hooks/useProfileSettings.ts +++ b/src/actions/hooks/useProfileSettings.ts @@ -1,40 +1,37 @@ 'use client' -import { useCallback, useEffect, useState } from 'react'; -import { Profile } from '../../types/profile'; -import { getPersonalData } from '../profile'; +import { useCallback, useState } from 'react'; +import { ProfileData, ProfileRequest } from '../../types/profile'; +import { getPersonalData, setPersonData } from '../profile'; import { useLocalStorage } from '../../hooks/useLocalStorage'; import { AUTH_TOKEN_KEY } from '../../constants/common'; export const useProfileSettings = (locale: string) => { const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, ''); - const [profileSettings, setProfileSettings] = useState(); + const [profileSettings, setProfileSettings] = useState(); const [fetchLoading, setFetchLoading] = useState(false); - const [saveLoading, setSaveLoading] = useState(false); - useEffect(() => { + const fetchProfileSettings = () => { if (jwt) { getPersonalData(locale, jwt) - .then(({ data }) => { + .then((data) => { setProfileSettings(data); }) .catch((err) => { - + console.log(err); }) .finally(() => { setFetchLoading(false); }); } - }, []); + }; - const save = useCallback(() => { - - }, []); + const save = useCallback((data: ProfileRequest) => setPersonData(data, locale, jwt), []); return { fetchLoading, + fetchProfileSettings, save, - saveLoading, profileSettings }; }; diff --git a/src/actions/hooks/useRoomDetails.ts b/src/actions/hooks/useRoomDetails.ts new file mode 100644 index 0000000..ff3163d --- /dev/null +++ b/src/actions/hooks/useRoomDetails.ts @@ -0,0 +1,51 @@ +'use client' + +import {useCallback, useEffect, useState} from 'react'; +import {useLocalStorage} from '../../hooks/useLocalStorage'; +import {AUTH_TOKEN_KEY} from '../../constants/common'; +import {Room} from '../../types/rooms'; +import {getRoomDetails} from '../rooms'; +import {SessionState} from "../../types/sessions"; + +export const useRoomDetails = (locale: string, roomId: number) => { + const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, ''); + const [room, setRoom] = useState(); + const [errorData, setErrorData] = useState(); + const [loading, setLoading] = useState(false); + const [isStarted, setIsStarted] = useState(false); + + const fetchData = useCallback(() => { + setLoading(true); + setErrorData(undefined); + setRoom(undefined); + + getRoomDetails(locale, jwt, roomId) + .then((room) => { + setRoom(room); + }) + .catch((err) => { + setErrorData(err); + }) + .finally(() => { + setLoading(false); + }) + }, []); + + useEffect(() => { + fetchData(); + }, []); + + useEffect(() => { + if (room?.state === SessionState.STARTED) { + setIsStarted(true); + } + }, [room?.state]) + + return { + fetchData, + loading, + room, + errorData, + isStarted + }; +}; diff --git a/src/actions/hooks/useSessionDetails.ts b/src/actions/hooks/useSessionDetails.ts new file mode 100644 index 0000000..107590d --- /dev/null +++ b/src/actions/hooks/useSessionDetails.ts @@ -0,0 +1,42 @@ +'use client' + +import { useCallback, useEffect, useState } from 'react'; +import { useLocalStorage } from '../../hooks/useLocalStorage'; +import { AUTH_TOKEN_KEY } from '../../constants/common'; +import { Session } from '../../types/sessions'; +import { getSessionDetails } from '../sessions'; + +export const useSessionDetails = (locale: string, sessionId: number) => { + const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, ''); + const [session, setSession] = useState(); + const [errorData, setErrorData] = useState(); + const [loading, setLoading] = useState(false); + + const fetchData = useCallback(() => { + setLoading(true); + setErrorData(undefined); + setSession(undefined); + + getSessionDetails(locale, jwt, sessionId) + .then((session) => { + setSession(session); + }) + .catch((err) => { + setErrorData(err); + }) + .finally(() => { + setLoading(false); + }) + }, []); + + useEffect(() => { + fetchData(); + }, []); + + return { + fetchData, + loading, + session, + errorData + }; +}; diff --git a/src/actions/hooks/useSessionTracking.ts b/src/actions/hooks/useSessionTracking.ts new file mode 100644 index 0000000..4f8018c --- /dev/null +++ b/src/actions/hooks/useSessionTracking.ts @@ -0,0 +1,46 @@ +'use client' + +import { useCallback, useEffect, useRef } from 'react'; +import { useLocalStorage } from '../../hooks/useLocalStorage'; +import { AUTH_TOKEN_KEY } from '../../constants/common'; +import { trackingStartSession } from '../sessions'; + +const DURATION = 30000; + +export const useSessionTracking = (locale: string, sessionId: number) => { + const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, ''); + const timer = useRef(); + + const fetchData = useCallback(() => { + trackingStartSession(locale, jwt, sessionId) + .then(() => { + console.log('tracking success'); + }) + .catch((err) => { + console.log('tracking error', err); + }) + }, []); + + useEffect(() => { + return () => { + window.clearInterval(timer.current); + } + }, []); + + const start = () => { + window.clearInterval(timer.current); + + timer.current = window.setInterval(() => { + fetchData(); + }, DURATION); + }; + + const stop = () => { + window.clearInterval(timer.current); + }; + + return { + start, + stop + }; +}; diff --git a/src/actions/profile.ts b/src/actions/profile.ts index 53462bf..5d517ef 100644 --- a/src/actions/profile.ts +++ b/src/actions/profile.ts @@ -1,75 +1,103 @@ -import { AxiosResponse } from 'axios'; -import { apiClient } from '../lib/apiClient'; -import { Profile } from '../types/profile'; -import { Session, SessionsFilter } from '../types/sessions'; +import { PayInfo, Profile, ProfileRequest, ProfileData } from '../types/profile'; +import { ExpertsTags } from '../types/tags'; +import { EducationData, EducationDTO } from '../types/education'; +import { PracticeData, PracticeDTO } from '../types/practice'; +import { ScheduleDTO } from '../types/schedule'; +import { apiRequest } from './helpers'; -export const setPersonData = (person: { login: string, password: string, role: string, languagesLinks: any[] }, locale: string, jwt: string): Promise> => ( - apiClient.post( - '/home/applyperson1', - { ...person }, - { - headers: { - 'X-User-Language': locale, - Authorization: `Bearer ${jwt}` - } - } - ) -); +export const getUserData = (locale: string, token: string): Promise => apiRequest({ + url: '/home/userdata', + method: 'post', + locale, + token +}); -export const getPersonalData = (locale: string, jwt: string): Promise> => ( - apiClient.post( - '/home/userdata', - {}, - { - headers: { - 'X-User-Language': locale, - Authorization: `Bearer ${jwt}` - } - } - ) -); +export const getPersonalData = (locale: string, token: string): Promise => apiRequest({ + url: '/home/person1', + method: 'post', + locale, + token +}); -export const getUpcomingSessions = (locale: string, jwt: string, filter?: SessionsFilter): Promise> => ( - apiClient.post( - '/home/upcomingsessionsall', - { - sessionType: 'session', - ...(filter || {}) - }, - { - headers: { - 'X-User-Language': locale, - Authorization: `Bearer ${jwt}` - } - } - ) -); +export const setPersonData = (data: ProfileRequest, locale: string, token: string): Promise<{ userData: Profile }> => apiRequest({ + url: '/home/applyperson1', + method: 'post', + data, + locale, + token +}); -export const getRequestedSessions = (locale: string, jwt: string): Promise> => ( - apiClient.post( - '/home/coachhomedata', - {}, - { - headers: { - 'X-User-Language': locale, - Authorization: `Bearer ${jwt}` - } - } - ) -); +export const getEducation = (locale: string, token: string): Promise => apiRequest({ + url: '/home/person2', + method: 'post', + locale, + token +}); -export const getRecentSessions = (locale: string, jwt: string, filter?: SessionsFilter): Promise> => ( - apiClient.post( - '/home/historicalmeetings ', - { - sessionType: 'session', - ...(filter || {}) - }, - { - headers: { - 'X-User-Language': locale, - Authorization: `Bearer ${jwt}` - } - } - ) -); +export const setEducation = (locale: string, token: string, data: EducationData): Promise => apiRequest({ + url: '/home/applyperson2', + method: 'post', + data, + locale, + token +}); + +export const getTags = (locale: string, token: string): Promise => apiRequest({ + url: '/home/person3', + method: 'post', + locale, + token +}); + +export const setTags = (locale: string, token: string, data: ExpertsTags): Promise => apiRequest({ + url: '/home/applyperson3', + method: 'post', + data, + locale, + token +}); + +export const getPractice = (locale: string, token: string): Promise => apiRequest({ + url: '/home/person4', + method: 'post', + locale, + token +}); + +export const setPractice = (locale: string, token: string, data: PracticeData): Promise => apiRequest({ + url: '/home/applyperson4', + method: 'post', + data, + locale, + token +}); + +export const getSchedule = (locale: string, token: string): Promise => apiRequest({ + url: '/home/person51', + method: 'post', + locale, + token +}); + +export const setSchedule = (locale: string, token: string, data: ScheduleDTO): Promise => apiRequest({ + url: '/home/applyperson51', + method: 'post', + data, + locale, + token +}); + +export const getPayData = (locale: string, token: string): Promise<{ person6Data?: PayInfo }> => apiRequest({ + url: '/home/person6', + method: 'post', + locale, + token +}); + +export const setPayData = (locale: string, token: string, data: PayInfo): Promise => apiRequest({ + url: '/home/applyperson6', + method: 'post', + data, + locale, + token +}); diff --git a/src/actions/rooms.ts b/src/actions/rooms.ts new file mode 100644 index 0000000..c1a8b83 --- /dev/null +++ b/src/actions/rooms.ts @@ -0,0 +1,125 @@ +import { apiRequest } from './helpers'; +import {GetUsersForRooms, Report, ReportData, Room, RoomEdit, RoomEditDTO} from '../types/rooms'; + +export const getUpcomingRooms = (locale: string, token: string): Promise => apiRequest({ + url: '/home/upcomingsessionsall', + method: 'post', + data: { + sessionType: 'room' + }, + locale, + token +}); + +export const getRecentRooms = (locale: string, token: string): Promise => apiRequest({ + url: '/home/historicalmeetings', + method: 'post', + data: { + sessionType: 'room' + }, + locale, + token +}); + +export const getRoomDetails = (locale: string, token: string, id: number): Promise => apiRequest({ + url: '/home/room', + method: 'post', + data: { id }, + locale, + token +}); + +export const deleteRoomClient = (locale: string, token: string, data: { sessionId: number, clientUserId: number }): Promise => apiRequest({ + url: '/home/deleteclientfromroom', + method: 'post', + data, + locale, + token +}); + +export const deleteRoomSupervisor = (locale: string, token: string, data: { sessionId: number, supervisorUserId: number }): Promise => apiRequest({ + url: '/home/deletesupervisorfromroom', + method: 'post', + data, + locale, + token +}); + +export const becomeRoomClient = (locale: string, token: string, data: { sessionId: number, clientUserId: number }): Promise => apiRequest({ + url: '/home/becomeroomclient', + method: 'post', + data, + locale, + token +}); + +export const becomeRoomSupervisor = (locale: string, token: string, data: { sessionId: number, supervisorUserId: number }): Promise => apiRequest({ + url: '/home/becomeroomsupervisor', + method: 'post', + data, + locale, + token +}); + +export const getUsersList = (locale: string, token: string, data: { template: string }): Promise => apiRequest({ + url: '/home/findusersforroom', + method: 'post', + data, + locale, + token +}); + +export const addClient = (locale: string, token: string, data: { sessionId: number, clientUserId: number }): Promise => apiRequest({ + url: '/home/addclienttoroom', + method: 'post', + data, + locale, + token +}); + +export const addSupervisor = (locale: string, token: string, data: { sessionId: number, supervisorUserId: number }): Promise => apiRequest({ + url: '/home/addsupervisortoroom', + method: 'post', + data, + locale, + token +}); + +export const createRoom = (locale: string, token: string): Promise => apiRequest({ + url: '/home/createroom', + method: 'post', + locale, + token +}); + +export const updateRoom = (locale: string, token: string, data: RoomEdit): Promise => apiRequest({ + url: '/home/updateroom', + method: 'post', + data, + locale, + token +}); + +export const getRoomById = (locale: string, token: string, id: number): Promise => apiRequest({ + url: '/home/getroomforedit', + method: 'post', + data: { id }, + locale, + token +}); + +// report +export const getReport = (locale: string, token: string, id: number): Promise => apiRequest({ + url: `/home/getsessionsupervisorscores?sessionId=${id}`, + method: 'post', + locale, + token +}); + +export const saveReport = (locale: string, token: string, data: ReportData): Promise => apiRequest({ + url: '/home/setsessionsupervisorscores', + method: 'post', + data, + locale, + token +}); diff --git a/src/actions/sessions.ts b/src/actions/sessions.ts new file mode 100644 index 0000000..4bdc084 --- /dev/null +++ b/src/actions/sessions.ts @@ -0,0 +1,101 @@ +import { DeclineSessionData, Session, SessionsFilter, SessionCommentData } from '../types/sessions'; +import { apiRequest } from './helpers'; + +export const getUpcomingSessions = (locale: string, token: string, filter?: SessionsFilter): Promise => apiRequest({ + url: '/home/upcomingsessionsall', + method: 'post', + data: { + sessionType: 'session', + ...(filter || {}) + }, + locale, + token +}); + +export const getRequestedSessions = (locale: string, token: string): Promise<{ requestedSessions: Session[] }> => apiRequest({ + url: '/home/coachhomedata', + method: 'post', + locale, + token +}); + +export const getRecentSessions = (locale: string, token: string, filter?: SessionsFilter): Promise => apiRequest({ + url: '/home/historicalmeetings', + method: 'post', + data: { + sessionType: 'session', + ...(filter || {}) + }, + locale, + token +}); + +export const getSessionDetails = (locale: string, token: string, id: number): Promise => apiRequest({ + url: '/home/session', + method: 'post', + data: { id }, + locale, + token +}); + +export const approveRequestedSession = (locale: string, token: string, sessionId: number): Promise => apiRequest({ + url: '/home/approverequestedsession', + method: 'post', + data: { sessionId }, + locale, + token +}); + +export const declineRequestedSession = (locale: string, token: string, { sessionId, reason }: DeclineSessionData): Promise => apiRequest({ + url: '/home/declinerequestedsession', + method: 'post', + data: { + sessionId, + coachDeclineReason: reason + }, + locale, + token +}); + +export const cancelUpcomingSession = (locale: string, token: string, { sessionId, reason }: DeclineSessionData): Promise => apiRequest({ + url: '/home/cancelupcomingsession', + method: 'post', + data: { + sessionId, + coachCancelReason: reason + }, + locale, + token +}); + +export const addSessionComment = (locale: string, token: string, data: SessionCommentData): Promise => apiRequest({ + url: '/home/session_comment', + method: 'post', + data, + locale, + token +}); + +export const trackingStartSession = (locale: string, token: string, id: number): Promise => apiRequest({ + url: '/home/sessiontracking', + method: 'post', + data: { id }, + locale, + token +}); + +export const finishSession = (locale: string, token: string, sessionId: number): Promise => apiRequest({ + url: '/home/finishsession', + method: 'post', + data: { sessionId }, + locale, + token +}); + +export const sessionPaymentConfirm = (locale: string, token: string, sessionId: number): Promise => apiRequest({ + url: '/home/session_pay_confirm', + method: 'post', + data: { id: sessionId }, + locale, + token +}); diff --git a/src/actions/stripe.ts b/src/actions/stripe.ts new file mode 100644 index 0000000..989796d --- /dev/null +++ b/src/actions/stripe.ts @@ -0,0 +1,79 @@ +"use server"; + +import { Stripe } from "stripe"; + +import { headers } from "next/headers"; + +import { formatAmountForStripe } from "../utils/stripe-helpers"; +import { stripe } from "../lib/stripe"; + +export async function createCheckoutSession( + data: FormData, +): Promise<{ client_secret: string | null; url: string | null }> { + const ui_mode = data.get( + "uiMode", + ) as Stripe.Checkout.SessionCreateParams.UiMode; + console.log('DATA', data) + const origin: string = headers().get("origin") as string; + + const checkoutSession: Stripe.Checkout.Session = + await stripe.checkout.sessions.create({ + mode: "payment", + submit_type: "donate", + line_items: [ + { + quantity: 1, + price_data: { + currency: 'eur', + product_data: { + name: "Custom amount donation", + }, + unit_amount: formatAmountForStripe( + Number(data.get("customDonation") as string), + 'eur', + ), + }, + }, + ], + ...(ui_mode === "hosted" && { + success_url: `${origin}/payment/with-checkout/result?session_id={CHECKOUT_SESSION_ID}`, + cancel_url: `${origin}/with-checkout`, + }), + ...(ui_mode === "embedded" && { + return_url: `${origin}/payment/with-embedded-checkout/result?session_id={CHECKOUT_SESSION_ID}`, + }), + ui_mode, + }); + + return { + client_secret: checkoutSession.client_secret, + url: checkoutSession.url, + }; +} + +export async function createPaymentIntent( + data: { amount: number, sessionId?: string }, +): Promise<{ client_secret: string }> { + + const params = { + amount: formatAmountForStripe( + data.amount, + 'eur', + ), + automatic_payment_methods: { enabled: true }, + currency: 'eur', + } as Stripe.PaymentIntentCreateParams; + + if (data?.sessionId){ + params.metadata = { + sessionId : data.sessionId + } + } + + const paymentIntent: Stripe.PaymentIntent = + await stripe.paymentIntents.create(params); + + return { client_secret: paymentIntent.client_secret as string }; +} + +export const getStripePaymentStatus = async (payment_intent: string): Promise => await stripe.paymentIntents.retrieve(payment_intent); \ No newline at end of file diff --git a/src/actions/tags.ts b/src/actions/tags.ts index 7443607..7fd18cd 100644 --- a/src/actions/tags.ts +++ b/src/actions/tags.ts @@ -1,29 +1,14 @@ -import { apiClient } from '../lib/apiClient'; import { SearchData, Languages } from '../types/tags'; +import { apiRequest } from './helpers'; -export const getTagList = async (locale: string) => { - const response = await apiClient.post( - '/home/searchdata', - {}, - { - headers: { - 'X-User-Language': locale - } - } - ); +export const getTagList = (locale: string): Promise => apiRequest({ + url: '/home/searchdata', + method: 'post', + locale +}); - return response.data as SearchData || null; -}; - -export const getLanguages = async (locale: string) => { - const response = await apiClient.get( - '/home/languages', - { - headers: { - 'X-User-Language': locale - } - } - ); - - return response.data as Languages || null; -}; +export const getLanguages = (locale: string): Promise => apiRequest({ + url: '/home/languages', + method: 'get', + locale +}); diff --git a/src/actions/upload.ts b/src/actions/upload.ts new file mode 100644 index 0000000..f41ef95 --- /dev/null +++ b/src/actions/upload.ts @@ -0,0 +1,13 @@ +import { ExpertDocument } from '../types/file'; +import { apiRequest } from './helpers'; + +export const setUploadFile = (locale: string, token: string, data: any): Promise => apiRequest({ + url: '/home/uploadfile', + method: 'post', + data, + locale, + token, + headers: { + 'Content-Type': 'multipart/form-data' + } +}); diff --git a/src/app/[locale]/(main)/@directions/page.tsx b/src/app/[locale]/(main)/@directions/page.tsx index 339743a..64d241c 100644 --- a/src/app/[locale]/(main)/@directions/page.tsx +++ b/src/app/[locale]/(main)/@directions/page.tsx @@ -1,6 +1,9 @@ import React from 'react'; +import { unstable_setRequestLocale } from 'next-intl/server'; + +export default function Directions({ params: { locale } }: { params: { locale: string } }) { + unstable_setRequestLocale(locale); -export default function Directions() { return (
diff --git a/src/app/[locale]/(main)/@experts/page.tsx b/src/app/[locale]/(main)/@experts/page.tsx index b39c521..824f6f3 100644 --- a/src/app/[locale]/(main)/@experts/page.tsx +++ b/src/app/[locale]/(main)/@experts/page.tsx @@ -1,8 +1,10 @@ import React from 'react'; +import { unstable_setRequestLocale } from 'next-intl/server'; import { useTranslations } from 'next-intl'; import { Experts } from '../../../../components/Experts/Experts'; -export default function ExpertsPage({ params }: { params: { locale: string } }) { +export default function ExpertsPage({ params: { locale } }: { params: { locale: string } }) { + unstable_setRequestLocale(locale); const t = useTranslations('Experts'); return ( @@ -14,7 +16,7 @@ export default function ExpertsPage({ params }: { params: { locale: string } })
- + ); diff --git a/src/app/[locale]/(main)/@news/page.tsx b/src/app/[locale]/(main)/@news/page.tsx index 15bce46..014a183 100644 --- a/src/app/[locale]/(main)/@news/page.tsx +++ b/src/app/[locale]/(main)/@news/page.tsx @@ -1,65 +1,40 @@ import React from 'react'; +// import { useTranslations } from 'next-intl'; +import Link from 'next/link'; +import { getTranslations, unstable_setRequestLocale } from 'next-intl/server'; +import { i18nText } from '../../../../i18nKeys'; +import { fetchBlogPosts } from '../../../../lib/contentful/blogPosts'; + +export default async function News({params: {locale}}: { params: { locale: string } }) { + unstable_setRequestLocale(locale); + const t = await getTranslations('Main'); + const { data, total } = await fetchBlogPosts({preview: false, sticky: true}) -export default function News() { return (
-

Professional Articles & Project News

+

{t('news')}

-
-
-
- -
-
-
News Headline
-
- The program not only focuses on a financial perspective, but allows you to study - performance from many angles, such as human resources management, IT, operations - management, risks etc. + {data.map((item, i) => ( +
+
+
+ {item.listImage?.alt}/ +
+
+
{item.title}
+
+ {item.excerpt} +
+ + {i18nText('readMore', locale)} + +
- Read more - -
-
-
-
-
- -
-
-
News Headline
-
- The program not only focuses on a financial perspective, but allows you to study - performance from many angles, such as human resources management, IT, operations - management, risks etc. -
- Read more - - -
-
-
-
-
-
- -
-
-
News Headline
-
- The program not only focuses on a financial perspective, but allows you to study - performance from many angles, such as human resources management, IT, operations - management, risks etc. -
- Read more - - -
-
-
+ ))} +
diff --git a/src/app/[locale]/(main)/layout.tsx b/src/app/[locale]/(main)/layout.tsx index daa1e7d..ed99329 100644 --- a/src/app/[locale]/(main)/layout.tsx +++ b/src/app/[locale]/(main)/layout.tsx @@ -12,18 +12,17 @@ import React, { ReactNode } from 'react'; // }; // } -export default function MainLayout({ children, news, directions, experts }: { +export default function MainLayout({ children, news, experts }: { children: ReactNode, news: ReactNode, - directions: ReactNode, - experts: ReactNode + experts: ReactNode, + payment: ReactNode }) { return ( <> {children} {news} - {directions} {experts} ); -}; +} diff --git a/src/app/[locale]/account/(account)/work-with-us/coaching/add-offer/page.tsx b/src/app/[locale]/account/(account)/expert-profile/add-offer/page.tsx similarity index 94% rename from src/app/[locale]/account/(account)/work-with-us/coaching/add-offer/page.tsx rename to src/app/[locale]/account/(account)/expert-profile/add-offer/page.tsx index 04ec673..7ed015c 100644 --- a/src/app/[locale]/account/(account)/work-with-us/coaching/add-offer/page.tsx +++ b/src/app/[locale]/account/(account)/expert-profile/add-offer/page.tsx @@ -1,18 +1,18 @@ import React from 'react'; -import { Link } from '../../../../../../../navigation'; -import { CustomSelect } from '../../../../../../../components/view/CustomSelect'; +import { Link } from '../../../../../../navigation'; +import { CustomSelect } from '../../../../../../components/view/CustomSelect'; export default function AddOffer() { return ( <>
  1. - + Work With Us
  2. - + Coaching
  3. diff --git a/src/app/[locale]/account/(account)/work-with-us/new-topic/page.tsx b/src/app/[locale]/account/(account)/expert-profile/new-topic/page.tsx similarity index 97% rename from src/app/[locale]/account/(account)/work-with-us/new-topic/page.tsx rename to src/app/[locale]/account/(account)/expert-profile/new-topic/page.tsx index a7b33ed..f8b6774 100644 --- a/src/app/[locale]/account/(account)/work-with-us/new-topic/page.tsx +++ b/src/app/[locale]/account/(account)/expert-profile/new-topic/page.tsx @@ -7,7 +7,7 @@ export default function NewTopic() { <>
    1. - + Work With Us
    2. diff --git a/src/app/[locale]/account/(account)/expert-profile/page.tsx b/src/app/[locale]/account/(account)/expert-profile/page.tsx new file mode 100644 index 0000000..1a46bcf --- /dev/null +++ b/src/app/[locale]/account/(account)/expert-profile/page.tsx @@ -0,0 +1,70 @@ +'use client' + +import { useEffect, useState } from 'react'; +import { message } from 'antd'; +// import { unstable_setRequestLocale } from 'next-intl/server'; +import { ExpertData } from '../../../../../types/profile'; +import { AUTH_TOKEN_KEY } from '../../../../../constants/common'; +import { useLocalStorage } from '../../../../../hooks/useLocalStorage'; +import { + getEducation, + getPersonalData, + getTags, + getPractice, + getSchedule, + getPayData, + getUserData +} from '../../../../../actions/profile'; +import { ExpertProfile } from '../../../../../components/ExpertProfile'; +import { Loader } from '../../../../../components/view/Loader'; + +export default function ExpertProfilePage({ params: { locale } }: { params: { locale: string } }) { + // unstable_setRequestLocale(locale); + const [jwt] = useLocalStorage(AUTH_TOKEN_KEY, ''); + const [loading, setLoading] = useState(false); + const [data, setData] = useState(); + const [isFull, setIsFull] = useState(false); + + useEffect(() => { + if (jwt) { + setLoading(true); + Promise.all([ + getUserData(locale, jwt), + getPersonalData(locale, jwt), + getEducation(locale, jwt), + getTags(locale, jwt), + getPractice(locale, jwt), + getSchedule(locale, jwt), + getPayData(locale, jwt) + ]) + .then(([profile, person, education, tags, practice, schedule, payData]) => { + setIsFull(profile.fillProgress === 'full'); + setData({ + person, + education, + tags, + practice, + schedule, + payData + }); + }) + .catch(() => { + message.error('Не удалось загрузить данные эксперта'); + }) + .finally(() => { + setLoading(false); + }) + } + }, [jwt]); + + return data ? ( + + + + ) : null; +}; diff --git a/src/app/[locale]/account/(account)/information/page.tsx b/src/app/[locale]/account/(account)/information/page.tsx index 42e1f74..3475709 100644 --- a/src/app/[locale]/account/(account)/information/page.tsx +++ b/src/app/[locale]/account/(account)/information/page.tsx @@ -1,5 +1,6 @@ import React from 'react'; import type { Metadata } from 'next'; +import { unstable_setRequestLocale } from 'next-intl/server'; import { useTranslations } from 'next-intl'; import { i18nText } from '../../../../../i18nKeys'; @@ -9,6 +10,7 @@ export const metadata: Metadata = { }; export default function Information({ params: { locale } }: { params: { locale: string } }) { + unstable_setRequestLocale(locale); const t = useTranslations('Account.LegalInformation'); return ( diff --git a/src/app/[locale]/account/(account)/layout.tsx b/src/app/[locale]/account/(account)/layout.tsx index 5c46a60..f6a63ab 100644 --- a/src/app/[locale]/account/(account)/layout.tsx +++ b/src/app/[locale]/account/(account)/layout.tsx @@ -2,34 +2,19 @@ import React, { ReactNode } from 'react'; import { AccountMenu } from '../../../../components/Account'; -import { i18nText } from '../../../../i18nKeys'; type AccountInnerLayoutProps = { children: ReactNode; params: { locale: string }; }; -const ROUTES = ['sessions', 'notifications', 'support', 'information', 'settings', 'messages', 'work-with-us']; -const COUNTS: Record = { - sessions: 12, - notifications: 5, - messages: 113 -}; - - export default function AccountInnerLayout({ children, params: { locale } }: AccountInnerLayoutProps) { - const getMenuConfig = () => ROUTES.map((path) => ({ - path, - title: i18nText(`accountMenu.${path}`, locale), - count: COUNTS[path] || undefined - })); - return (
      - +
      diff --git a/src/app/[locale]/account/(account)/messages/[textId]/page.tsx b/src/app/[locale]/account/(account)/messages/[textId]/page.tsx index 669063c..095e3b8 100644 --- a/src/app/[locale]/account/(account)/messages/[textId]/page.tsx +++ b/src/app/[locale]/account/(account)/messages/[textId]/page.tsx @@ -1,8 +1,9 @@ +'use client' import React from 'react'; -import { useTranslations } from 'next-intl'; import { Link } from '../../../../../../navigation'; import { i18nText } from '../../../../../../i18nKeys'; - +import {ChatMessages} from "../../../../../../components/Chat/ChatMessages"; +/* export function generateStaticParams({ params: { locale }, }: { params: { locale: string } }) { @@ -15,56 +16,22 @@ export function generateStaticParams({ return result; } +* + */ -export default function Message({ params }: { params: { locale: string, textId: string } }) { - const t = useTranslations('Account.Messages'); +export default function Message({ params: { locale, textId } }: { params: { locale: string, textId: string } }) { return ( <>
      1. - {i18nText('accountMenu.messages', params.locale)} + {i18nText('accountMenu.messages', locale)}
      2. -
      3. {`Person ${params.textId}`}
      -
      -
      -
      -
      -
      - -
      -
      - 🤩 It all for you! - - 07.09.2022 -
      -
      -
      -
      -
      -
      - -
      -
      - 🤩 It all for you! - 07.09.2022 -
      -
      -
      -
      -
      -