Compare commits

..

No commits in common. "fcd103b8c84f8bcf1cc9bb00ad8b3282ea603d11" and "e1119c4b42743f96f848f28bd7e8547a21effd69" have entirely different histories.

64 changed files with 616 additions and 1899 deletions

1
.gitignore vendored
View File

@ -15,7 +15,6 @@
# production
/dist
/build
# ide
/.idea

View File

@ -30,37 +30,6 @@
},
"Messages": {
"title": "Messages"
},
"Settings": {
"title": "Profile Settings",
"photo-desc": "Add a real photo, as a person's face is always more credible.",
"name": "Name",
"surname": "Surname",
"birthday": "Date of Birth",
"email": "E-mail",
"change-password": "Change Password",
"save": "Save",
"old-password": "Old Password",
"new-password": "New Password",
"confirm-password": "Confirm Password"
},
"LegalInformation": {
"title": "Legal Information"
},
"Support": {
"title": "Help & Support"
},
"Notifications": {
"title": "Notifications",
"read": "Read",
"delete": "Delete"
},
"Sessions": {
"upcoming-sessions": "Upcoming Sessions",
"sessions-requested": "Sessions Requested",
"recent-sessions": "Recent Sessions",
"topic": "Topic",
"day-start": "Day start"
}
},
"Footer": {

View File

@ -31,37 +31,6 @@
},
"Messages": {
"title": "Messages"
},
"Settings": {
"title": "Profile Settings",
"photo-desc": "Add a real photo, as a person's face is always more credible.",
"name": "Name",
"surname": "Surname",
"birthday": "Date of Birth",
"email": "E-mail",
"change-password": "Change Password",
"save": "Save",
"old-password": "Old Password",
"new-password": "New Password",
"confirm-password": "Confirm Password"
},
"LegalInformation": {
"title": "Legal Information"
},
"Support": {
"title": "Help & Support"
},
"Notifications": {
"title": "Notifications",
"read": "Read",
"delete": "Delete"
},
"Sessions": {
"upcoming-sessions": "Upcoming Sessions",
"sessions-requested": "Sessions Requested",
"recent-sessions": "Recent Sessions",
"topic": "Topic",
"day-start": "Day start"
}
},
"Footer": {

View File

@ -30,37 +30,6 @@
},
"Messages": {
"title": "Messages"
},
"Settings": {
"title": "Profile Settings",
"photo-desc": "Add a real photo, as a person's face is always more credible.",
"name": "Name",
"surname": "Surname",
"birthday": "Date of Birth",
"email": "E-mail",
"change-password": "Change Password",
"save": "Save",
"old-password": "Old Password",
"new-password": "New Password",
"confirm-password": "Confirm Password"
},
"LegalInformation": {
"title": "Legal Information"
},
"Support": {
"title": "Help & Support"
},
"Notifications": {
"title": "Notifications",
"read": "Read",
"delete": "Delete"
},
"Sessions": {
"upcoming-sessions": "Upcoming Sessions",
"sessions-requested": "Sessions Requested",
"recent-sessions": "Recent Sessions",
"topic": "Topic",
"day-start": "Day start"
}
},
"Footer": {

View File

@ -30,37 +30,6 @@
},
"Messages": {
"title": "Messages"
},
"Settings": {
"title": "Profile Settings",
"photo-desc": "Add a real photo, as a person's face is always more credible.",
"name": "Name",
"surname": "Surname",
"birthday": "Date of Birth",
"email": "E-mail",
"change-password": "Change Password",
"save": "Save",
"old-password": "Old Password",
"new-password": "New Password",
"confirm-password": "Confirm Password"
},
"LegalInformation": {
"title": "Legal Information"
},
"Support": {
"title": "Help & Support"
},
"Notifications": {
"title": "Notifications",
"read": "Read",
"delete": "Delete"
},
"Sessions": {
"upcoming-sessions": "Upcoming Sessions",
"sessions-requested": "Sessions Requested",
"recent-sessions": "Recent Sessions",
"topic": "Topic",
"day-start": "Day start"
}
},
"Footer": {

View File

@ -30,37 +30,6 @@
},
"Messages": {
"title": "Messages"
},
"Settings": {
"title": "Profile Settings",
"photo-desc": "Add a real photo, as a person's face is always more credible.",
"name": "Name",
"surname": "Surname",
"birthday": "Date of Birth",
"email": "E-mail",
"change-password": "Change Password",
"save": "Save",
"old-password": "Old Password",
"new-password": "New Password",
"confirm-password": "Confirm Password"
},
"LegalInformation": {
"title": "Legal Information"
},
"Support": {
"title": "Help & Support"
},
"Notifications": {
"title": "Notifications",
"read": "Read",
"delete": "Delete"
},
"Sessions": {
"upcoming-sessions": "Upcoming Sessions",
"sessions-requested": "Sessions Requested",
"recent-sessions": "Recent Sessions",
"topic": "Topic",
"day-start": "Day start"
}
},
"Footer": {

View File

@ -23,44 +23,13 @@
"work-with-us": "Работать с нами"
},
"WorkWithUs": {
"title": "Стань BBuddy экспертом",
"title": "Become a BBuddy Expert",
"insert-info": "Insert your personal information to start your journey as a BBuddy Expert",
"start": "Начать",
"start": "Get Started",
"base-text": "Your info can either be added or amended at anytime"
},
"Messages": {
"title": "Сообщения"
},
"Settings": {
"title": "Настройки пользователя",
"photo-desc": "Добавьте реальное фото, это вызывает больше доверия",
"name": "Имя",
"surname": "Фамилия",
"birthday": "Дата рождения",
"email": "E-mail",
"change-password": "Изменить пароль",
"save": "Сохранить изменения",
"old-password": "Старый пароль",
"new-password": "Новый пароль",
"confirm-password": "Подтверждение пароля"
},
"LegalInformation": {
"title": "Legal Information"
},
"Support": {
"title": "Помощь и поддержка"
},
"Notifications": {
"title": "Оповещения",
"read": "Смотреть",
"delete": "Удалить"
},
"Sessions": {
"upcoming-sessions": "Upcoming Sessions",
"sessions-requested": "Sessions Requested",
"recent-sessions": "Recent Sessions",
"topic": "Тема",
"day-start": "Дата начала"
}
},
"Footer": {

View File

@ -14,27 +14,9 @@ const nextConfig = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
},
images: {
unoptimized: true
},
experimental: {
taint: true,
typedRoutes: true
},
output: 'export',
distDir: 'dist',
poweredByHeader: false,
productionBrowserSourceMaps: true,
trailingSlash: true
// redirects: async () => {
// return [
// {
// source: '/en/',
// destination: '/en.html',
// permanent: true
// }
// ]
// }
cleanDistDir: true,
distDir: 'dist'
};
module.exports = withNextIntl(nextConfig);

152
package-lock.json generated
View File

@ -11,7 +11,6 @@
"@ant-design/cssinjs": "^1.18.1",
"@ant-design/icons": "^5.2.6",
"antd": "^5.12.1",
"axios": "^1.6.5",
"next": "14.0.3",
"next-intl": "^3.3.1",
"react": "^18",
@ -1124,11 +1123,6 @@
"has-symbols": "^1.0.3"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/autoprefixer": {
"version": "10.4.16",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
@ -1187,16 +1181,6 @@
"node": ">=4"
}
},
"node_modules/axios": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"dependencies": {
"follow-redirects": "^1.15.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axobject-query": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
@ -1419,17 +1403,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/compute-scroll-into-view": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
@ -1551,14 +1524,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@ -2278,25 +2243,6 @@
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
"dev": true
},
"node_modules/follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@ -2306,19 +2252,6 @@
"is-callable": "^1.1.3"
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@ -3247,25 +3180,6 @@
"node": ">=8.6"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -3710,11 +3624,6 @@
"react-is": "^16.13.1"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@ -6029,11 +5938,6 @@
"has-symbols": "^1.0.3"
}
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"autoprefixer": {
"version": "10.4.16",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
@ -6060,16 +5964,6 @@
"integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==",
"dev": true
},
"axios": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"requires": {
"follow-redirects": "^1.15.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"axobject-query": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
@ -6219,14 +6113,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"compute-scroll-into-view": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
@ -6325,11 +6211,6 @@
"object-keys": "^1.1.1"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@ -6895,11 +6776,6 @@
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
"dev": true
},
"follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw=="
},
"for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@ -6909,16 +6785,6 @@
"is-callable": "^1.1.3"
}
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"fraction.js": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@ -7592,19 +7458,6 @@
"picomatch": "^2.3.1"
}
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -7901,11 +7754,6 @@
"react-is": "^16.13.1"
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",

View File

@ -3,7 +3,7 @@
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "next dev -p 4200",
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
@ -12,7 +12,6 @@
"@ant-design/cssinjs": "^1.18.1",
"@ant-design/icons": "^5.2.6",
"antd": "^5.12.1",
"axios": "^1.6.5",
"next": "14.0.3",
"next-intl": "^3.3.1",
"react": "^18",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,11 +0,0 @@
<svg width="192" height="60" viewBox="0 0 192 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M37.0913 31.7816V13.8849C35.9805 13.613 34.829 13.477 33.6233 13.477C32.7022 13.477 31.9029 13.5314 31.1849 13.6402L31.2391 26.3147C34.1788 26.4371 36.1431 28.9121 36.1431 31.7816C36.1431 34.719 34.0839 37.2621 31.0223 37.2621C27.893 37.2621 25.8339 34.719 25.8339 31.7816C25.8339 31.4688 25.861 31.1696 25.9016 30.884L25.7662 0.380859L12.9237 1.4416V31.7816C12.9237 36.4597 14.2648 40.3627 16.5814 43.3546L39.2047 40.9611C37.85 38.3772 37.0913 35.2902 37.0913 31.7816Z" fill="#35E2CF"/>
<path d="M22.542 48.1416C25.2243 49.4199 28.3672 50.0863 31.8216 50.0863C36.1295 50.0863 40.2478 48.7263 43.4855 46.1289C43.4042 46.0745 43.3365 46.0065 43.2687 45.9385L22.542 48.1416Z" fill="#35E2CF"/>
<path d="M43.4855 46.1291C46.7367 48.6858 51.0446 50.0865 55.9893 50.0865C61.7602 50.0865 67.2061 47.6522 70.6063 43.0557L43.77 45.8979C43.6887 45.9795 43.5803 46.0475 43.4855 46.1291Z" fill="#5AADCC"/>
<path d="M43.2687 45.9519C43.3365 46.0063 43.4178 46.0743 43.4855 46.1423C43.5803 46.0607 43.6887 45.9791 43.7835 45.9111L43.2687 45.9519Z" fill="#5AADCC"/>
<path d="M57.791 13.4633C56.8698 13.4633 56.0705 13.5177 55.3525 13.6265L55.4067 26.301C58.3464 26.4234 60.3107 28.8985 60.3107 31.7679C60.3107 34.7054 58.2516 37.2484 55.19 37.2484C52.0607 37.2484 50.0015 34.7054 50.0015 31.7679C50.0015 31.4551 50.0286 31.1559 50.0693 30.8568L50.0015 15.6664V0.367188H49.9338L37.0913 1.42793V13.8713V31.7815C37.0913 35.3037 37.8364 38.3772 39.1911 40.9746L48.2269 40.0227L73.3699 37.3708C73.8711 35.5757 74.1556 33.6038 74.1556 31.4551C74.1692 22.4932 67.3144 13.4633 57.791 13.4633Z" fill="#5AADCC"/>
<path d="M81.2813 26.0283V42.2115C81.2813 46.5904 83.0288 49.0655 87.1877 49.0655C91.7395 49.0655 94.6385 47.42 94.6385 37.6013V26.6131L97.4427 26.0283V50.9966L94.6385 51.391V47.352H94.5437C93.5818 49.5415 90.6692 51.5814 86.9439 51.5814C80.7936 51.5814 78.4771 48.0863 78.4771 42.5514V26.6131L81.2813 26.0283Z" fill="#5AADCC"/>
<path d="M123.06 16.4139L125.864 15.8291V51.0104L123.06 51.5952V46.9306H122.965C121.123 49.3649 117.397 51.5952 113.428 51.5952C106.357 51.5952 100.748 46.4003 100.748 38.7167C100.748 31.5771 106.316 26.0422 113.333 26.0422C117.302 26.0422 120.594 28.1364 122.965 30.8563H123.06V16.4139ZM113.184 28.8572C107.427 28.8572 103.552 33.8617 103.552 38.7167C103.552 44.4012 107.427 48.7801 113.279 48.7801C118.698 48.7801 123.06 44.17 123.06 38.8663C123.06 32.5426 118.508 28.8572 113.184 28.8572Z" fill="#5AADCC"/>
<path d="M151.712 16.4139L154.516 15.8291V51.0104L151.712 51.5952V46.9306H151.617C149.774 49.3649 146.049 51.5952 142.08 51.5952C135.008 51.5952 129.4 46.4003 129.4 38.7167C129.4 31.5771 134.968 26.0422 141.985 26.0422C145.954 26.0422 149.246 28.1364 151.617 30.8563H151.712V16.4139ZM141.836 28.8572C136.078 28.8572 132.204 33.8617 132.204 38.7167C132.204 44.4012 136.078 48.7801 141.931 48.7801C147.349 48.7801 151.712 44.17 151.712 38.8663C151.712 32.5426 147.16 28.8572 141.836 28.8572Z" fill="#5AADCC"/>
<path d="M155.288 26.6131L158.051 26.0283L167.778 43.8162L176.299 26.0283L179.103 26.6131L162.888 59.9449L160.178 59.3601L166.18 46.7808L155.288 26.6131Z" fill="#5AADCC"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

View File

@ -1,14 +0,0 @@
import { AxiosResponse } from 'axios';
import { apiClient } from '../lib/apiClient';
export const getAuth = (login: string, password: string, locale: string ): Promise<AxiosResponse<{ jwtToken: string }>> => (
apiClient.post(
'/auth/login',
{ login, password },
{
headers: {
'X-User-Language': locale
}
}
)
);

View File

@ -1,32 +0,0 @@
import { apiClient } from '../lib/apiClient';
import { Filter, ExpertsData, ExpertDetails } from '../types/experts';
export const getExpertsList = async (filter: Filter, locale: string) => {
const response = await apiClient.post(
'/home/coachsearch',
{ ...filter },
{
headers: {
'X-User-Language': locale,
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJuYW1laWQiOiIxNzIiLCJuYmYiOjE3MDM2ODMyMDgsImV4cCI6MTczNTIxOTIwOCwiaWF0IjoxNzAzNjgzMjA4fQ.KgnYfKO7oVFLlDuKhfyNN6RAaXKdeSzJd7F4r6_15AA'
}
}
);
return response.data?.coaches as ExpertsData || null;
};
export const getExpertById = async (id: string, locale: string) => {
const response = await apiClient.post(
'/home/coachdetails',
{ id },
{
headers: {
'X-User-Language': locale,
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJuYW1laWQiOiIxNzIiLCJuYmYiOjE3MDM2ODMyMDgsImV4cCI6MTczNTIxOTIwOCwiaWF0IjoxNzAzNjgzMjA4fQ.KgnYfKO7oVFLlDuKhfyNN6RAaXKdeSzJd7F4r6_15AA'
}
}
);
return response.data as ExpertDetails || null;
};

View File

@ -9,7 +9,7 @@ export default function Directions() {
<div className="main-popular__coll">
<div className="b-popular">
<div className="b-popular__image">
<img className="" src="/images/popular1.png" alt=""/>
<img className="" src="/images/popular.png" alt=""/>
</div>
<div className="b-popular__inner">
<div className="b-popular__title">Work Life Balance</div>
@ -23,10 +23,10 @@ export default function Directions() {
<div className="main-popular__coll">
<div className="b-popular">
<div className="b-popular__image">
<img className="" src="/images/popular2.png" alt=""/>
<img className="" src="/images/popular.png" alt=""/>
</div>
<div className="b-popular__inner">
<div className="b-popular__title">Strategic Session</div>
<div className="b-popular__title">Work Life Balance</div>
<div className="b-popular__wrap-link">
<a className="b-popular__link" href="">23 experts</a> |
<a className="b-popular__link" href="">245 offers</a>
@ -37,10 +37,10 @@ export default function Directions() {
<div className="main-popular__coll d-none d-md-block">
<div className="b-popular">
<div className="b-popular__image">
<img className="" src="/images/popular3.png" alt=""/>
<img className="" src="/images/popular.png" alt=""/>
</div>
<div className="b-popular__inner">
<div className="b-popular__title">Personal Growth</div>
<div className="b-popular__title">Work Life Balance</div>
<div className="b-popular__wrap-link">
<a className="b-popular__link" href="">23 experts</a> |
<a className="b-popular__link" href="">245 offers</a>
@ -51,10 +51,10 @@ export default function Directions() {
<div className="main-popular__coll d-none d-lg-block">
<div className="b-popular">
<div className="b-popular__image">
<img className="" src="/images/popular4.png" alt=""/>
<img className="" src="/images/popular.png" alt=""/>
</div>
<div className="b-popular__inner">
<div className="b-popular__title">Career Planning</div>
<div className="b-popular__title">Work Life Balance</div>
<div className="b-popular__wrap-link">
<a className="b-popular__link" href="">23 experts</a> |
<a className="b-popular__link" href="">245 offers</a>
@ -65,10 +65,10 @@ export default function Directions() {
<div className="main-popular__coll d-none d-lg-block">
<div className="b-popular">
<div className="b-popular__image">
<img className="" src="/images/popular5.png" alt=""/>
<img className="" src="/images/popular.png" alt=""/>
</div>
<div className="b-popular__inner">
<div className="b-popular__title">Executive Coaching</div>
<div className="b-popular__title">Work Life Balance</div>
<div className="b-popular__wrap-link">
<a className="b-popular__link" href="">23 experts</a> |
<a className="b-popular__link" href="">245 offers</a>
@ -79,10 +79,10 @@ export default function Directions() {
<div className="main-popular__coll d-none d-xl-block">
<div className="b-popular">
<div className="b-popular__image">
<img className="" src="/images/popular6.png" alt=""/>
<img className="" src="/images/popular.png" alt=""/>
</div>
<div className="b-popular__inner">
<div className="b-popular__title">Career Development</div>
<div className="b-popular__title">Work Life Balance</div>
<div className="b-popular__wrap-link">
<a className="b-popular__link" href="">23 experts</a> |
<a className="b-popular__link" href="">245 offers</a>

View File

@ -1,20 +1,76 @@
import React from 'react';
import { CustomPagination } from '../../../../components/view';
import { ExpertsFilter } from '../../../../components/Experts/Filter';
import { ExpertsAdditionalFilter } from '../../../../components/Experts/AdditionalFilter';
import { ExpertsList } from '../../../../components/Experts/ExpertsList';
import { getExpertsList } from '../../../../actions/experts';
'use client';
export default async function Experts({ params }: { params: { locale: string } }) {
const data = await getExpertsList({
"themesTagIds": [
1,2,3,4,5,6,7,8
],
"priceFrom": null,
"priceTo": null,
"durationFrom": null,
"durationTo": null
}, params.locale);
import React from 'react';
import { Avatar, List, Typography, Tag } from 'antd';
import { RightOutlined } from '@ant-design/icons';
import { Link } from '../../../../navigation';
import { ExpertsFilter, ExpertsAdditionalFilter } from '../../../../components/Experts';
const { Text } = Typography;
const data = Array.from({ length: 10 }).map((_, i) => ({
href: '/',
name: 'Matthew Weeks',
avatar: '/images/person.png',
duration: '45min',
price: '45$',
skills: ['Engineering & Data', 'Soft skills', 'Interview'],
speciality: 'Senior Software Engineer',
specialityDesc: 'Auth0',
description: 'I have worked across a variety of organizations, lead teams, and delivered quality software for 8 years. In that time I\'ve worked as an independent consultant, at agencies as a team lead, and as a senior engineer at Auth0. I also host a podcast https://anchor.fm/work-in-programming where I break down how …'
}));
export default function Experts() {
const expertsList = (
<List
itemLayout="vertical"
size="large"
pagination={{
className: 'pagination',
onChange: (page) => {
console.log(page);
},
pageSize: 5
}}
dataSource={data}
renderItem={(item) => (
<List.Item key={item.name}>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={item.name}
description={(
<div className="card-profile__header__price">
{item.price} <span>/ {item.duration}</span>
</div>
)}
/>
<div className="card-profile__skills">
<div className="skills__list">
{item.skills.map((skill) => <Tag color="#f50">{skill}</Tag>)}
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__more">+6</div>
</div>
</div>
<div className="card-profile__title">{item.speciality}</div>
<div className="card-profile__subtitle">{item.specialityDesc}</div>
<div className="card-profile__desc">{item.description}</div>
<div className="card-profile__footer">
<Link href={item.href as any}>
<Text
copyable={{
icon: <RightOutlined key="copy-icon" style={{ fontSize: '15px' }}/>,
onCopy: undefined,
tooltips: false
}}
>
Details
</Text>
</Link>
</div>
</List.Item>
)}
/>
);
return (
<div className="main-find">
@ -27,12 +83,54 @@ export default async function Experts({ params }: { params: { locale: string } }
</div>
<div className="row">
<div className="col-xl-3 col-lg-4 d-none d-lg-block">
<ExpertsFilter locale={params.locale} />
<ExpertsFilter />
</div>
<div className="col-xl-9 col-lg-8 ">
<ExpertsAdditionalFilter />
<ExpertsList data={data} locale={params.locale} />
<CustomPagination total={20} />
<div className="search-result">
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__price">
45$ <span>/ 45min</span>
</div>
</div>
</div>
<div className="card-profile__skills">
<div className="skills__list">
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__more">+6</div>
</div>
</div>
<div className="card-profile__title">Senior Software Engineer</div>
<div className="card-profile__subtitle">Auth0</div>
<div className="card-profile__desc">
I have worked across a variety of organizations, lead teams, and delivered quality
software for 8 years. In that time I've worked as an independent consultant, at
agencies as a team lead, and as a senior engineer at Auth0. I also host a podcast
https://anchor.fm/work-in-programming where I break down how …
</div>
<div className="card-profile__footer">
<a href="#">Details
<img className="" src="/images/chevron-forward.svg" alt="" />
</a>
</div>
</div>
{expertsList}
</div>
<ul className="pagination">
<li className="page-item"><a className="page-link" href="#">1</a></li>
<li className="page-item active" aria-current="page">
<a className="page-link" href="#">2</a>
</li>
<li className="page-item"><a className="page-link" href="#">3</a></li>
<li className="page-item"><a className="page-link" href="#">4</a></li>
</ul>
</div>
</div>
</div>

View File

@ -1,16 +1,16 @@
import React, { ReactNode } from 'react';
// import { getTranslations } from 'next-intl/server';
//
// export async function generateMetadata({
// params: { locale }
// }: { params: { locale: string }}) {
// const t = await getTranslations({ locale, namespace: 'Main' });
//
// return {
// title: t('title'),
// description: t('description'),
// };
// }
import { getTranslations } from 'next-intl/server';
export async function generateMetadata({
params: { locale }
}: { params: { locale: string }}) {
const t = await getTranslations({ locale, namespace: 'Main' });
return {
title: t('title'),
description: t('description'),
};
}
export default function MainLayout({ children, news, directions, experts }: {
children: ReactNode,

View File

@ -19,20 +19,12 @@ export default function Home() {
<p className="main-top__text">from a mentor, and getting your feet wet with coaching.</p>
</div>
<div className="main-top__wrap-btn">
<a
href="https://apps.apple.com/us/app/bbuddy/id6443601377?platform=iphone"
className="main-top__btn main-top__btn--apple"
target="_blank"
>
<a href="#" className="main-top__btn main-top__btn--apple">
<img className="" src="/images/logo-apple.svg" alt=""/>
<span className="line" />
AppStore
</a>
<a
href="https://play.google.com/store/apps/details?id=com.bbuddy.whistle"
className="main-top__btn main-top__btn--android"
target="_blank"
>
<a href="#" className="main-top__btn main-top__btn--android">
<img className="" src="/images/logo-android.svg" alt=""/>
<span className="line" />
GooglePlay

View File

@ -1,6 +1,5 @@
import React from 'react';
import type { Metadata } from 'next';
import { useTranslations } from 'next-intl';
export const metadata: Metadata = {
title: 'Bbuddy - Account - Information',
@ -8,68 +7,9 @@ export const metadata: Metadata = {
};
export default function Information() {
const t = useTranslations('Account.LegalInformation');
return (
<>
<ol className="breadcrumb">
<li className="breadcrumb-item active" aria-current="page">{t('title')}</li>
</ol>
<div className="base-text">
Welcome to the B BUDDY LTDs privacy policy. <br />
B BUDDY LTD respects your privacy and is committed to protecting your personal data. This privacy policy
will inform you as to how we collect, use and look after your personal data. It further describes your
privacy rights and the control you can exercise in relation to your personal data.
</div>
<h3 className="title-h3">
Important Information
</h3>
<div className="base-text">
This privacy policy is issued on behalf of B BUDDY LTD which is the controller of your personal data. B
BUDDY LTD is a limited liability company registered in the Republic of Cyprus with registration number
HE 417576.
<br />
This privacy policy is addressed to individuals outside B BUDDY LTD with whom we interact, including
individual clients, representatives, directors, shareholders, beneficial owners, coaches and/or
mentors and/or consultants of our application and/or website as well as other users of our services
and suppliers.
</div>
<h3 className="title-h3">What Personal Date We Collect About You?</h3>
<div className="base-text">
We may collect, use, store and transfer different kinds of personal data about you which we have grouped
together as follows:<br />
Identity Data includes first name, maiden name, last name, username or similar identifier, title,
date of birth, gender;<br />
Contact Data includes billing address, delivery address, email address, and telephone numbers
(including mobile telephone number(s)), postal address.<br />
Business Data includes date identifying you in relation to matters on which you instruct us or
in which you are involved such as diplomas and any other educational document or
certificate;<br />
Consent Records Data includes records of any consents you have given us, together with the date,
means of consent and any other information provided such as the subject matter of the consent
provided;<br />
Supplier Data includes contact details and other information about you or your company or
organisation where you provide services to B BUDDY LTD;<br />
Tracker (i.e. any technology - e.g Cookies, unique identifiers, web beacons, embedded scripts,
e-tags and fingerprinting - that enables the tracking of Users, for example by accessing or
storing information on the Users device);<br />
Usage Data (i.e information collected automatically through this Website (or third-party
services employed in this Website), which can include: the IP addresses or domain names of the
computers utilized by the Users who use this Website, the URI addresses (Uniform Resource
Identifier), the time of the request, the method utilized to submit the request to the server,
the size of the file received in response, the numerical code indicating the status of the
server's answer (successful outcome, error, etc.), the country of origin, the features of the
browser and the operating system utilized by the User, the various time details per visit (e.g.,
the time spent on each page within the Application) and the details about the path followed
within the Application with special reference to the sequence of pages visited, and other
parameters about the device operating system and/or the User's IT environment.);<br />
Any other information relating to you which you may provide us with, such as health personal
data, if required by us to be able to provide our services to you.<br />
B BUDDY LTD does not collect any payment details data as they are collected directly by Stripe,
Inc. which is responsible to effect the payments. Stripe, Inc. is a PCI Service Provider Level 1
and it is obliged to follow PCI compliance and the General Data Protection Regulations 2018
(GDPR).
</div>
</>
<div>
Страница Информации о пользователе
</div>
);
};
}

View File

@ -1,55 +1,15 @@
import React from 'react';
import type { Metadata } from 'next';
import { useTranslations } from 'next-intl';
export const metadata: Metadata = {
title: 'Bbuddy - Account - Notifications',
description: 'Bbuddy desc notifications'
title: 'Bbuddy - Account - Information',
description: 'Bbuddy desc information'
};
export default function Notifications() {
const t = useTranslations('Account.Notifications');
export default function Information() {
return (
<>
<ol className="breadcrumb">
<li className="breadcrumb-item active" aria-current="page">{t('title')}</li>
</ol>
<div className="list-notifications ">
<div className="b-notifications primary">
<div className="b-notifications__title">Notification Headline</div>
<div className="b-notifications__text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc auctor leo eu justo molestie
</div>
<div className="b-notifications__date">25 may 2022</div>
<div className="b-notifications__inner">
<a href="#" className="b-notifications__read">{t('read')}</a>
<a href="#" className="b-notifications__delete">{t('delete')}</a>
</div>
</div>
<div className="b-notifications primary">
<div className="b-notifications__title">Notification Headline</div>
<div className="b-notifications__text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc auctor leo eu justo molestie
</div>
<div className="b-notifications__date">25 may 2022</div>
<div className="b-notifications__inner">
<a href="#" className="b-notifications__read">{t('read')}</a>
<a href="#" className="b-notifications__delete">{t('delete')}</a>
</div>
</div>
<div className="b-notifications danger">
<div className="b-notifications__title">Notification Headline</div>
<div className="b-notifications__text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc auctor leo eu justo molestie
</div>
<div className="b-notifications__date">25 may 2022</div>
<div className="b-notifications__inner">
<a href="#" className="b-notifications__read">{t('read')}</a>
<a href="#" className="b-notifications__delete">{t('delete')}</a>
</div>
</div>
</div>
</>
<div>
Страница Информации о пользователе
</div>
);
}

View File

@ -1,25 +1,15 @@
import React from 'react';
import type { Metadata } from 'next';
import { useTranslations } from 'next-intl';
import { SessionsTabs } from '../../../../components/Account';
export const metadata: Metadata = {
title: 'Bbuddy - Account - Sessions',
description: 'Bbuddy desc sessions'
title: 'Bbuddy - Account - Information',
description: 'Bbuddy desc information'
};
export default function Sessions() {
const t = useTranslations('Account.Sessions');
return (
<SessionsTabs
intlConfig={{
upcoming: t('upcoming-sessions'),
requested: t('sessions-requested'),
recent: t('recent-sessions'),
selectTopicLabel: t('topic'),
dateLabel: t('day-start')
}}
/>
<div>
Страница Информации о пользователе
</div>
);
}

View File

@ -1,32 +0,0 @@
import React from 'react';
import { useTranslations } from 'next-intl';
import { Link } from '../../../../../navigation';
export default function ChangePassword({ params }: { params: { userId: string } }) {
const t = useTranslations('Account.Settings');
return (
<>
<ol className="breadcrumb">
<li className="breadcrumb-item">
<Link href={`/${params.userId}/settings` as any}>
{t('title')}
</Link>
</li>
<li className="breadcrumb-item active" aria-current="page">{t('change-password')}</li>
</ol>
<form className="form-settings" action="">
<div className="form-field password-hide">
<input type="text" placeholder={t('old-password')} className="base-input" id="" value="" />
</div>
<div className="form-field password-hide">
<input type="text" placeholder={t('new-password')} className="base-input" id="" value="" />
</div>
<div className="form-field password-show">
<input className="base-input" type="text" placeholder={t('confirm-password')} id="" value="" />
</div>
<button className="btn-apply">{t('save')}</button>
</form>
</>
);
};

View File

@ -1,48 +1,15 @@
import React from 'react';
import type { Metadata } from 'next';
import { useTranslations } from 'next-intl';
import {Link} from "../../../../navigation";
export const metadata: Metadata = {
title: 'Bbuddy - Account - Profile Settings',
description: 'Bbuddy desc Profile settings'
title: 'Bbuddy - Account - Information',
description: 'Bbuddy desc information'
};
export default function Settings({ params }: { params: { userId: string } }) {
const t = useTranslations('Account.Settings');
export default function Information() {
return (
<>
<ol className="breadcrumb">
<li className="breadcrumb-item active" aria-current="page">{t('title')}</li>
</ol>
<form className="form-settings" action="">
<div className="user-avatar">
<div className="user-avatar__edit">
<input className="" type="file" id="input-file" />
<label htmlFor="input-file" className="form-label" />
</div>
<div className="user-avatar__text">{t('photo-desc')}</div>
</div>
<div className="form-field">
<input type="text" placeholder={t('name')} className="base-input" id="" value="" />
</div>
<div className="form-field">
<input type="text" placeholder={t('surname')} className="base-input" id="" value="" />
</div>
<div className="form-field date">
<input className="base-input " type="text" placeholder={t('birthday')} id="" value="" />
</div>
<div className="form-field">
<input type="email" placeholder={t('email')} className="base-input" id="" value="" />
</div>
<div className="form-link">
<Link href={`/${params.userId}/settings/change-password` as any}>
{t('change-password')}
</Link>
</div>
<button className="btn-apply">{t('save')}</button>
</form>
</>
<div>
Страница Информации о пользователе
</div>
);
};
}

View File

@ -1,23 +1,15 @@
import React from 'react';
import type { Metadata } from 'next';
import {useTranslations} from "next-intl";
export const metadata: Metadata = {
title: 'Bbuddy - Account - Help & Support',
description: 'Bbuddy desc help & support'
title: 'Bbuddy - Account - Information',
description: 'Bbuddy desc information'
};
export default function Support() {
const t = useTranslations('Account.Support');
export default function Information() {
return (
<>
<ol className="breadcrumb">
<li className="breadcrumb-item active" aria-current="page">{t('title')}</li>
</ol>
<div className="base-text">
some text
</div>
</>
<div>
Страница Информации о пользователе
</div>
);
}

View File

@ -15,6 +15,7 @@ export default function WorkWithUs() {
<ol className="breadcrumb">
<li className="breadcrumb-item active" aria-current="page">{t('title')}</li>
</ol>
<div className="b-info">
<div className="image-info">
<img className="" src="/images/info.png" alt="" />

View File

@ -2,79 +2,18 @@ import React from 'react';
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { Link } from '../../../../navigation';
import { getExpertById, getExpertsList } from '../../../../actions/experts';
import {
ExpertCard,
ExpertCertificate,
ExpertInformation,
ExpertPractice
} from '../../../../components/Experts/ExpertDetails';
import { Details } from '../../../../types/experts';
export const metadata: Metadata = {
title: 'Bbuddy - Experts item',
description: 'Bbuddy desc experts'
};
export async function generateStaticParams({
params: { locale },
}: { params: { locale: string } }) {
const result: { locale: string, expertId: string }[] = [];
const experts = await getExpertsList({
"themesTagIds": [
1,2,3,4,5,6,7,8
],
"priceFrom": null,
"priceTo": null,
"durationFrom": null,
"durationTo": null
}, locale);
experts?.forEach(({ id }) => {
result.push({ locale, expertId: id.toString() });
});
return result;
export function generateStaticParams() {
return [{ expertId: '1' }, { expertId: '2' }];
}
export default async function ExpertItem({ params: { expertId = '', locale} }: { params: { expertId: string, locale: string } }) {
if (!expertId) notFound();
const expert = await getExpertById(expertId, locale);
const getAssociationLevel = (accLevelId?: number) => {
if (accLevelId) {
const [cur] = (expert?.associationLevels || []).filter(({ id }) => id === accLevelId) || [];
return cur?.name || '';
}
return '';
};
const getAssociation = (accLevelId?: number) => {
if (accLevelId) {
const [curLevel] = (expert?.associationLevels || []).filter(({ id }) => id === accLevelId) || [];
if (curLevel) {
const [cur] = (expert?.associations || []).filter(({ id }) => id === curLevel.associationId) || [];
return cur?.name || '';
}
}
return '';
};
const generateDescription = ({ id, title, description, document }: Details) => (
<div key={id}>
<h3 className="title-h3">{title}</h3>
<p className="base-text">{description}</p>
{document && (
<div className="sertific">
<ExpertCertificate document={document} />
</div>
)}
</div>
);
export default function ExpertItem({ params }: { params: { expertId: string } }) {
if (!params?.expertId) notFound();
return (
<div className="b-page">
@ -85,37 +24,125 @@ export default async function ExpertItem({ params: { expertId = '', locale} }: {
Back to experts list
</Link>
</div>
<ExpertCard expert={expert} />
<ExpertInformation expert={expert} locale={locale} />
<div className="expert-card">
<div className="expert-card__wrap">
<div className="expert-card__avatar">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="expert-card__inner">
<h1 className="expert-card__title">{`Matthew Weeks | id ${params.expertId}`}</h1>
<div className="expert-card__info">
<span>12 Practice hours</span>
<i>|</i>
<span>15 Supervision per year</span>
</div>
<div className="expert-card__rating">
<img src="/images/stars.svg" className="" alt="" />
<span>4/5 (out of 345)</span>
</div>
</div>
</div>
<div className="expert-card__wrap-btn">
<a href="#" className="btn-apply">
<img src="/images/calendar-outline.svg" className="" alt="" />
Schedule
</a>
<a href="#" className="btn-video">
<img src="/images/videocam-outline.svg" className="" alt="" />
Video
</a>
</div>
</div>
<h2 className="title-h2">Current Offer</h2>
<div className="skills__list">
<div className="skills__list__item">Engineering &amp; Data</div>
<div className="skills__list__item">Communication</div>
<div className="skills__list__item">Communication</div>
</div>
<p className="base-text">
Hello, my name is Marcelo. I am a Senior UX Designer with more than 6 years of experience working
with the largest companies in the world such as Disney, Globant and currently IBM.
During my career, I have helped organizations solve complex problems using aesthetically pleasing
designs with design while building teams and mentoring other designers.
I can help you: <br />
Prepare for interviews, prepare your resume or CV and work on your LinkedIn profile <br />
Get ready for whiteboard challenges and take-home exercises <br />
Create a great portfolio and case study presentation. <br />
Provide industry information. <br />
Professional orientation <br />
Strategic thinking <br /><br />
Oh, and I also speak Spanish!
</p>
<div className="wrap-btn-prise">
<a href="#" className="btn-apply">
Sign Up Now
</a>
<div className="wrap-btn-prise__text">
45$ <span> / 45min</span>
</div>
</div>
<h2 className="title-h2">Expert Background</h2>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
{expert?.publicCoachDetails?.educations && expert.publicCoachDetails.educations?.map(generateDescription)}
{expert?.publicCoachDetails?.certificates && expert.publicCoachDetails.certificates.length > 0 && (
<div>
<h3 className="title-h3">Professional Certification</h3>
{expert.publicCoachDetails.certificates?.map((cert) => (
<div key={cert.id}>
<p className="base-text">
{`${getAssociationLevel(cert?.associationLevelId)} ${getAssociation(cert?.associationLevelId)}`}
</p>
{cert.document && (
<div className="sertific">
<ExpertCertificate document={cert.document} />
</div>
)}
</div>
))}
<h3 className="title-h3">Education</h3>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
<div className="sertific">
<img src="/images/sertific.png" className="" alt="" />
</div>
<h3 className="title-h3">Professional Certification</h3>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
<h3 className="title-h3">Trainings | Seminars | Courses</h3>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
<h3 className="title-h3">MBA Information</h3>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
<h3 className="title-h3">Managerial Experience</h3>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
<h3 className="title-h3">Entrepreneurial Experience</h3>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
<h3 className="title-h3">Successful Cases From Practice</h3>
<div className="case-list">
<div className="skills__list">
<div className="skills__list__item">Engineering &amp; Data</div>
<div className="skills__list__item">Communication</div>
<div className="skills__list__item">Communication</div>
</div>
)}
{expert?.publicCoachDetails?.trainings && expert.publicCoachDetails.trainings?.map(generateDescription)}
{expert?.publicCoachDetails?.mbas && expert.publicCoachDetails.mbas?.map(generateDescription)}
{expert?.publicCoachDetails?.experiences && expert.publicCoachDetails.experiences?.map(generateDescription)}
<ExpertPractice expert={expert} />
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
</div>
<div className="case-list">
<div className="skills__list">
<div className="skills__list__item">Engineering &amp; Data</div>
<div className="skills__list__item">Communication</div>
<div className="skills__list__item">Communication</div>
</div>
<p className="base-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam aliquet, lectus nec viverra
malesuada, ligula sem tempor risus, non posuere urna diam a libero.
</p>
</div>
<h2 className="title-h2">All Offers by this Expert</h2>
<div className="offers-list">
<div className="card-profile">

View File

@ -1,27 +1,14 @@
import React from 'react';
import type { Metadata } from 'next';
import { getExpertsList } from '../../../actions/experts';
import { ExpertsFilter } from '../../../components/Experts/Filter';
import { ExpertsAdditionalFilter } from '../../../components/Experts/AdditionalFilter';
import { ExpertsList } from '../../../components/Experts/ExpertsList';
import { CustomPagination } from '../../../components/view';
import { ExpertsFilter, ExpertsAdditionalFilter } from '../../../components/Experts';
export const metadata: Metadata = {
title: 'Bbuddy - Experts',
description: 'Bbuddy desc experts'
};
export default async function Experts({ params, searchParams }: { params: { locale: string }, searchParams: { [key: string]: string | string[] | undefined } }) {
export default function Experts({ searchParams }: { searchParams: { [key: string]: string | string[] | undefined } }) {
console.log('search params', searchParams);
const data = await getExpertsList({
"themesTagIds": [
1,2,3,4,5,6,7,8
],
"priceFrom": null,
"priceTo": null,
"durationFrom": null,
"durationTo": null
}, params.locale);
return (
<div className="page-search">
@ -30,17 +17,162 @@ export default async function Experts({ params, searchParams }: { params: { loca
<div className="main-find__top">
<h2 className="title-h2">Find a expert</h2>
<div className="open-filter">
<img src="/images/options-outline.svg" alt="" />
<img src="/images/options-outline.svg" className="" alt="" />
</div>
</div>
<div className="row">
<div className="col-xl-3 col-lg-4 d-none d-lg-block">
<ExpertsFilter locale={params.locale} />
<ExpertsFilter />
</div>
<div className="col-xl-9 col-lg-8 ">
<ExpertsAdditionalFilter />
<ExpertsList data={data} locale={params.locale} />
<CustomPagination total={20} />
<div className="search-result">
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__price">
45$ <span>/ 45min</span>
</div>
</div>
</div>
<div className="card-profile__skills">
<div className="skills__list">
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__more">+6</div>
</div>
</div>
<div className="card-profile__title">Senior Software Engineer</div>
<div className="card-profile__subtitle">Auth0</div>
<div className="card-profile__desc">
I have worked across a variety of organizations, lead teams, and delivered
quality software for 8 years. In that time I've worked as an independent
consultant, at agencies as a team lead, and as a senior engineer at Auth0. I
also host a podcast https://anchor.fm/work-in-programming where I break down how
</div>
<div className="card-profile__footer">
<a href="#">Details
<img className="" src="/images/chevron-forward.svg" alt="" />
</a>
</div>
</div>
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__price">
45$ <span>/ 45min</span>
</div>
</div>
</div>
<div className="card-profile__skills">
<div className="skills__list">
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__more">+6</div>
</div>
</div>
<div className="card-profile__title">Senior Software Engineer</div>
<div className="card-profile__subtitle">Auth0</div>
<div className="card-profile__desc">
I have worked across a variety of organizations, lead teams, and delivered
quality software for 8 years. In that time I've worked as an independent
consultant, at agencies as a team lead, and as a senior engineer at Auth0. I
also host a podcast https://anchor.fm/work-in-programming where I break down how
</div>
<div className="card-profile__footer">
<a href="#">Details
<img className="" src="/images/chevron-forward.svg" alt="" />
</a>
</div>
</div>
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__price">
45$ <span>/ 45min</span>
</div>
</div>
</div>
<div className="card-profile__skills">
<div className="skills__list">
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__more">+6</div>
</div>
</div>
<div className="card-profile__title">Senior Software Engineer</div>
<div className="card-profile__subtitle">Auth0</div>
<div className="card-profile__desc">
I have worked across a variety of organizations, lead teams, and delivered
quality software for 8 years. In that time I've worked as an independent
consultant, at agencies as a team lead, and as a senior engineer at Auth0. I
also host a podcast https://anchor.fm/work-in-programming where I break down how
</div>
<div className="card-profile__footer">
<a href="#">Details
<img className="" src="/images/chevron-forward.svg" alt="" />
</a>
</div>
</div>
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__price">
45$ <span>/ 45min</span>
</div>
</div>
</div>
<div className="card-profile__skills">
<div className="skills__list">
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__item">Engineering & Data</div>
<div className="skills__list__more">+6</div>
</div>
</div>
<div className="card-profile__title">Senior Software Engineer</div>
<div className="card-profile__subtitle">Auth0</div>
<div className="card-profile__desc">
I have worked across a variety of organizations, lead teams, and delivered
quality software for 8 years. In that time I've worked as an independent
consultant, at agencies as a team lead, and as a senior engineer at Auth0. I
also host a podcast https://anchor.fm/work-in-programming where I break down how
</div>
<div className="card-profile__footer">
<a href="#">Details
<img className="" src="/images/chevron-forward.svg" alt="" />
</a>
</div>
</div>
</div>
<ul className="pagination">
<li className="page-item"><a className="page-link" href="#">1</a></li>
<li className="page-item active" aria-current="page">
<a className="page-link" href="#">2</a>
</li>
<li className="page-item"><a className="page-link" href="#">3</a></li>
<li className="page-item"><a className="page-link" href="#">4</a></li>
</ul>
</div>
</div>
</div>

View File

@ -1,110 +0,0 @@
'use client';
import React from 'react';
import { Tabs } from 'antd';
export const SessionsTabs = ({ intlConfig }: { intlConfig: Record<string, string> }) => {
const getChildren = () => (
<>
<div className="filter-session">
<div className="filter-session__item filter-session__item--type">
<select name="" id="">
<option value="">1</option>
<option value="">2</option>
</select>
</div>
</div>
<div className="list-session">
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__title">
Personal Growth Course
</div>
<div className="card-profile__header__date chosen">
Today 10:00 AM - 10:30 AM
</div>
</div>
</div>
</div>
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__title">
Personal Growth Course
</div>
<div className="card-profile__header__date">
8 december at 10:00 AM - 10:30 AM
</div>
</div>
</div>
</div>
<div className="card-profile">
<div className="card-profile__header">
<div className="card-profile__header__portrait">
<img src="/images/person.png" className="" alt="" />
</div>
<div className="card-profile__header__inner">
<div className="card-profile__header__name">Matthew Weeks</div>
<div className="card-profile__header__title">
Personal Growth Course
</div>
<div className="card-profile__header__date">
8 december at 10:00 AM - 10:30 AM
</div>
</div>
</div>
</div>
</div>
</>
);
const tabs = [
{
key: 'upcoming',
label: (
<div className="tabs-session__item active">
{intlConfig?.upcoming || 'Tab 1'}
<span className="count">3</span>
</div>
),
children: getChildren()
},
{
key: 'requested',
label: (
<div className="tabs-session__item">
{intlConfig?.requested || 'Tab 2'}
<span className="count">2</span>
</div>
),
children: getChildren()
},
{
key: 'recent',
label: (
<div className="tabs-session__item">
{intlConfig?.recent || 'Tab 3'}
</div>
),
children: getChildren()
}
];
return (
<Tabs
defaultActiveKey="upcoming"
items={tabs}
renderTabBar={(props, DefaultTabBar) => (<DefaultTabBar {...props} className="tabs-session" />)}
/>
);
};

View File

@ -1,2 +1 @@
export { AccountMenu } from './AccountMenu';
export { SessionsTabs } from './SessionsTabs';

View File

@ -1,11 +1,10 @@
'use client';
import React, { useCallback, useState } from 'react';
import { Select } from 'antd';
import { Input, Select } from 'antd';
import { AdditionalFilter } from '../../types/experts';
import { INITIAL_ADD_FILTER } from '../../constants/experts';
import { LOCALES } from '../../constants/locale';
import { CustomInput } from '../view';
export const ExpertsAdditionalFilter = () => {
const [filter, setFilter] = useState<AdditionalFilter>(INITIAL_ADD_FILTER);
@ -20,20 +19,15 @@ export const ExpertsAdditionalFilter = () => {
return (
<div className="main-find__search">
<div className="main-find__search__input">
<CustomInput
placeholder="Search for an Expert"
onChange={(e: any) => onChangeFilter('text', e?.target?.value)}
/>
<input className="base-input" type="text" placeholder="Search for an Expert" />
</div>
<Input placeholder="Search for an Expert" onChange={(e) => onChangeFilter('text', e?.target?.value)}/>
<div className="main-find__search__sort">
<Select
defaultValue={INITIAL_ADD_FILTER.sort}
onChange={(val) => onChangeFilter('sort', val)}
options={[
{ value: 'By top views', label: 'By top views' },
{ value: 'By Price Ascending', label: 'By Price Ascending' },
{ value: 'By Price Descending', label: 'By Price Descending' },
{ value: 'By rating', label: 'By rating' }
{ value: 'By top views', label: 'By top views' }
]}
/>
</div>

View File

@ -1,144 +0,0 @@
'use client';
import React, { FC } from 'react';
import Image from 'next/image';
import { Tag, Image as AntdImage, Space } from 'antd';
import { ZoomInOutlined, ZoomOutOutlined, StarFilled } from '@ant-design/icons';
import { ExpertDetails, ExpertDocument } from '../../types/experts';
import { Locale } from '../../types/locale';
import { CustomRate } from '../view/CustomRate';
type ExpertDetailsProps = {
expert: ExpertDetails;
locale?: string;
};
export const ExpertCard: FC<ExpertDetailsProps> = ({ expert }) => {
const { publicCoachDetails } = expert || {};
return (
<div className="expert-card">
<div className="expert-card__wrap">
<div className="expert-card__avatar">
<Image src={publicCoachDetails?.faceImageUrl || '/images/person.png'} width={216} height={216} alt="" />
</div>
<div className="expert-card__inner">
<h1 className="expert-card__title">{`${publicCoachDetails?.name} ${publicCoachDetails?.surname || ''}`}</h1>
<div className="expert-card__info">
<span>{`${publicCoachDetails?.practiceHours} Practice hours`}</span>
<i>|</i>
<span>{`${publicCoachDetails?.supervisionPerYearId} Supervision per year`}</span>
</div>
<div className="expert-card__rating">
<CustomRate defaultValue={4} character={<StarFilled style={{ fontSize: 32 }} />} disabled />
<span>4/5 (out of 345)</span>
</div>
</div>
</div>
<div className="expert-card__wrap-btn">
<a href="#" className="btn-apply">
<img src="/images/calendar-outline.svg" className="" alt="" />
Schedule
</a>
<a href="#" className="btn-video">
<img src="/images/videocam-outline.svg" className="" alt="" />
Video
</a>
</div>
</div>
);
};
export const ExpertInformation: FC<ExpertDetailsProps> = ({ expert, locale }) => {
const { publicCoachDetails: { tags = [], sessionCost = 0, sessionDuration = 0 } } = expert || {};
const isRus = locale === Locale.ru;
return (
<>
<h2 className="title-h2">Current Offer</h2>
<div className="skills__list">
{tags?.map((skill) => <Tag key={skill?.id} className="skills__list__item">{skill?.name}</Tag>)}
</div>
<p className="base-text">
Hello, my name is Marcelo. I am a Senior UX Designer with more than 6 years of experience working
with the largest companies in the world such as Disney, Globant and currently IBM.
During my career, I have helped organizations solve complex problems using aesthetically pleasing
designs with design while building teams and mentoring other designers.
I can help you: <br />
Prepare for interviews, prepare your resume or CV and work on your LinkedIn profile <br />
Get ready for whiteboard challenges and take-home exercises <br />
Create a great portfolio and case study presentation. <br />
Provide industry information. <br />
Professional orientation <br />
Strategic thinking <br /><br />
Oh, and I also speak Spanish!
</p>
<div className="wrap-btn-prise">
<a href="#" className="btn-apply">
Sign Up Now
</a>
<div className="wrap-btn-prise__text">
{`${sessionCost}${isRus ? '₽' : '€'}`} <span>/ {`${sessionDuration}${isRus ? 'мин' : 'min'}`}</span>
</div>
</div>
</>
);
};
export const ExpertPractice: FC<ExpertDetailsProps> = ({ expert }) => {
const { publicCoachDetails: { practiceCases = [], themesGroups = [] } } = expert || {};
return practiceCases?.length > 0 ? (
<div>
<h3 className="title-h3">Successful Cases From Practice</h3>
{practiceCases?.map(({ id, description, themesGroupIds }) => {
const filtered = themesGroups?.filter(({ id }) => themesGroupIds?.includes(+id));
return (
<div key={id} className="case-list">
{themesGroupIds && (
<div className="skills__list">
{filtered?.map(({ id, name }) => (
<div key={id} className="skills__list__item">{name}</div>
))}
</div>
)}
{description && <p className="base-text">{description}</p>}
</div>
)
})}
</div>
) : null;
};
export const ExpertCertificate: FC<{ document: ExpertDocument }> = ({ document }) => (
<AntdImage
width={160}
src={document?.preview?.url}
placeholder={(
<AntdImage
preview={false}
src={document?.preview?.url}
width={160}
fallback="data:image/png;base64,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"
/>
)}
fallback="data:image/png;base64,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"
preview={{
src: document.fullSize?.url,
toolbarRender: (
_,
{
transform: { scale },
actions: { onZoomOut, onZoomIn },
},
) => (
<Space size={12} className="toolbar-wrapper">
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
</Space>
)
}}
/>
);

View File

@ -1,66 +0,0 @@
'use client';
import React from 'react';
import { List, Tag } from 'antd';
import { RightOutlined } from '@ant-design/icons';
import Image from 'next/image';
import { Link } from '../../navigation';
import { Locale } from '../../types/locale';
import { ExpertsData } from '../../types/experts';
export const ExpertsList = ({ data, locale }: { data: ExpertsData, locale: string }) => {
const isRus = locale === Locale.ru;
return (
<List
itemLayout="vertical"
size="large"
className="search-result"
dataSource={data}
renderItem={(item) => (
<List.Item key={item?.id} className="card-profile">
<List.Item.Meta
className="card-profile__header"
avatar={(
<div className="card-profile__header__portrait">
<Image src={item?.faceImageUrl || '/images/person.png'} width={100} height={100} alt="" />
</div>
)}
description={(
<div className="card-profile__header__inner">
<Link href={`/experts/${item?.id}` as any}>
<div className="card-profile__header__name">{`${item.name} ${item?.surname || ''}`}</div>
</Link>
<div className="card-profile__header__price">
{`${item?.sessionCost}${isRus ? '₽' : '€'}`} <span>/ {`${item?.sessionDuration}${isRus ? 'мин' : 'min'}`}</span>
</div>
</div>
)}
/>
<div className="card-profile__skills">
<div className="skills__list">
{item?.tags?.slice(0, 2).map((skill) => <Tag key={skill?.id} className="skills__list__item">{skill?.name}</Tag>)}
{item?.tags?.length > 2
? (
<Tag className="skills__list__more">
<Link href={`/experts/${item?.id}` as any}>
{`+${item?.tags?.length - 2}`}
</Link>
</Tag>
) : null}
</div>
</div>
<div className="card-profile__title">{item?.speciality}</div>
<div className="card-profile__subtitle">{item?.specialityDesc}</div>
<div className="card-profile__desc">{item?.description}</div>
<div className="card-profile__footer">
<Link href={`/experts/${item?.id}` as any}>
Details
<RightOutlined style={{ fontSize: '10px', padding: '0 7px' }}/>
</Link>
</div>
</List.Item>
)}
/>
);
};

View File

@ -1,11 +1,77 @@
'use client';
import React, { useCallback, useState } from 'react';
import { List } from 'antd';
import { List, Switch, Slider } from 'antd';
import styled from 'styled-components';
import { FilterType, INITIAL_FILTER } from '../../constants/experts';
import { Filter } from '../../types/experts';
import { CustomSwitch, CustomSlider } from '../view';
import {Locale} from "../../types/locale";
const CustomSwitch = styled(Switch)`
height: 24px !important;
background: #F8F8F7 !important;
.ant-switch-handle {
height: 24px !important;
width: 24px !important;
top: 0 !important;
&::before {
box-shadow: none !important;
background: #C4DFE6 !important;
border-radius: 50% !important;
}
}
&.ant-switch-checked {
background: #2c7873 !important;
}
`;
const WrapSlider = styled.div`
width: 100%;
position: relative;
margin: 8px 0 16px -5px;
`;
const CustomSlider = styled(Slider)`
padding-block: 7px !important;
height: 16px !important;
.ant-slider-rail {
background-color: #E5E5E5 !important;
}
.ant-slider-track {
background-color: #66A5AD !important;
}
.ant-slider-handle {
width: 16px !important;
height: 16px !important;
&::before {
width: 16px !important;
height: 16px !important;
inset-inline-start: 0 !important;
inset-block-start: 0 !important;
}
&::after {
width: 16px !important;
height: 16px !important;
background-color: #66A5AD !important;
inset-inline-start: 0 !important;
inset-block-start: 0 !important;
box-shadow: none !important;
}
&:focus, &:hover {
&::after {
box-shadow: 0 0 0 10px rgba(102, 165, 173, .2) !important;
}
}
}
`;
const dataCoaching = [
{
@ -48,9 +114,8 @@ const dataConsultation = [
}
];
export const ExpertsFilter = ({ locale }: { locale: string }) => {
export const ExpertsFilter = () => {
const [filter, setFilter] = useState<Filter>(INITIAL_FILTER);
const isRus = locale === Locale.ru;
const onChangeFilter = useCallback((key: string, value: any) => {
setFilter({
@ -73,7 +138,7 @@ export const ExpertsFilter = ({ locale }: { locale: string }) => {
<div className="b-filter__title">{title}</div>
<CustomSwitch
defaultChecked={filter[key]}
onChange={(checked: boolean) => onChangeFilter(key, checked)}
onChange={(checked) => onChangeFilter(key, checked)}
/>
</div>
</List.Item>
@ -90,28 +155,28 @@ export const ExpertsFilter = ({ locale }: { locale: string }) => {
{getList(dataMentoring)}
<h3 className="title-h3">Business-consultation</h3>
{getList(dataConsultation)}
<h3 className="title-h3">{`Price from 45${isRus ? '₽' : '€'} to 170${isRus ? '₽' : '€'}`}</h3>
<div className="b-filter__slider">
<h3 className="title-h3">Price from 45 to 170</h3>
<WrapSlider>
<CustomSlider
range
step={1}
defaultValue={INITIAL_FILTER[FilterType.Price]}
min={45}
max={170}
onChange={(val: any) => onChangeFilter(FilterType.Price, val)}
onChange={(val) => onChangeFilter(FilterType.Price, val)}
/>
</div>
<h3 className="title-h3">{`Duration from 45${isRus ? 'мин' : 'min'} to 120${isRus ? 'мин' : 'min'}`}</h3>
<div className="b-filter__slider">
</WrapSlider>
<h3 className="title-h3">Duration from 45m to 120m</h3>
<WrapSlider>
<CustomSlider
range
step={1}
defaultValue={INITIAL_FILTER[FilterType.Duration]}
min={45}
max={120}
onChange={(val: any) => onChangeFilter(FilterType.Duration, val)}
onChange={(val) => onChangeFilter(FilterType.Duration, val)}
/>
</div>
</WrapSlider>
<button className="btn-apply">Apply</button>
</div>
);

View File

@ -0,0 +1,2 @@
export * from './Filter';
export * from './AdditionalFilter';

View File

@ -1,281 +0,0 @@
'use client';
import React, { FC, useState } from 'react';
import { usePathname } from 'next/navigation';
import Image from 'next/image';
import {Button, Modal as AntdModal, Form, notification} from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import { styled } from 'styled-components';
import { CustomInput } from '../view';
import { getAuth } from '../../actions/auth';
type AuthModalProps = {
open: boolean;
handleCancel: () => void;
mode: 'enter' | 'register' | 'reset' | 'finish';
updateMode: (mode: 'enter' | 'register' | 'reset' | 'finish') => void;
};
const Modal = styled(AntdModal)`
.ant-modal-content {
border-radius: 24px !important;
}
.ant-modal-close {
height: 64px !important;
width: 64px !important;
border-radius: 50% !important;
background: #fff !important;
top: -32px !important;
inset-inline-end: -32px !important;
&:active, &:hover {
background: #fff !important;
}
}
`;
const FilledButton = styled(Button)`
background: #66A5AD !important;
font-size: 15px !important;
border-radius: 8px !important;
height: 54px !important;
box-shadow: 0px 2px 4px 0px rgba(102, 165, 173, 0.32) !important;
`;
const OutlinedButton = styled(Button)`
display: inline-flex !important;
justify-content: center;
align-items: center;
gap: 16px;
border-color: #66A5AD !important;
color: #66A5AD !important;
font-size: 15px !important;
border-radius: 8px !important;
height: 54px !important;
span {
margin-inline-end: 0 !important;
line-height: 15px !important;
}
`;
const LinkButton = styled(Button)`
color: #66A5AD !important;
font-size: 15px !important;
height: auto !important;
padding: 0 !important;
`;
export const AuthModal: FC<AuthModalProps> = ({
open,
handleCancel,
mode,
updateMode
}) => {
const [form] = Form.useForm<{ login: string, password: string, name: string, surname: string, phone: string }>();
const [isLoading, setIsLoading] = useState<boolean>(false);
const paths = usePathname().split('/');
const onAfterClose = () => {
form.resetFields();
};
const onSubmit = () => {
form.validateFields().then(() => {
const { login, password } = form.getFieldsValue();
setIsLoading(true);
getAuth(login, password, paths[1])
.then(({ data }) => {
console.log('jwt', data.jwtToken)
})
.catch((error) => {
notification.error({
message: 'Error',
description: error?.response?.data?.errMessage
});
})
.finally(() => {
setIsLoading(false);
})
});
};
const onValidate = () => {
};
return (
<Modal
open={open}
title={undefined}
onOk={onSubmit}
onCancel={handleCancel}
afterClose={onAfterClose}
footer={false}
width={498}
closeIcon={<CloseOutlined style={{ fontSize: 20, color: '#000' }}/>}
>
<div className="b-modal__auth__content">
<div className="b-modal__auth__logo">
<img className="" src="/images/logo-auth.svg" alt=""/>
</div>
{mode === 'enter' && (
<>
<Form form={form} autoComplete="off" style={{ display: 'flex', gap: 16, flexDirection: 'column' }}>
<Form.Item name="login" rules={[{ required: true }]} noStyle>
<CustomInput
size="small"
placeholder="E-mail"
/>
</Form.Item>
<Form.Item name="password" rules={[{ required: true }]} noStyle>
<CustomInput
size="small"
placeholder="Password"
type="password"
/>
</Form.Item>
</Form>
<FilledButton
type="primary"
onClick={onSubmit}
loading={isLoading}
>
Enter
</FilledButton>
<OutlinedButton onClick={() => updateMode('register')}>Register</OutlinedButton>
<LinkButton
type="link"
onClick={() => updateMode('reset')}
>
Forgot password?
</LinkButton>
<span>or</span>
<OutlinedButton
icon={<Image src="/images/facebook-logo.png" height={20} width={20} alt="" />}
>
Facebook account
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/apple-logo.png" height={22} width={22} alt="" />}
>
Apple account
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/google-logo.png" height={20} width={20} alt="" />}
>
Google account
</OutlinedButton>
</>
)}
{mode === 'register' && (
<>
<Form form={form} autoComplete="off" style={{ display: 'flex', gap: 16, flexDirection: 'column' }}>
<Form.Item name="name" noStyle>
<CustomInput
size="small"
placeholder="Name"
/>
</Form.Item>
<Form.Item name="surname" noStyle>
<CustomInput
size="small"
placeholder="Surname"
/>
</Form.Item>
<Form.Item name="phone" noStyle>
<CustomInput
size="small"
placeholder="Phone"
type="phone"
/>
</Form.Item>
<Form.Item name="login" rules={[{ required: true }]} noStyle>
<CustomInput
size="small"
placeholder="E-mail"
/>
</Form.Item>
<Form.Item name="password" rules={[{ required: true }]} noStyle>
<CustomInput
size="small"
placeholder="Password"
type="password"
/>
</Form.Item>
</Form>
<FilledButton
type="primary"
>
Register
</FilledButton>
<span>or</span>
<OutlinedButton
icon={<Image src="/images/facebook-logo.png" height={20} width={20} alt="" />}
>
Facebook account
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/apple-logo.png" height={22} width={22} alt="" />}
>
Apple account
</OutlinedButton>
<OutlinedButton
icon={<Image src="/images/google-logo.png" height={20} width={20} alt="" />}
>
Google account
</OutlinedButton>
</>
)}
{mode === 'reset' && (
<>
<Form form={form} autoComplete="off" style={{ display: 'flex', gap: 16, flexDirection: 'column' }}>
<Form.Item name="login" rules={[{ required: true }]} noStyle>
<CustomInput
size="small"
placeholder="E-mail"
/>
</Form.Item>
<Form.Item name="password" rules={[{ required: true }]} noStyle>
<CustomInput
size="small"
placeholder="Password"
type="password"
/>
</Form.Item>
</Form>
<FilledButton
type="primary"
>
Reset Password
</FilledButton>
<LinkButton
type="link"
>
Enter
</LinkButton>
</>
)}
{mode === 'finish' && (
<>
<div className="b-modal__auth__agreement">
A link to reset your password has been sent
<br />
to your email
</div>
<FilledButton
type="primary"
>
Enter Account
</FilledButton>
</>
)}
<div className="b-modal__auth__agreement">
I have read and agree with the terms of the
User Agreement, Privacy Policy
</div>
</div>
</Modal>
);
};

View File

@ -1,72 +1,24 @@
'use client';
import React, { FC, useState, useEffect } from 'react';
import { Button } from 'antd';
import { styled } from 'styled-components';
import { AuthModal } from '../../Modals/AuthModal';
import React, { FC } from 'react';
import { useTranslations } from 'next-intl';
type HeaderAuthLinksProps = {
enterTitle: string;
registerTitle: string;
separatorClass?: string;
};
const LinkButton = styled(Button)`
color: #66A5AD !important;
font-size: 16px !important;
height: auto !important;
padding: 0 !important;
font-style: normal !important;
font-weight: 600 !important;
line-height: normal !important;
`;
export const HeaderAuthLinks: FC<HeaderAuthLinksProps> = ({
enterTitle,
registerTitle,
separatorClass = 'b-header__nav__list__line'
}) => {
const [isOpenModal, setIsOpenModal] = useState<boolean>(false);
const [mode, setMode] = useState<'enter' | 'register' | 'reset' | 'finish'>('enter');
useEffect(() => {
if (!isOpenModal) {
setMode('enter');
}
}, [isOpenModal]);
const onOpen = (mode: 'enter' | 'register' | 'reset' | 'finish') => {
setMode(mode);
setIsOpenModal(true);
};
export const HeaderAuthLinks: FC<HeaderAuthLinksProps> = ({ separatorClass = 'b-header__nav__list__line' }) => {
const t = useTranslations('Header');
return (
<>
<li>
<LinkButton
type="link"
onClick={() => onOpen('register')}
>
{registerTitle}
</LinkButton>
<a href="#">{t('registration')}</a>
</li>
<li>
<span className={separatorClass}>|</span>
</li>
<li>
<LinkButton
type="link"
onClick={() => onOpen('enter')}
>
{enterTitle}
</LinkButton>
<a href="#">{t('enter')}</a>
</li>
<AuthModal
open={isOpenModal}
handleCancel={() => setIsOpenModal(false)}
mode={mode}
updateMode={setMode}
/>
</>
);
};
}

View File

@ -1,18 +1,12 @@
import React, { ReactNode } from 'react';
import { HeaderAuthLinks } from './HeaderAuthLinks';
type HeaderMenuProps = {
children: ReactNode;
enterTitle: string;
registerTitle: string;
};
export const HeaderMenu = ({ children, enterTitle, registerTitle }: HeaderMenuProps) => (
export const HeaderMenu = ({ children }: { children: ReactNode }) => (
<div className="b-header__nav">
<nav>
<ul className="b-header__nav__list ">
{children}
<HeaderAuthLinks enterTitle={enterTitle} registerTitle={registerTitle} />
<HeaderAuthLinks />
</ul>
</nav>
</div>

View File

@ -5,11 +5,9 @@ import { HeaderAuthLinks } from './HeaderAuthLinks';
type HeaderMenuMobileProps = {
children: ReactNode;
enterTitle: string;
registerTitle: string;
};
export const HeaderMobileMenu: FC<HeaderMenuMobileProps> = ({ children, enterTitle, registerTitle }) => {
export const HeaderMobileMenu: FC<HeaderMenuMobileProps> = ({ children }) => {
const [showMobileMenu, setShowMobileMenu] = useState<boolean>(false);
return (
@ -29,11 +27,7 @@ export const HeaderMobileMenu: FC<HeaderMenuMobileProps> = ({ children, enterTit
<img className="img-default" src="/images/avatar.png" alt=""/>
</div>
<ul className="menu-mobile__header__nav">
<HeaderAuthLinks
separatorClass="menu-mobile__header__nav__line"
enterTitle={enterTitle}
registerTitle={registerTitle}
/>
<HeaderAuthLinks separatorClass="menu-mobile__header__nav__line" />
</ul>
</div>
<div className="menu-mobile__body">

View File

@ -23,20 +23,20 @@ export const Header: FC<HeaderProps> = ({ locale }) => {
<>
<header className="b-header">
<div className="b-inner">
<Link href={'/' as any} className="b-header__logo">
<div className="b-header__logo">
<img
src="/images/logo-header.svg"
className="img-default"
alt=""
/>
</Link>
<HeaderMenu enterTitle={t('enter')} registerTitle={t('registration')}>
</div>
<HeaderMenu>
{routes}
</HeaderMenu>
<LanguageSwitcher locale={locale} />
</div>
</header>
<HeaderMobileMenu enterTitle={t('enter')} registerTitle={t('registration')}>
<HeaderMobileMenu>
{routes}
</HeaderMobileMenu>
</>

View File

@ -1,29 +0,0 @@
import React from 'react';
import styled from 'styled-components';
import { Input as AntdInput } from 'antd';
const Input = styled(AntdInput)`
padding: 15px 16px !important;
background: #F8F8F7 !important;
border: 1px solid #F8F8F7 !important;
border-radius: 8px !important;
color: #000 !important;
&:focus, &:hover {
border-color: #66A5AD !important;
box-shadow: none !important;
}
&::placeholder {
color: #000 !important;
opacity: .4 !important;
}
&.ant-input-status-error:not(.ant-input-disabled):not(.ant-input-borderless) {
border-color: #ff4d4f !important;
}
`;
export const CustomInput = (props: any) => (
<Input {...props} />
);

View File

@ -1,58 +0,0 @@
'use client';
import React from 'react';
import styled from 'styled-components';
import { Pagination as AntdPagination, PaginationProps } from 'antd';
const DEFAULT_SIZE = 5;
const Pagination = styled(AntdPagination)`
display: flex;
gap: 8px;
.ant-pagination-item {
margin-inline-end: 0 !important;
height: 40px !important;
width: 40px !important;
border-radius: 8px !important;
line-height: 38px !important;
font-family: var(--font-inter) !important;
font-weight: 400 !important;
border-color: #2c7873 !important;
font-size: 16px !important;
a {
color: #2c7873 !important;
}
}
.ant-pagination-item-active {
background: #2c7873 !important;
a {
color: #fff !important;
}
}
.ant-pagination-item:not(.ant-pagination-item-active):active,
.ant-pagination-item:not(.ant-pagination-item-active):hover {
background-color: rgba(44, 120, 115, 0.06) !important;
}
`;
const itemRender: PaginationProps['itemRender'] = (_, type, originalElement) => {
if (type === 'prev' || type === 'next') {
return null;
}
return originalElement;
};
export const CustomPagination = (props: PaginationProps) => (
<Pagination
itemRender={itemRender}
defaultCurrent={1}
defaultPageSize={DEFAULT_SIZE}
{...props}
/>
);

View File

@ -1,25 +0,0 @@
import React from 'react';
import styled from 'styled-components';
import { Rate as AntdRate } from 'antd';
const Rate = styled(AntdRate)`
display: inline-flex !important;
gap: 4px;
li {
margin-inline-end: 0 !important;
padding: 5px 0 0 !important;
&.ant-rate-star-full span {
color: #ffbd00 !important;
}
&.ant-rate-star-zero span {
color: #c4dfe6 !important;
}
}
`;
export const CustomRate = (props: any) => (
<Rate {...props} />
);

View File

@ -1,49 +0,0 @@
'use client';
import React from 'react';
import styled from 'styled-components';
import { Slider as AntdSlider } from 'antd';
const Slider = styled(AntdSlider)`
padding-block: 7px !important;
height: 16px !important;
.ant-slider-rail {
background-color: #E5E5E5 !important;
}
.ant-slider-track {
background-color: #66A5AD !important;
}
.ant-slider-handle {
width: 16px !important;
height: 16px !important;
&::before {
width: 16px !important;
height: 16px !important;
inset-inline-start: 0 !important;
inset-block-start: 0 !important;
}
&::after {
width: 16px !important;
height: 16px !important;
background-color: #66A5AD !important;
inset-inline-start: 0 !important;
inset-block-start: 0 !important;
box-shadow: none !important;
}
&:focus, &:hover {
&::after {
box-shadow: 0 0 0 10px rgba(102, 165, 173, .2) !important;
}
}
}
`;
export const CustomSlider = (props: any) => (
<Slider {...props} />
);

View File

@ -1,34 +0,0 @@
'use client';
import React from 'react';
import styled from 'styled-components';
import { Switch as AntdSwitch } from 'antd';
const Switch = styled(AntdSwitch)`
height: 24px !important;
background: #F8F8F7 !important;
.ant-switch-handle {
height: 24px !important;
width: 24px !important;
top: 0 !important;
&::before {
box-shadow: none !important;
background: #C4DFE6 !important;
border-radius: 50% !important;
}
}
&.ant-switch-checked {
background: #F8F8F7 !important;
.ant-switch-handle::before {
background: #66A5AD !important;
}
}
`;
export const CustomSwitch = (props: any) => (
<Switch {...props} />
);

View File

@ -1,7 +0,0 @@
'use client';
export * from './CustomSwitch';
export * from './CustomSlider';
export * from './CustomPagination';
export * from './CustomRate';
export * from './CustomInput';

View File

@ -1 +0,0 @@
export const BASE_URL = process.env.NEXT_PUBLIC_SERVER_BASE_URL || 'https://api.bbuddy.expert/api';

View File

@ -1,33 +0,0 @@
import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import { BASE_URL } from '../constants/common';
// import { getAuthToken } from '../../utils';
export const onSuccessRequestCallback = (config: InternalAxiosRequestConfig) => {
const newConfig = { ...config };
// if (!newConfig.headers) {
// newConfig.headers = {};
// }
//
// if (IS_DEV && !newConfig.headers.Authorization && getAuthToken()) {
// newConfig.headers.Authorization = `Bearer ${getAuthToken()}`;
// }
newConfig.headers['Content-Type'] = 'application/json';
return newConfig;
};
export const onSuccessResponseCallback = (response: AxiosResponse) => response;
export const onErrorResponseCallback = (error: any) => Promise.reject(error);
export const apiClient = axios.create({
baseURL: BASE_URL
});
apiClient.interceptors.request.use(onSuccessRequestCallback);
apiClient.interceptors.response.use(
onSuccessResponseCallback,
onErrorResponseCallback
);

View File

@ -9,5 +9,4 @@ export default createMiddleware({
export const config = {
matcher: ['/', '/(en|ru|de|it|es|fr)/:path*']
// matcher: ['/', '/(en|ru|de|it|es|fr).html']
};

View File

@ -1,29 +0,0 @@
.b {
&-modal {
&__auth {
&__content {
padding: 80px 76px 68px;
display: flex;
flex-direction: column;
gap: 16px;
text-align: center;
span, div {
font-size: 13px;
}
& > span {
color: #66A5AD;
}
}
&__logo {
margin-bottom: 16px;
}
&__agreement {
}
}
}
}

View File

@ -10,10 +10,6 @@ body{
background-color: #ffffff;
}
*::selection {
background-color: #2C7873;
color: #fff;
}
.b-wrapper {
width: 100%;
@ -309,12 +305,6 @@ body{
gap: 16px;
}
&__slider {
width: 100%;
position: relative;
margin: 8px 0 16px -5px;
}
&__title {
color: $black;
@include rem(15);
@ -490,20 +480,18 @@ body{
//
.card-profile {
display: flex !important;
display: flex;
flex-direction: column;
gap: 8px !important;
padding: 0 0 8px !important;
border-block-end: 1px solid #C4DFE6 !important;
margin: 0 0 16px !important;
gap: 8px;
padding-bottom: 8px;
border-bottom: 1px solid #C4DFE6;
&__header {
display: flex;
padding-bottom: 8px;
align-items: center !important;
align-items: center;
gap: 16px;
align-self: stretch;
margin-block-end: 0 !important;
&__portrait {
width: 86px;
@ -511,9 +499,8 @@ body{
border-radius: 16px;
border: 2px solid #FFF;
background: lightgray 50%;
box-shadow: 0 8px 16px 0 rgba(102, 165, 173, 0.32);
box-shadow: 0px 8px 16px 0px rgba(102, 165, 173, 0.32);
overflow: hidden;
margin-right: -16px;
img {
object-fit: cover;
@ -612,29 +599,70 @@ body{
align-self: stretch;
&__item {
margin-inline-end: 0 !important;
padding-inline: 4px !important;
font-size: 0.75rem;
height: 22px;
border-radius: 4px;
background: #2C7873;
display: inline-flex;
padding: 4px;
color: #FFF;
@include rem(12);
font-style: normal;
font-weight: 300;
line-height: 20px;
background: #2C7873 !important;
border-color: #2C7873 !important;
color: #fff !important;
height: 22px;
text-transform: capitalize;
line-height: 116.667%;
align-items: center;
}
&__more {
margin-inline-end: 0 !important;
padding-inline: 4px !important;
font-size: 0.75rem;
height: 22px;
display: inline-flex;
align-items: center;
padding: 4px;
border-radius: 4px;
border: 1px solid #2C7873;
color: #2C7873;
@include rem(12);
font-style: normal;
font-weight: 300;
line-height: 22px;
border-color: #2C7873 !important;
color: #2C7873 !important;
height: 22px;
line-height: 116.667%;
}
}
.pagination {
display: flex;
gap: 8px;
.page-item {
border-radius: 8px;
display: inline-flex;
height: 40px;
width: 40px;
.page-link {
border-radius: 8px;
border: 1px solid #2C7873;
display: inline-flex;
padding: 8px 16px;
justify-content: center;
align-items: center;
background: $white;
height: 40px;
width: 40px;
color: #2C7873;
text-align: center;
font-family: 'Inter', sans-serif;
@include rem(16);
font-style: normal;
font-weight: 400;
line-height: 150%;
text-decoration: none;
}
&.active {
.page-link {
background: #2C7873;
color: $white;
}
}
}
}
@ -712,17 +740,17 @@ body{
&__rating {
display: flex;
align-items: center;
gap: 8px;
flex-flow: wrap;
& > span {
span {
display: block;
color: #2C7873;
@include rem(13);
font-style: normal;
font-weight: 500;
line-height: 123.077%;
padding-top: 9px;
}
img {

View File

@ -610,3 +610,10 @@
}
}
}
.search-result {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 16px;
}

View File

@ -9,6 +9,5 @@
@import "_pages.scss";
@import "_form.scss";
@import "_message.scss";
@import "_auth-modal.scss";

View File

@ -1,108 +1,7 @@
export type Filter = Record<string, any>;
// export type Filter = {
// themesTagIds: number[];
// priceFrom?: number | null;
// priceTo?: number | null;
// durationFrom?: number | null;
// durationTo?: number | null;
// };
export type AdditionalFilter = {
text?: string;
sort?: string;
language?: string[];
};
export type Tag = {
id: number;
groupId: number;
name: string
couchCount?: number;
group?: string | null;
};
export type File = {
id: number;
fileType: string;
url: string;
};
export interface ExpertDocument {
fileName: string;
original?: File;
preview?: File;
fullSize?: File;
}
export type Details = {
id: number;
userId?:number;
title?: string;
description?: string;
document?: ExpertDocument;
};
export type Certificate = {
id: number;
userId?: number;
associationLevelId?: number;
document?: ExpertDocument;
};
export type Practice = {
id: number;
userId?: number;
description?: string;
themesGroupIds?: number[];
};
export type ThemeGroup = {
id: number;
name: string;
isActive?: boolean;
canDeleted?: boolean;
};
export type Association = {
id: number;
name: string;
};
export type AssociationLevel = {
id: number;
associationId: number;
name: string;
};
export interface ExpertItem {
id: number;
name: string;
surname?: string;
faceImageUrl?: string;
sessionDuration: number;
sessionCost: number;
coachRating?: number;
tags: Tag[];
speciality?: string;
specialityDesc?: string;
description?: string;
}
export type ExpertsData = ExpertItem[];
export type ExpertDetails = {
publicCoachDetails: ExpertItem & {
practiceHours?: number;
supervisionPerYearId?: number;
educations?: Details[];
certificates?: Certificate[];
trainings?: Details[];
mbas?: Details[];
experiences?: Details[];
practiceCases?: Practice[];
themesGroups?: ThemeGroup[];
};
associations?: Association[];
associationLevels?: AssociationLevel[];
};

View File

@ -29,8 +29,7 @@
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"dist/types/**/*.ts",
"build/types/**/*.ts"
"dist/types/**/*.ts"
],
"exclude": [
"node_modules"