/opt/canhelp/apps/web/.next/cache/webpack/server-production
NameSizeModeActions
0.pack925145390644editdlrm
1.pack12673790644editdlrm
2.pack43735990644editdlrm
3.pack7451990644editdlrm
4.pack65204660644editdlrm
5.pack259717610644editdlrm
6.pack7518430644editdlrm
7.pack46388840644editdlrm
8.pack48452960644editdlrm
9.pack97020644editdlrm
10.pack27038500644editdlrm
11.pack1361530644editdlrm
12.pack24060644editdlrm
13.pack4277340644editdlrm
14.pack6358240644editdlrm
15.pack19769150644editdlrm
16.pack85740644editdlrm
17.pack24591570644editdlrm
18.pack119171890644editdlrm
19.pack768050644editdlrm
20.pack31443360644editdlrm
21.pack60115380644editdlrm
22.pack10241010644editdlrm
index.pack77214480644editdlrm
index.pack.old84399530644editdlrm
Edit: /opt/canhelp/apps/web/.next/cache/webpack/server-production/21.pack (6011538B)
wpc[webpack/lib/cache/PackFileCacheStrategyPackContentItems `&Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[4].use[0]!/opt/canhelp/apps/web/src/app/tasks/page.tsx|rscCompilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[4].use[0]!/opt/canhelp/apps/web/src/app/robots.ts|rscCompilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[4].use[0]!/opt/canhelp/apps/web/src/app/sitemap.ts|rscCompilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[4].use[0]!/opt/canhelp/apps/web/src/lib/api.ts|rsc$Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/chat/page.tsx|ssr'Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/profile/page.tsx|ssr(Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/schedule/page.tsx|ssr0Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/specialist-setup/page.tsx|ssr)Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/tasks/new/page.tsx|ssr%Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/context/locale.tsx|ssrCompilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/lib/api.ts|ssr/Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/tasks/TaskListClient.tsx|ssr(Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/components/Footer.tsx|ssrCompilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/lib/auth.ts|ssr+Compilation/modules|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/components/Turnstile.tsx|ssr4Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[4].use[0]!/opt/canhelp/apps/web/src/app/tasks/page.tsx|rsc|webpack-runtime,Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[4].use[0]!/opt/canhelp/apps/web/src/lib/api.ts|rsc|webpack-runtime;Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/chat/page.tsx|ssr|webpack-runtime>Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/profile/page.tsx|ssr|webpack-runtime?Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/schedule/page.tsx|ssr|webpack-runtimeGCompilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/specialist-setup/page.tsx|ssr|webpack-runtime@Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/tasks/new/page.tsx|ssr|webpack-runtime<Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/context/locale.tsx|ssr|webpack-runtime4Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/lib/api.ts|ssr|webpack-runtimeFCompilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/app/tasks/TaskListClient.tsx|ssr|webpack-runtime5Compilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/lib/auth.ts|ssr|webpack-runtimeCompilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=!|rsc|7a7f45020dcf5f1c|webpack-runtimeCompilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=!|rsc|049d8527ae16ef50|webpack-runtimePCompilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/components/Footer.tsx|ssr|f8575f579785db27|webpack-runtimeSCompilation/codeGeneration|javascript/auto|/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js!/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!/opt/canhelp/apps/web/src/components/Turnstile.tsx|ssr|49d9f9ab1791da38|webpack-runtimeCompilation/assets|chunk784Compilation/assets|chunk475Compilation/assets|chunk892Compilation/assets|chunk902MinifierWebpackPlugin|../app/robots.txt/route.jsMinifierWebpackPlugin|../app/sitemap.xml/route.jsMinifierWebpackPlugin|892.jsMinifierWebpackPlugin|902.jswebpack/lib/NormalModulewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource"import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import Link from 'next/link'; import { cookies } from 'next/headers'; import { getCategories, getLocations, getTaskBudgetRange } from '@/lib/api'; import { getTranslations } from '@/lib/translations'; import { TaskListClient } from './TaskListClient'; import { TaskFiltersClient } from './TaskFiltersClient'; import { TasksAuthGuard } from './TasksAuthGuard'; const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export default async function TasksPage({ searchParams }) { const params = await searchParams; const page = Number(params.page || 1); const mode = params.mode === 'all' ? 'all' : 'for_me'; const cookieStore = await cookies(); const locale = cookieStore.get('canhelp_locale')?.value ?? 'el'; const cookieLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const t = getTranslations(locale); const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const cookieHeader = cookieStore.getAll().map((c)=>`${c.name}=${c.value}`).join('; '); let tasks = []; let total = 0; let noCards = false; let categories = []; let locationTree = []; let budgetRange = { min: 0, max: 0 }; const effectiveLocation = params.location ?? cookieLocation; const { q, category } = params; const rangeParams = {}; if (q) rangeParams.q = q; if (category) rangeParams.category = category; if (effectiveLocation) rangeParams.location = effectiveLocation; const effectiveParams = { page: String(page), limit: '10', ...params, ...effectiveLocation ? { location: effectiveLocation } : {} }; delete effectiveParams.mode; try { ; [categories, locationTree, budgetRange] = await Promise.all([ getCategories(), getLocations(), getTaskBudgetRange(Object.keys(rangeParams).length ? rangeParams : undefined) ]); } catch {} try { if (mode === 'for_me') { const forMeParams = new URLSearchParams(effectiveParams); const res = await fetch(`${API_BASE}/api/tasks/for-me?${forMeParams}`, { headers: { Cookie: cookieHeader }, cache: 'no-store' }); if (res.ok) { const json = await res.json(); if (json.noCards) { noCards = true; } else { tasks = json.data ?? []; total = json.total ?? 0; } } } else { const allParams = new URLSearchParams(effectiveParams); const res = await fetch(`${API_BASE}/api/tasks?${allParams}`, { headers: { Cookie: cookieHeader }, cache: 'no-store' }); if (res.ok) { const json = await res.json(); tasks = json.data ?? []; total = json.total ?? 0; } } } catch {} const catMap = {}; for (const cat of categories){ catMap[cat.slug] = cat.names[catLocale] ?? cat.names.el; for (const sub of cat.children ?? []){ catMap[sub.slug] = sub.names[catLocale] ?? sub.names.el; } } const locMap = {}; for (const city of locationTree){ locMap[city.slug] = city.names[catLocale] ?? city.names.el; for (const d of city.children ?? []){ locMap[d.slug] = d.names[catLocale] ?? d.names.el; } } const hasFilter = !!(params.q || params.category || params.location || params.budgetMin || params.budgetMax); const filterParams = {}; if (params.q) filterParams.q = params.q; if (params.category) filterParams.category = params.category; if (params.location) filterParams.location = params.location; if (params.budgetMin) filterParams.budgetMin = params.budgetMin; if (params.budgetMax) filterParams.budgetMax = params.budgetMax; return /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 py-8", children: [ /*#__PURE__*/ _jsx(TasksAuthGuard, {}), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row gap-8", children: [ /*#__PURE__*/ _jsx("aside", { className: "md:w-64 shrink-0", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5 sticky top-24", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-900 mb-4", children: t('tasks.filters') }), /*#__PURE__*/ _jsx(TaskFiltersClient, { categories: categories, locationTree: locationTree, budgetRange: budgetRange, initialMode: mode, initialQ: params.q, initialCategory: params.category, initialLocation: params.location, initialBudgetMin: params.budgetMin, initialBudgetMax: params.budgetMax }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsx("div", { className: "mb-6", children: /*#__PURE__*/ _jsx("h1", { className: "text-xl font-bold text-white", children: hasFilter ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ total, " ", t('tasks.title') ] }) : t('nav.tasks') }) }), noCards ? /*#__PURE__*/ _jsxs("div", { className: "bg-white/15 border border-white/30 rounded-xl p-8 text-center", children: [ /*#__PURE__*/ _jsx("div", { className: "text-4xl mb-3", children: "\uD83D\uDDC2️" }), /*#__PURE__*/ _jsx("p", { className: "text-white font-medium mb-2", children: t('find_tasks.no_cards') }), /*#__PURE__*/ _jsx(Link, { href: "/profile", className: "inline-block mt-2 px-5 py-2 bg-white text-blue-600 rounded-lg text-sm font-medium hover:bg-blue-50 transition", children: t('find_tasks.add_card') }) ] }) : /*#__PURE__*/ _jsx(TaskListClient, { initialTasks: tasks, initialTotal: total, filterParams: filterParams, locale: locale, catMap: catMap, locMap: locMap, mode: mode }, [ mode, params.q, params.category, params.location, params.budgetMin, params.budgetMax, page ].join('|')) ] }) ] }) ] }); } exportsTypesideEffectFreenamespace  javascript/autorsc/opt/canhelp/apps/web/src/app/tasksaliasmainFieldsconditionNames`$server-only$client-only$next/dist/compiled/server-only$next/dist/compiled/client-only$/opt/canhelp/node_modules/next/head.js/opt/canhelp/node_modules/next/image.js/opt/canhelp/node_modules/next/constants.js/opt/canhelp/node_modules/next/router.js/opt/canhelp/node_modules/next/dynamic.js/opt/canhelp/node_modules/next/script.js/opt/canhelp/node_modules/next/link.js/opt/canhelp/node_modules/next/form.js/opt/canhelp/node_modules/next/navigation.js/opt/canhelp/node_modules/next/headers.js/opt/canhelp/node_modules/next/og.js/opt/canhelp/node_modules/next/server.js/opt/canhelp/node_modules/next/document.js/opt/canhelp/node_modules/next/app.jsreact$react/compiler-runtime$react/jsx-dev-runtime$react/jsx-runtime$react-dom$react-dom/client$react-dom/server$react-dom/server.browser$react-dom/server.edge$react-dom/static$react-dom/static.browser$react-dom/static.edge$react-server-dom-webpack/client$react-server-dom-webpack/server$react-server-dom-webpack/server.node$react-server-dom-webpack/static$@vercel/turbopack-ecmascript-runtime/browser/dev/hmr-client/hmr-client.tsnextnext/dist/compiled/server-only/emptynext/dist/compiled/client-only/errornext/dist/client/components/noop-headnext/dist/api/imagenext/dist/api/constantsnext/dist/api/routernext/dist/api/app-dynamicnext/dist/api/scriptnext/dist/client/app-dir/linknext/dist/client/app-dir/formnext/dist/api/navigation.react-servernext/dist/api/headersnext/dist/api/ognext/dist/api/servernext/dist/api/documentnext/dist/api/appnext/dist/server/route-modules/app-page/vendored/rsc/reactnext/dist/server/route-modules/app-page/vendored/rsc/react-compiler-runtimenext/dist/server/route-modules/app-page/vendored/rsc/react-jsx-dev-runtimenext/dist/server/route-modules/app-page/vendored/rsc/react-jsx-runtimenext/dist/server/route-modules/app-page/vendored/rsc/react-domnext/dist/compiled/react-dom/clientnext/dist/compiled/react-dom/server.nodenext/dist/compiled/react-dom/server.browsernext/dist/build/webpack/alias/react-dom-server.jsnext/dist/compiled/react-dom/static.nodenext/dist/compiled/react-dom/static.browsernext/dist/compiled/react-dom/static.edgenext/dist/compiled/react-server-dom-webpack/client.nodenext/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-webpack-servernext/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-webpack-staticnext/dist/client/dev/noop-turbopack-hmr/opt/canhelp/node_modules/nextmodulemainreact-server...`cacheableparsedfileDependenciescontextDependenciesmissingDependenciesbuildDependenciesvalueDependencieshashassetsassetsInfostrictexportsArgumenttopLevelDeclarationssnapshot webpack/lib/util/LazySet/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-loader/index.js/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-swc-loader.jswebpack/DefinePlugin_hashwebpack/DefinePlugin process.env.NEXT_PUBLIC_API_URL4028310f"https://api.canhelp.gr"8fc3b9783ac2759etypeactionIdsclientRefsclientEntryTypeisClientRefserver  __webpack_exports__API_BASE*default*TasksPagewebpack/lib/FileSystemInfoSnapshot EyB/opt/canhelp/apps/web/src/app/tasks/page.tsxsafeTimetimestamp!`fyBPfyBe9e3359bb88edae5` webpack/lib/dependencies/HarmonyCompatibilityDependency dwebpack/lib/dependencies/ConstDependency`V `VaWt ``u@ `'A `LA `5A R `2AS `8A `2A b 00A  b Kwebpack/lib/dependencies/HarmonyExportHeaderDependencyA"A " @`$webpack/lib/dependencies/HarmonyImportSideEffectDependencyreact/jsx-runtime `Vnext/link `next/headers `'@/lib/api `L@/lib/translations `5./TaskListClient `2./TaskFiltersClient `8./TasksAuthGuard `2webpack/lib/dependencies/PureExpressionDependency A default  `Kwebpack/lib/dependencies/HarmonyExportSpecifierDependency` @webpack/lib/dependencies/HarmonyImportSpecifierDependencya cookies A    c% getTranslations A   c getCategories A   c/ / getLocations A   c0 0 getTaskBudgetRange A   c1 1 jsxs_jsxs Ahm   cjj jsx_jsx A   cmm TasksAuthGuard A 4 cmm-  A    cnn  A   cq"q&  A    cs0s5  A   cv.v2  A   cz.z2 TaskFiltersClient A 4 cz3zD  A   @`"@`'  AJN   @`*@`.  A   @`8@`<  Agl   @`H@`M Fragment_Fragment Amv 4 @`N@`W  A(-   @`4@`9  A   @`2@`6  A   @`2@`6  A   @`2@`6 Link A 4 @`7@`;  A  yy @`/@`3 TaskListClient A 4~~ @`4@`B  const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; export default function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } `   /opt/canhelp/apps/web/src/app" 1  234webpack/DefinePlugin process.env.NEXT_PUBLIC_APP_URL5"http://canhelp.gr"e21eb76bb0be822f ;<   = APP_URL>robots EyB/opt/canhelp/apps/web/src/app/robots.ts A!@v)yB0v)yB98480c3cfda03512  d a/ b/0 a3J bJ `[@ `L@ a  aJ b `J` a   const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } export default async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } `     1833543e201be90f     fetchAllTasksfetchAllSpecialists܇API_URLSTATIC_ROUTESsitemap EyB/opt/canhelp/apps/web/src/app/sitemap.ts !@yB0yBf44001f3979d6782  d a/ b/0 a3J bJ a\{ b/0 `@ bJ A  A  cZd  `\@ 9 `J7 cZd  fQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); ` } /opt/canhelp/apps/web/src/lib   0644203e50beb1bc     @BASErequestgetTasks?searchTasksgetMyTasksgetTasksForSpecialistgetTaskCountsByCategorygetTaskcreateTaskupdateTaskcompleteTaskcancelTaskgetOffersgetMyOfferscreateOfferacceptOfferdeclineOffergetUserProfilegetSpecialistscreateReviewgetTaskReviewsgetMyReviewsgetChatRoomsgetOrCreateDirectRoomgetCanMessagegetMessagessendMessageupdateNotifSettingsgetNotificationsgetUnreadCountmarkReadmarkAllReadgetTaskInvitedismissNotificationgetMyReferralInfogetUserReviewsgetUserRatinggetFavoritesaddFavoriteremoveFavoritegetSpecialistFavoritesaddSpecialistFavoriteremoveSpecialistFavoritegetAdminCategoriescreateCategoryupdateCategorydeleteCategorygetAdminStatsgetAdminUsersdeactivateUseractivateUserchangeUserRolegetAdminUsergetAdminUserSpecialistCardsadminUpdateSpecialistCardupdateAdminUserverifyAdminUserEmailgetAdminTaskscancelTaskAdmindeleteTaskAdmingetAdminReportsupdateReportStatusgetAdminAiLogsgetAdminActivityLogsgetAdminMailLogsgetAdminNotifLogsgetAdminNotifStatsgetAdminMailStatsgetAdminLocationscreateLocationupdateLocationdeleteLocationgetAdminPlanscreatePlanupdatePlandeletePlangetAdminSettingsupdateAdminSettingsgetAdminEmailTemplatesupdateAdminEmailTemplatetranslateAdminEmailTemplatesendTestEmailgetMyAvailabilitysetAvailabilitysetAvailabilityRangegetSpecialistAvailabilitygetMyPortfolioaddPortfolioItemupdatePortfolioItemdeletePortfolioItemgetSpecialistPortfoliogetMySpecialistCardscreateSpecialistCardupdateSpecialistCarddeleteSpecialistCardgetSpecialistCardsgetSkillSuggestionsinitiateTopUpgetPaymentHistorygetBalanceHistorygetAdminBalanceHistoryadminTopUpUserBalanceadminWithdrawUserBalancepreviewPlanChangegetPlansgetMyDashboardgetDailyUsagepurchasePlangetMyStatusestoggleStatusgetAutoResponseSettingsupdateAutoResponseSettingsgetSpecialistFomoDashboardgetCustomerFomoDashboardgetFomoRecommendationsgetAutoMatchResultsrunAutoMatchgetGoogleCalendarStatusdisconnectGoogleCalendarimportFromGoogleCalendargetGoogleCalendarConnectUrlgetPublicSiteProfilegetSiteStatstrackSiteMessagegetTaskStats EyB/opt/canhelp/apps/web/src/lib/api.ts z!+TyB+TyB3d3e7ac4aaff706e @ d Ab  A[  a A_ AX c A A c  A A c!!] A A c""3 A A c#& A A c''P A 9 A9 c((5 AA A: c), A6 A6 c-0 A> A7 c13 A A c46 AS  AL  c88G A  A  c995 A D  A D  c:= AL  AE  c>@ A  A  cAC A Q  A Q  cDDD AY  AR  cEH A j  A j  cIL Ar  Ak  cMMK A  A  cNN7 AE u  A> u  cPP7 A}  Av  cQQQ A  A  cRRN Af Af cSSO An Ag cTZ Ar Ak c\_ A/ A/ c``> A7r A0r caaB Az As cbd A; A; ceg AC A< chhh A A cik Af A_ cmmC A< A< cooK AD A= cppQ A A crr8 Ak Ad ctt6 A A cvv6 A' A  cwy A A cz| A= A= c}}L AE A> a~@ AR AR @@ A4 A4 @@`C A< A5 @@ AO AO @@ AW AP @@ AB A B @@`9 AJ; AC; @@ AC A< @@ A A @@ A A @@ A A @@`@ A j Aj @@`h Ar Ak @@ A A @@ A A @@ A  A  @@ A  A  @@ A  A  @@ A C! A C! @@`[ AK!! AD!! @@ A"U" A!U" @@`Z A]"$ AV"$ @@ A$% A$% @@ A%' A%' @@ A%'i' A'i' @@`K Aq'' Aj'' @@`B A(=( A'=( @@`A AE(( A>(( @@ A(V) A(V) @@ A^)) AW)) @@ A*H* A*H* @@`9 AP** AI** @@ A*Q+ A*Q+ @@ AY++ AR++ @@ A ,A, A,A, @@`? AI,, AB,, @@  A,- A,- @ @ `O A#-- A-- @ @ A-g. A-g. @@ Ao.. Ah.. @@ A&// A// @@`g A/[0 A/[0 @@  Ac071 A\071 @!@( A?11 A811 @)A) A11 A11 @*@*`; A13 A13 @+@7 A334 A334 @8@; A;44 A444 @<@> A44 A44 @?@?`U A4:5 A4:5 @@@@`H AB55 A;55 @A@D A5a6 A5a6 @E@H Ai66 Ab66 @I@K A6*7 A6*7 @L@L`X A278 A+78 @M@P A88 A88 @Q@V A88 A88 @W@W`B A9`9 A8`9 @X@X`c Ah9: Aa9: @Y@` A:O; A:O; @a@d AW;; AP;; @e@h A;< A;< @i@n A<= A<= @o@r A=S= A=S= @s@s`; A[== AT== @t@t`? A=n> A=n> @u@{ A>> A>> @}@}`9 A>? A>? @~@ A?@ A?@ @@`E A @@ A@@ @@ A@,A A@,A @@`J A4AsA A-AsA @@`F A{AA AtAA @@`K AB]B AB]B @@`N AeBB A^BB @@ ACcC ACcC @@`N AkCC AdCC @@ ACID ACID @@ AQDD AJDD @@`U AD:E AD:E @@`K ABE{E A;E{E @@`@ AEE A|EE @@` AVFF AOFF @@`H true A a @0 AY @@ A bKj0 A a+@true A `I ` a c11 c  c!!] c""3 c#& c''P c((5 c), c-0 c13 c46 c88G c995 c:= c>@ cAC cDDD cEH cIL cMMK cNN7 cPP7 cQQQ cRRN cSSO cTZ c\_ c``> caaB cbd ceg chhh cik cmmC cooK cppQ crr8 ctt6 cvv6 cwy cz| c}}L a~@ @@ @@`C @@ @@ @@ @@`9 @@ @@ @@ @@ @@`@ @@`h @@ @@ @@ @@ @@ @@ @@`[ @@ @@`Z @@ @@ @@ @@`K @@`B @@`A @@ @@ @@ @@`9 @@ @@ @@ @@`? @@  @ @ `O @ @ @@ @@ @@`g @@  @!@( @)A) @*@*`; @+@7 @8@; @<@> @?@?`U @@@@`H @A@D @E@H @I@K @L@L`X @M@P @Q@V @W@W`B @X@X`c @Y@` @a@d @e@h @i@n @o@r @s@s`; @t@t`? @u@{ @}@}`9 @~@ @@`E @@ @@`J @@`F @@`K @@`N @@ @@`N @@ @@ @@`U @@`K @@`@ @@` @@`H  m/* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState, useEffect, useRef, useCallback, Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { getChatRooms, getMessages, getDailyUsage } from '@/lib/api'; import { formatShortName } from '@/lib/formatName'; import { io } from 'socket.io-client'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; function ChatPageInner() { const router = useRouter(); const searchParams = useSearchParams(); const { data: session, isPending } = useSession(); const { t, locale } = useLocale(); const [rooms, setRooms] = useState([]); const [loadingRooms, setLoadingRooms] = useState(true); const [activeRoomId, setActiveRoomId] = useState(null); const [messages, setMessages] = useState([]); const [loadingMessages, setLoadingMessages] = useState(false); const [input, setInput] = useState(''); const [connected, setConnected] = useState(false); const [msgLimit, setMsgLimit] = useState(null); const socketRef = useRef(null); const messagesEndRef = useRef(null); const inputRef = useRef(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); }, [ session, isPending ]); // Load chat rooms process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; getChatRooms().then((data)=>{ setRooms(data); const roomParam = searchParams.get('room'); if (roomParam) setActiveRoomId(roomParam); }).catch(()=>{}).finally(()=>setLoadingRooms(false)); getDailyUsage().then((u)=>setMsgLimit({ left: u.messagesLeft, sent: u.messagesSent })).catch(()=>{}); }, [ session ]); // Setup Socket.IO process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; const socket = io(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socketRef.current = socket; socket.on('connect', ()=>setConnected(true)); socket.on('disconnect', ()=>setConnected(false)); socket.on('new_message', (msg)=>{ setMessages((prev)=>{ // avoid duplicate if we get it back from our own send if (prev.some((m)=>m.message.id === msg.id)) return prev; return [ ...prev, { message: msg, sender: session.user ? { id: session.user.id, name: session.user.name ?? '', image: session.user.image ?? undefined } : null } ]; }); // Update lastMessage in rooms list and bubble room to top setRooms((prev)=>{ const updated = prev.map((r)=>r.room.id === msg.roomId ? { ...r, lastMessage: { body: msg.body, createdAt: msg.createdAt, translations: msg.translations ?? null } } : r); return updated.sort((a, b)=>{ const aTime = a.lastMessage?.createdAt ? new Date(a.lastMessage.createdAt).getTime() : new Date(a.room.createdAt).getTime(); const bTime = b.lastMessage?.createdAt ? new Date(b.lastMessage.createdAt).getTime() : new Date(b.room.createdAt).getTime(); return bTime - aTime; }); }); }); socket.on('message_translated', ({ id, roomId, translations })=>{ setMessages((prev)=>prev.map((m)=>m.message.id === id ? { ...m, message: { ...m.message, translations } } : m)); // Also update lastMessage in sidebar if this is the last message of that room if (roomId) { setRooms((prev)=>prev.map((r)=>r.room.id === roomId && r.lastMessage ? { ...r, lastMessage: { ...r.lastMessage, translations } } : r)); } }); return ()=>{ socket.disconnect(); socketRef.current = null; }; }, [ session ]); // Join room and load messages when activeRoomId changes process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!activeRoomId) return; setLoadingMessages(true); setMessages([]); getMessages(activeRoomId).then(setMessages).catch(()=>{}).finally(()=>setLoadingMessages(false)); socketRef.current?.emit('join_room', activeRoomId); socketRef.current?.emit('mark_read', activeRoomId); }, [ activeRoomId ]); // Focus input when active room changes process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!activeRoomId) return; const t = setTimeout(()=>inputRef.current?.focus(), 50); return ()=>clearTimeout(t); }, [ activeRoomId ]); // Auto-scroll on new messages (within container only) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, [ messages ]); const sendMessage = useCallback(()=>{ const body = input.trim(); if (!body || !activeRoomId || !socketRef.current) return; if (msgLimit && msgLimit.left !== null && msgLimit.left <= 0) return; socketRef.current.emit('send_message', { roomId: activeRoomId, body, locale }); setInput(''); // decrement local counter setMsgLimit((prev)=>prev && prev.left !== null ? { ...prev, left: prev.left - 1, sent: prev.sent + 1 } : prev); }, [ input, activeRoomId, msgLimit ]); const handleKeyDown = (e)=>{ if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; const LOCALE_TAG = { ru: 'ru-RU', en: 'en-US', el: 'el-GR' }; const localeTag = LOCALE_TAG[locale] ?? 'el-GR'; function fmtMsgTime(iso) { const d = new Date(iso); const now = new Date(); const diffMin = Math.floor((now.getTime() - d.getTime()) / 60000); if (diffMin < 1) return t('chat.just_now'); if (diffMin < 60) return `${diffMin}${t('chat.min_ago')}`; if (d.toDateString() === now.toDateString()) return d.toLocaleTimeString(localeTag, { hour: '2-digit', minute: '2-digit' }); return d.toLocaleDateString(localeTag, { day: '2-digit', month: '2-digit' }); } if (isPending || loadingRooms) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const activeRoom = rooms.find((r)=>r.room.id === activeRoomId); const currentUserId = session?.user?.id; return /*#__PURE__*/ _jsxs("div", { className: "max-w-5xl mx-auto px-4 py-6 h-[calc(100vh-80px)] flex gap-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "w-72 flex-shrink-0 bg-white rounded-xl border border-gray-200 overflow-hidden flex flex-col", children: [ /*#__PURE__*/ _jsxs("div", { className: "p-4 border-b border-gray-100", children: [ /*#__PURE__*/ _jsx("h1", { className: "font-bold text-gray-900 text-lg", children: t('nav.chat') }), /*#__PURE__*/ _jsxs("div", { className: `flex items-center gap-1.5 mt-1`, children: [ /*#__PURE__*/ _jsx("span", { className: `w-2 h-2 rounded-full ${connected ? 'bg-green-400' : 'bg-gray-300'}` }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400", children: connected ? t('chat.connected') : t('chat.disconnected') }) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "flex-1 overflow-y-auto", children: rooms.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "p-6 text-center text-gray-400 text-sm", children: t('chat.no_rooms') }) : rooms.map(({ room, task, otherUser, lastMessage })=>{ const roomLabel = task?.title ?? (formatShortName(otherUser?.firstName, otherUser?.lastName, otherUser?.name) || t('chat.direct_chat')); const roomSub = task ? formatShortName(otherUser?.firstName, otherUser?.lastName, otherUser?.name) || '' : t('chat.direct_chat'); return /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setActiveRoomId(room.id); setTimeout(()=>inputRef.current?.focus(), 50); }, className: `w-full text-left px-4 py-3 border-b border-gray-50 hover:bg-gray-50 transition ${activeRoomId === room.id ? 'bg-blue-50 border-l-2 border-l-blue-500' : ''}`, children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-start justify-between gap-1", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800 line-clamp-1 flex-1", children: roomLabel }), lastMessage && /*#__PURE__*/ _jsx("span", { className: "text-[10px] text-gray-400 shrink-0 mt-0.5", children: fmtMsgTime(lastMessage.createdAt) }) ] }), lastMessage ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5 line-clamp-1", children: lastMessage.translations?.[locale] ?? lastMessage.body }) : task ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5 line-clamp-1", children: roomSub }) : null ] }, room.id); }) }) ] }), /*#__PURE__*/ _jsx("div", { className: "flex-1 bg-white rounded-xl border border-gray-200 flex flex-col overflow-hidden", children: !activeRoomId ? /*#__PURE__*/ _jsx("div", { className: "flex-1 flex items-center justify-center text-gray-400 text-sm", children: t('chat.select') }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("div", { className: "px-5 py-4 border-b border-gray-100", children: /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-800 text-sm", children: activeRoom?.task?.title ?? (formatShortName(activeRoom?.otherUser?.firstName, activeRoom?.otherUser?.lastName, activeRoom?.otherUser?.name) || t('chat.direct_chat')) }) }), activeRoom?.task && /*#__PURE__*/ _jsxs(Link, { href: `/tasks/${activeRoom.task.id}`, className: "flex items-center gap-3 mx-5 mt-4 px-4 py-3 bg-blue-50 border border-blue-200 rounded-xl hover:bg-blue-100 transition group", children: [ /*#__PURE__*/ _jsx("div", { className: "w-8 h-8 rounded-lg bg-blue-600 flex items-center justify-center flex-shrink-0", children: /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-white", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [ /*#__PURE__*/ _jsx("path", { d: "M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2" }), /*#__PURE__*/ _jsx("rect", { x: "8", y: "2", width: "8", height: "4", rx: "1", ry: "1" }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs text-blue-500 font-medium", children: t('chat.linked_task') }), /*#__PURE__*/ _jsx("p", { className: "text-sm font-semibold text-blue-800 truncate group-hover:underline", children: activeRoom.task.title }) ] }), /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-blue-400 flex-shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /*#__PURE__*/ _jsx("polyline", { points: "9 18 15 12 9 6" }) }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-4 space-y-3", children: [ loadingMessages ? /*#__PURE__*/ _jsx("div", { className: "text-center text-gray-400 text-sm py-10", children: t('common.loading') }) : messages.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "text-center text-gray-400 text-sm py-10", children: t('chat.no_messages') }) : messages.map(({ message, sender })=>{ const isMe = message.senderId === currentUserId; return /*#__PURE__*/ _jsxs("div", { className: `flex gap-2.5 ${isMe ? 'flex-row-reverse' : ''}`, children: [ /*#__PURE__*/ _jsx("div", { className: "w-8 h-8 rounded-full bg-blue-100 flex-shrink-0 flex items-center justify-center text-blue-700 text-xs font-bold overflow-hidden", children: sender?.image ? /*#__PURE__*/ _jsx("img", { src: sender.image, alt: sender.name, className: "w-full h-full object-cover" }) : sender?.name?.[0]?.toUpperCase() ?? '?' }), /*#__PURE__*/ _jsxs("div", { className: `max-w-[70%] ${isMe ? 'items-end' : 'items-start'} flex flex-col gap-1`, children: [ !isMe && /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400 px-1", children: formatShortName(sender?.firstName, sender?.lastName, sender?.name) }), /*#__PURE__*/ _jsx("div", { className: `px-4 py-2 rounded-2xl text-sm leading-relaxed ${isMe ? 'bg-blue-600 text-white rounded-tr-sm' : 'bg-gray-100 text-gray-800 rounded-tl-sm'}`, children: message.translations?.[locale] ?? message.body }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-300 px-1", children: new Date(message.createdAt).toLocaleTimeString(localeTag, { hour: '2-digit', minute: '2-digit' }) }) ] }) ] }, message.id); }), /*#__PURE__*/ _jsx("div", { ref: messagesEndRef }) ] }), /*#__PURE__*/ _jsxs("div", { className: "px-4 py-3 border-t border-gray-100", children: [ msgLimit && msgLimit.left !== null && msgLimit.left <= 0 && /*#__PURE__*/ _jsxs("div", { className: "mb-2 flex items-center gap-2 bg-red-50 border border-red-200 rounded-xl px-3 py-2", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-red-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }) }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-red-700 flex-1", children: t('chat.limit_reached', 'Дневной лимит сообщений исчерпан') }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "text-xs font-medium text-red-700 underline", children: t('plan.upgrade') }) ] }), msgLimit && msgLimit.left !== null && msgLimit.left > 0 && msgLimit.left <= Math.ceil((msgLimit.left + msgLimit.sent) * 0.2) && /*#__PURE__*/ _jsxs("div", { className: "mb-2 flex items-center gap-2 bg-amber-50 border border-amber-200 rounded-xl px-3 py-2", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-amber-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }) }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-amber-700 flex-1", children: t('chat.limit_warning', 'Осталось {n} сообщений сегодня').replace('{n}', String(msgLimit.left)) }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "text-xs font-medium text-amber-700 underline", children: t('plan.upgrade') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2 items-end", children: [ /*#__PURE__*/ _jsx("textarea", { ref: inputRef, value: input, onChange: (e)=>setInput(e.target.value), onKeyDown: handleKeyDown, rows: 1, placeholder: t('chat.placeholder'), disabled: !!(msgLimit && msgLimit.left !== null && msgLimit.left <= 0), className: "flex-1 border border-gray-300 rounded-xl px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none max-h-32 disabled:bg-gray-50 disabled:text-gray-400", style: { minHeight: '40px' } }), /*#__PURE__*/ _jsx("button", { onClick: sendMessage, disabled: !input.trim() || !connected || !!(msgLimit && msgLimit.left !== null && msgLimit.left <= 0), className: "h-10 w-10 bg-blue-600 text-white rounded-xl hover:bg-blue-700 disabled:opacity-40 disabled:cursor-not-allowed flex-shrink-0 flex items-center justify-center", children: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 12h14M12 5l7 7-7 7" }) }) }) ] }) ] }) ] }) }) ] }); } export default function ChatPage() { return /*#__PURE__*/ _jsx(Suspense, { fallback: /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: "..." }), children: /*#__PURE__*/ _jsx(ChatPageInner, {}) }); } `   ssr/opt/canhelp/apps/web/src/app/chat    `$next/dist/compiled/server-only    next/dist/compiled/server-only/indexnext/dist/compiled/client-only/index next/dist/api/navigationnext/dist/server/route-modules/app-page/vendored/ssr/reactnext/dist/server/route-modules/app-page/vendored/ssr/react-compiler-runtimenext/dist/server/route-modules/app-page/vendored/ssr/react-jsx-dev-runtimenext/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtimenext/dist/server/route-modules/app-page/vendored/ssr/react-dom next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-webpack-clientnext/dist/compiled/react-server-dom-webpack/server.nodenext/dist/compiled/react-server-dom-webpack/static.node!"% 7  /opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.js89:;<a525f46734d39a7e  =>Aclient  C ChatPageInner)DChatPage EyB/opt/canhelp/apps/web/src/app/chat/page.tsx G! fyBfyB3426eb4ec40452e6 `  d `=@ a=@ A `K A `= A; ` A<d `( Ae `- A `E A  `3 A 3 `& ADc b /0 Ag~ b J AGlUm A8lUm @@ `kFF a=@react `Knext/navigation `=CC `@/lib/auth `(@/context/locale `-BB `E@/lib/formatName `3 socket.io-client `& AD~ G  `J useRouter A   A c   useSearchParams A   c  ( useSession A   c)3 useLocale A8A   c# useState Ack   c&  A   c,4  A   c,4  A    c$,  AMU   c2:  A|   c&  A   c&.  A   c$, useRef A    c  A4:   c!  AW]   c useEffect A   c7@  Air   c"7"@  A   c$$ 65 A   c))  A   c171@ io A    c33  A2;   cy7y@  A   c}}  A    @`7@`@  A;D   @`7@`@ useCallback A   ~~ @`@`#  A15   @`@`!  A<A   @`@`  A   @`@`  A    @`"@`'  A2!6!   @`*@`.  A""  { @`*@`/  A""  w @`2@`6  A##  s @`2@`6  A,%0%  o @`"@`&  A%%  k @`E@`I formatShortName A&&  f[[ @`>@`M  A~''  bWW @`3@`B  A((  ^ @`1@`6  A7*<*  Z @`2@`7  A++  V @`:@`>  AN,R,  R @`I@`M  A--  N~~ @`@@`D  A..  Jzz @`>@`B  A00  Fvv @`@`  A61:1  Brr @`8@`<  A11  >nn @`#@`(  A12 4:jj @`)@`2  AO2S2  6ff @`&@`*  A22  2bb @`4@`8  A33  .## @`F@`U  A44  *ZZ @`:@`? j A44 4&XX @`@@`D  A55  "RR @"`.@"`2  A66  NN @$`<@$`A  A88  JJ @-`:@-`> ~ A99  FF @0`:@0`> tu A;;  BB @;`.@;`3 vw A<<  >> @>`6@>`: rs A==   :: @B`6@B`: no A:?>?  66 @H`.@H`2 jk A/A3A  22 @P`<@P`@ `a A-B2B  .. @V`&@V`+ bc ABB  ** @Y`@@Y`D ^_ ACC  && @\`K@\`O TU AsExE  "" @a`9@a`> VW AUFYF   @d`:@d`> RS AyG}G   @f`X@f`\ HI A7I? AMM   @w`B@w`F :; APP   @`.@`2 01 A_QdQ   @`&@`+ ,- AMRRR   @`j@`o ./ AFSJS   @`6@`: *+ ATT   @`D@`H &' AVV   @`6@`: "# AWW   @`6@`:i AWW 4 @`;@`?  A ZZ   C  A[ [   @`6@`:  A\\   @`D@`H  Aw^{^   @`6@`:    A__   @`6@`:yR A__ 4 @`;@`?  Asaxa   @`.@`3  A/b3b   @`6@`:  A;f?f   @`6@`:  A{ if (cardTab !== 'skills') return; api.getSkillSuggestions(localCategories.length > 0 ? localCategories : undefined).then(setApiSkillSugs).catch(()=>setApiSkillSugs([])); }, [ localCategories, cardTab ]); const lbl = (ru, en, el)=>locale === 'ru' ? ru : locale === 'en' ? en : el; async function saveAll() { setSaving(true); try { const updated = await api.updateSpecialistCard(card.id, { title: localTitle, description: localDesc || null, skills: localSkills, categories: localCategories, locations: localLocations }); onUpdate({ ...updated, portfolio }); setSavedOk(true); setTimeout(()=>setSavedOk(false), 2000); } catch {} finally{ setSaving(false); } } async function toggleActive() { const next = !localActive; setLocalActive(next); try { await api.updateSpecialistCard(card.id, { isActive: next }); } catch {} } function addSkill(s) { const trimmed = s.trim(); if (trimmed && !localSkills.includes(trimmed)) setLocalSkills([ ...localSkills, trimmed ]); setSkillInput(''); } function toggleCategory(slug, childSlugs = []) { if (localCategories.includes(slug)) { setLocalCategories(localCategories.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocalCategories([ ...new Set([ ...localCategories, slug, ...childSlugs ]) ]); } } function toggleLocation(slug, childSlugs = []) { if (localLocations.includes(slug)) { setLocalLocations(localLocations.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocalLocations([ ...new Set([ ...localLocations, slug, ...childSlugs ]) ]); } } async function handlePortfolioUpload(e) { const file = e.target.files?.[0]; if (!file) return; setPortfolioUploading(true); try { const form = new FormData(); form.append('file', file); form.append('cardId', card.id); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}/api/portfolio`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const item = await res.json(); const next = [ ...portfolio, item ]; setPortfolio(next); onUpdate({ ...card, portfolio: next }); } catch {} finally{ setPortfolioUploading(false); if (portfolioFileRef.current) portfolioFileRef.current.value = ''; } } async function handlePortfolioDelete(id) { try { await api.deletePortfolioItem(id); const next = portfolio.filter((p)=>p.id !== id); setPortfolio(next); onUpdate({ ...card, portfolio: next }); } catch {} } async function handlePortfolioSave(id) { try { const item = await api.updatePortfolioItem(id, { title: editTitle, description: editDesc }); setPortfolio((prev)=>prev.map((p)=>p.id === id ? item : p)); setEditingItem(null); } catch {} } const cardTabs = [ { id: 'main', label: t('profile.card.tab.main') }, { id: 'skills', label: t('profile.card.tab.skills') }, { id: 'categories', label: t('profile.card.tab.categories') }, { id: 'geography', label: t('profile.card.tab.geography') }, { id: 'portfolio', label: t('profile.card.tab.portfolio') } ]; return /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 overflow-hidden", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-gray-100", children: [ /*#__PURE__*/ _jsxs("button", { type: "button", onClick: onToggle, className: "flex-1 flex items-center gap-3 text-left", children: [ /*#__PURE__*/ _jsx("span", { className: "text-sm font-semibold text-gray-800 flex-1", children: localTitle || card.title }), /*#__PURE__*/ _jsx("span", { className: "text-gray-400 text-xs", children: isOpen ? '▲' : '▼' }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", title: t('profile.card.active'), onClick: toggleActive, className: `w-8 h-5 rounded-full transition-colors flex-shrink-0 ${localActive ? 'bg-green-400' : 'bg-gray-300'}`, children: /*#__PURE__*/ _jsx("span", { className: `block w-4 h-4 rounded-full bg-white shadow transition-transform mx-0.5 ${localActive ? 'translate-x-3' : ''}` }) }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: onDelete, className: "text-red-400 hover:text-red-600 text-sm px-1 flex-shrink-0", title: t('profile.card.delete'), children: "\uD83D\uDDD1" }) ] }), isOpen && /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("div", { className: "flex overflow-x-auto border-b border-gray-100 bg-gray-50 gap-0", children: cardTabs.map((t)=>/*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setCardTab(t.id), className: `px-4 py-2.5 text-xs font-medium whitespace-nowrap border-b-2 transition -mb-px ${cardTab === t.id ? 'border-blue-500 text-blue-600 bg-white' : 'border-transparent text-gray-500 hover:text-gray-700'}`, children: t.label }, t.id)) }), /*#__PURE__*/ _jsxs("div", { className: "p-4", children: [ cardTab === 'main' && /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsx("input", { value: localTitle, onChange: (e)=>setLocalTitle(e.target.value), maxLength: 200, placeholder: t('profile.cards.new_title'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("textarea", { value: localDesc, onChange: (e)=>setLocalDesc(e.target.value), rows: 4, maxLength: 1000, placeholder: t('profile.bio.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), cardTab === 'skills' && /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ localSkills.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2", children: localSkills.map((s)=>/*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5 bg-blue-50 text-blue-700 text-sm px-3 py-1 rounded-full", children: [ s, /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setLocalSkills(localSkills.filter((x)=>x !== s)), className: "text-blue-400 hover:text-blue-700 leading-none", children: "\xd7" }) ] }, s)) }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2", children: [ /*#__PURE__*/ _jsx("input", { value: skillInput, onChange: (e)=>setSkillInput(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') { e.preventDefault(); addSkill(skillInput); } }, placeholder: t('profile.card.skill.add'), className: "flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>addSkill(skillInput), className: "px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium", children: "+" }) ] }), apiSkillSugs.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-1.5", children: apiSkillSugs.map((s)=>s.names[catLocale] ?? s.names.el).filter((name, i, arr)=>arr.indexOf(name) === i && !localSkills.includes(name)).slice(0, 16).map((name)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>addSkill(name), className: "text-xs px-2.5 py-1 border border-gray-200 rounded-full text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: [ "+ ", name ] }, name)) }) ] }), cardTab === 'categories' && /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: categories.map((cat)=>{ const catName = cat.names?.[catLocale] ?? cat.names?.el ?? cat.slug; const children = cat.children ?? []; const childSlugs = children.map((c)=>c.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localCategories.includes(cat.slug), onChange: ()=>toggleCategory(cat.slug, childSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("span", { className: "text-sm font-medium text-gray-800", children: [ cat.icon && /*#__PURE__*/ _jsx("span", { className: "mr-1", children: cat.icon }), catName ] }) ] }), children.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-2 space-y-2", children: children.map((sub)=>{ const subName = sub.names?.[catLocale] ?? sub.names?.el ?? sub.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localCategories.includes(sub.slug), onChange: ()=>toggleCategory(sub.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: subName }) ] }, sub.id); }) }) ] }, cat.id); }) }), cardTab === 'geography' && /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: locationTree.map((city)=>{ const cityName = city.names?.[catLocale] ?? city.names?.el ?? city.slug; const districts = city.children ?? []; const districtSlugs = districts.map((d)=>d.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localLocations.includes(city.slug), onChange: ()=>toggleLocation(city.slug, districtSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-800", children: cityName }) ] }), districts.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-2 space-y-2", children: districts.map((d)=>{ const dName = d.names?.[catLocale] ?? d.names?.el ?? d.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localLocations.includes(d.slug), onChange: ()=>toggleLocation(d.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: dName }) ] }, d.id); }) }) ] }, city.id); }) }), cardTab === 'portfolio' && /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ portfolio.length < 20 && /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>portfolioFileRef.current?.click(), disabled: portfolioUploading, className: "flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium disabled:opacity-50", children: portfolioUploading ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("span", { className: "w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" }), t('profile.card.photo.uploading') ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ "\uD83D\uDCF7 ", t('profile.card.photo.add') ] }) }), /*#__PURE__*/ _jsx("input", { ref: portfolioFileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handlePortfolioUpload }) ] }), portfolio.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "text-center py-8 text-gray-400 text-sm border-2 border-dashed border-gray-200 rounded-xl", children: t('profile.card.photo.empty') }) : /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-3", children: portfolio.map((item)=>/*#__PURE__*/ _jsxs("div", { className: "group relative rounded-xl overflow-hidden border border-gray-200 bg-gray-50", children: [ /*#__PURE__*/ _jsx("img", { src: item.imageUrl, alt: item.title ?? '', className: "w-full aspect-square object-cover" }), /*#__PURE__*/ _jsxs("div", { className: "absolute inset-0 bg-black/0 group-hover:bg-black/50 transition-all flex flex-col justify-between p-2", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>handlePortfolioDelete(item.id), className: "self-end opacity-0 group-hover:opacity-100 transition w-7 h-7 rounded-full bg-red-500 text-white text-sm flex items-center justify-center hover:bg-red-600", children: "\xd7" }), /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>{ setEditingItem(item); setEditTitle(item.title ?? ''); setEditDesc(item.description ?? ''); }, className: "opacity-0 group-hover:opacity-100 transition text-xs text-white bg-black/50 hover:bg-black/70 rounded-lg px-2 py-1", children: [ "✏️ ", t('profile.card.item.edit') ] }) ] }), item.title && /*#__PURE__*/ _jsx("div", { className: "px-2 py-1.5", children: /*#__PURE__*/ _jsx("p", { className: "text-xs font-medium text-gray-700 truncate", children: item.title }) }) ] }, item.id)) }) ] }), cardTab !== 'portfolio' && /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 mt-4 pt-4 border-t border-gray-100", children: [ /*#__PURE__*/ _jsx("button", { type: "button", disabled: saving, onClick: saveAll, className: "px-5 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-semibold disabled:opacity-50", children: saving ? '...' : t('profile.card.save') }), savedOk && /*#__PURE__*/ _jsxs("span", { className: "text-sm text-green-600", children: [ "✓ ", t('profile.card.saved') ] }) ] }) ] }) ] }), editingItem && /*#__PURE__*/ _jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl shadow-xl p-6 w-full max-w-md", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-800 mb-4", children: t('profile.card.item.edit') }), /*#__PURE__*/ _jsx("img", { src: editingItem.imageUrl, alt: "", className: "w-full h-40 object-cover rounded-xl mb-4" }), /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.card.item.title') }), /*#__PURE__*/ _jsx("input", { value: editTitle, onChange: (e)=>setEditTitle(e.target.value), maxLength: 200, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.card.item.desc') }), /*#__PURE__*/ _jsx("textarea", { value: editDesc, onChange: (e)=>setEditDesc(e.target.value), rows: 3, maxLength: 1000, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-3 mt-5", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>handlePortfolioSave(editingItem.id), className: "flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 rounded-lg text-sm font-medium", children: t('profile.card.item.save') }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setEditingItem(null), className: "flex-1 bg-gray-100 hover:bg-gray-200 text-gray-700 py-2 rounded-lg text-sm font-medium", children: t('profile.card.item.cancel') }) ] }) ] }) }) ] }); } // ─── AutoResponseTab ─────────────────────────────────────────────────────── function AutoResponseTab({ categories, locationTree, loaded, onLoad, settings, saving, saved, onSave, t, catLocale }) { const { useEffect: _ue, useState: _us } = { useEffect, useState }; const [enabled, setEnabled] = _us(false); const [minBudget, setMinBudget] = _us(''); const [maxBudget, setMaxBudget] = _us(''); const [defaultPrice, setDefaultPrice] = _us(''); const [defaultMessage, setDefaultMessage] = _us(''); const [maxPerDay, setMaxPerDay] = _us(''); const [selCategories, setSelCategories] = _us([]); const [selLocations, setSelLocations] = _us([]); _ue(()=>{ onLoad(); }, []); _ue(()=>{ if (!settings) return; setEnabled(settings.enabled); setMinBudget(settings.minBudget != null ? String(settings.minBudget) : ''); setMaxBudget(settings.maxBudget != null ? String(settings.maxBudget) : ''); setDefaultPrice(settings.defaultPrice != null ? String(settings.defaultPrice) : ''); setDefaultMessage(settings.defaultMessage ?? ''); setMaxPerDay(settings.maxAutoOffersPerDay != null ? String(settings.maxAutoOffersPerDay) : ''); setSelCategories(settings.categories ?? []); setSelLocations(settings.locations ?? []); }, [ settings ]); if (!loaded) return /*#__PURE__*/ _jsx("div", { className: "text-center py-10 text-white/60", children: t('common.loading') }); const flatLocations = []; function flatten(nodes) { for (const n of nodes){ flatLocations.push({ id: n.id, name: n.name }); if (n.children?.length) flatten(n.children); } } flatten(locationTree); return /*#__PURE__*/ _jsxs("div", { className: "space-y-4", children: [ /*#__PURE__*/ _jsx("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "font-medium text-gray-800", children: t('auto_response.title', 'Авто-ответ') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('auto_response.desc', 'Автоматически отвечать на подходящие задачи') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setEnabled((v)=>!v), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${enabled ? 'bg-blue-500' : 'bg-gray-300'}`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${enabled ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5 space-y-4", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-medium text-gray-800 text-sm", children: t('auto_response.budget_range', 'Бюджет задачи') }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.min_budget', 'Мин. €') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "0", value: minBudget, onChange: (e)=>setMinBudget(e.target.value), placeholder: "0", className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.max_budget', 'Макс. €') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "0", value: maxBudget, onChange: (e)=>setMaxBudget(e.target.value), placeholder: "∞", className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.default_price', 'Цена по умолчанию €') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "0", value: defaultPrice, onChange: (e)=>setDefaultPrice(e.target.value), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.max_per_day', 'Макс. авто-офертов/день') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "1", max: "50", value: maxPerDay, onChange: (e)=>setMaxPerDay(e.target.value), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.default_message', 'Текст авто-ответа') }), /*#__PURE__*/ _jsx("textarea", { value: defaultMessage, onChange: (e)=>setDefaultMessage(e.target.value), rows: 4, maxLength: 2000, placeholder: t('auto_response.message_placeholder', 'Здравствуйте! Я могу помочь с этой задачей...'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), categories.length > 0 && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-medium text-gray-800 text-sm mb-3", children: t('auto_response.categories', 'Категории задач') }), /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2 max-h-40 overflow-y-auto", children: categories.map((cat)=>{ const name = cat[`name_${catLocale}`] || cat.name_el || cat.name; const sel = selCategories.includes(cat.id); return /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setSelCategories(sel ? selCategories.filter((c)=>c !== cat.id) : [ ...selCategories, cat.id ]), className: `px-3 py-1.5 rounded-lg text-xs border transition ${sel ? 'bg-blue-600 border-blue-600 text-white' : 'bg-white border-gray-300 text-gray-700 hover:border-blue-400'}`, children: name }, cat.id); }) }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: saving, onClick: ()=>onSave({ enabled, minBudget: minBudget ? Number(minBudget) : null, maxBudget: maxBudget ? Number(maxBudget) : null, defaultPrice: defaultPrice ? Number(defaultPrice) : null, defaultMessage: defaultMessage || null, maxAutoOffersPerDay: maxPerDay ? Number(maxPerDay) : null, categories: selCategories.length > 0 ? selCategories : null, locations: selLocations.length > 0 ? selLocations : null }), className: "w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50", children: saving ? t('common.loading') : saved ? t('auto_response.saved', 'Сохранено ✓') : t('common.save') }) ] }); } export default function ProfilePage() { return /*#__PURE__*/ _jsx(Suspense, { fallback: null, children: /*#__PURE__*/ _jsx(ProfilePageInner, {}) }); } function ProfilePageInner() { const router = useRouter(); const searchParams = useSearchParams(); const { data: session, isPending } = useSession(); const { t, locale } = useLocale(); const validTabs = [ 'info', 'finance', 'cards', 'notifications', 'reviews', 'referral', 'auto_response', 'site' ]; const initialTab = searchParams.get('tab') ?? 'info'; const [activeTab, setActiveTab] = useState(validTabs.includes(initialTab) ? initialTab : 'info'); const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [saved, setSaved] = useState(false); const [error, setError] = useState(''); const [formData, setFormData] = useState({ firstName: '', lastName: '', phone: '', bio: '', locale: 'el' }); const [selectedLanguages, setSelectedLanguages] = useState([]); // Specialist cards const [cards, setCards] = useState([]); const [maxCards, setMaxCards] = useState(1); const [cardsLoading, setCardsLoading] = useState(false); const [openCardId, setOpenCardId] = useState(null); const [creatingCard, setCreatingCard] = useState(false); const [newCardTitle, setNewCardTitle] = useState(''); const [showNewCardForm, setShowNewCardForm] = useState(false); const [showUpgradeModal, setShowUpgradeModal] = useState(false); // Reference data const [categories, setCategories] = useState([]); const [locationTree, setLocationTree] = useState([]); // Become specialist const [becomingSpecialist, setBecomingSpecialist] = useState(false); const [avatarUploading, setAvatarUploading] = useState(false); const fileRef = useRef(null); // Notification preferences const [notifyNewTasks, setNotifyNewTasks] = useState(false); const [notifMessages, setNotifMessages] = useState(true); const [notifySaving, setNotifySaving] = useState(false); const [notifySaved, setNotifySaved] = useState(false); // Email verification resend const [resendState, setResendState] = useState('idle'); // Referral info const [referralCode, setReferralCode] = useState(null); const [referralCount, setReferralCount] = useState(0); const [referralCopied, setReferralCopied] = useState(false); const [referralLoaded, setReferralLoaded] = useState(false); // Balance top-up modal const [showTopUpModal, setShowTopUpModal] = useState(false); const [topUpAmount, setTopUpAmount] = useState(10); const [topUpLoading, setTopUpLoading] = useState(false); const [topUpError, setTopUpError] = useState(''); const [balanceHistory, setBalanceHistory] = useState([]); // Plan data + statuses const [dashData, setDashData] = useState(null); const [myStatuses, setMyStatuses] = useState([]); const [statusToggling, setStatusToggling] = useState(null); const [personalSiteSlug, setPersonalSiteSlug] = useState(''); const [slugSaving, setSlugSaving] = useState(false); const [slugSaved, setSlugSaved] = useState(false); const [slugCopied, setSlugCopied] = useState(false); const [slugError, setSlugError] = useState(''); const [showContactInfo, setShowContactInfo] = useState(false); const [siteSettings, setSiteSettings] = useState({}); const [siteSettingsSaving, setSiteSettingsSaving] = useState(false); const [siteStats, setSiteStats] = useState(null); const [siteStatsLoading, setSiteStatsLoading] = useState(false); const [autoResponse, setAutoResponse] = useState(null); const [arLoaded, setArLoaded] = useState(false); const [arSaving, setArSaving] = useState(false); const [arSaved, setArSaved] = useState(false); async function handleTopUp() { const amount = Number(topUpAmount); if (!amount || amount < 1) return; setTopUpLoading(true); setTopUpError(''); try { const { url, params } = await api.initiateTopUp(amount); // Build and auto-submit form to ePay const form = document.createElement('form'); form.method = 'POST'; form.action = url; Object.entries(params).forEach(([k, v])=>{ const input = document.createElement('input'); input.type = 'hidden'; input.name = k; input.value = v; form.appendChild(input); }); document.body.appendChild(form); form.submit(); } catch (e) { setTopUpError(e?.message || t('profile.balance.topup.error')); setTopUpLoading(false); } } async function handleResendVerification() { if (!user?.email || resendState !== 'idle') return; setResendState('sending'); const callbackURL = `${window.location.origin}/profile`; const result = await authClient.sendVerificationEmail({ email: user.email, callbackURL }); if (result?.error) { setResendState('idle'); } else { setResendState('sent'); } } process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (activeTab !== 'referral' || referralLoaded) return; api.getMyReferralInfo().then((r)=>{ setReferralCode(r.referralCode); setReferralCount(r.referralCount); }).catch(()=>{}).finally(()=>setReferralLoaded(true)); }, [ activeTab ]); // Reviews const [myReviews, setMyReviews] = useState(null); const [reviewsLoading, setReviewsLoading] = useState(false); const [myRating, setMyRating] = useState(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (activeTab !== 'reviews' || myReviews !== null || reviewsLoading) return; setReviewsLoading(true); api.getMyReviews().then(setMyReviews).catch(()=>setMyReviews([])).finally(()=>setReviewsLoading(false)); }, [ activeTab ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (activeTab !== 'site' || siteStats !== null || siteStatsLoading) return; setSiteStatsLoading(true); api.getSiteStats().then((res)=>setSiteStats(res.days)).catch(()=>setSiteStats([])).finally(()=>setSiteStatsLoading(false)); }, [ activeTab ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); }, [ session, isPending ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; Promise.all([ api.request('/users/me'), api.getCategories(), api.getLocations(), api.getMyDashboard().catch(()=>null), api.getMyStatuses().catch(()=>[]), api.getBalanceHistory(8).catch(()=>[]) ]).then(([u, cats, locs, dash, statusRes, history])=>{ setUser(u); setFormData({ firstName: u.firstName ?? '', lastName: u.lastName ?? '', phone: u.phone ?? '', bio: u.bio ?? '', locale: u.locale ?? 'el' }); setSelectedLanguages(u.languages ?? []); setNotifyNewTasks(u.notifyNewTasks ?? false); setNotifMessages(u.notifMessages ?? true); setCategories(cats); setLocationTree(locs); setDashData(dash); setMyStatuses((statusRes ?? []).filter((s)=>s.isActive).map((s)=>s.statusType)); setBalanceHistory(history); setPersonalSiteSlug(u.personalSiteSlug ?? ''); setShowContactInfo(u.showContactInfo ?? false); setSiteSettings(u.siteSettings ?? {}); if (u.role === 'specialist' || u.role === 'admin') { loadCards(); api.getUserRating(u.id).then((r)=>setMyRating(r.avg)).catch(()=>{}); } }).catch(()=>{}).finally(()=>setLoading(false)); }, [ session ]); async function loadCards() { setCardsLoading(true); try { const { cards: c, maxCards: m } = await api.getMySpecialistCards(); setCards(c); setMaxCards(m); } catch {} finally{ setCardsLoading(false); } } async function handleSubmit(e) { e.preventDefault(); setError(''); setSaving(true); try { const updated = await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ firstName: formData.firstName, lastName: formData.lastName, phone: formData.phone || undefined, bio: formData.bio || undefined, locale: formData.locale, languages: selectedLanguages, personalSiteSlug: personalSiteSlug || undefined, showContactInfo }) }); setUser(updated); setSaved(true); setTimeout(()=>setSaved(false), 2500); } catch (err) { setError(err.message || t('common.error')); } finally{ setSaving(false); } } async function handleBecomeSpecialist() { setBecomingSpecialist(true); setError(''); try { const updated = await api.request('/users/me/become-specialist', { method: 'POST' }); setUser(updated); setActiveTab('cards'); loadCards(); } catch (err) { setError(err.message || t('common.error')); } finally{ setBecomingSpecialist(false); } } async function handleSaveSiteSlug() { setSlugSaving(true); setSlugError(''); try { const updated = await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ personalSiteSlug: personalSiteSlug || null }) }); setUser(updated); setPersonalSiteSlug(updated.personalSiteSlug ?? ''); setSlugSaved(true); setTimeout(()=>setSlugSaved(false), 2500); } catch (err) { const code = err?.code ?? ''; if (code === 'SLUG_TAKEN' || err.message === 'This URL is already taken') { setSlugError(t('profile.site.slug_taken', 'Этот адрес уже занят')); } else { setSlugError(err.message || t('common.error')); } } finally{ setSlugSaving(false); } } async function handleSaveSiteSettings(newSettings) { setSiteSettings(newSettings); setSiteSettingsSaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ siteSettings: newSettings }) }); } catch {} finally{ setSiteSettingsSaving(false); } } async function handleAvatarChange(e) { const file = e.target.files?.[0]; if (!file) return; setAvatarUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); const fullUrl = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}${url}`; await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ image: fullUrl }) }); setUser((prev)=>({ ...prev, image: fullUrl })); } catch { setError(t('profile.upload.error')); } finally{ setAvatarUploading(false); } } async function handleCreateCard() { if (!newCardTitle.trim()) return; setCreatingCard(true); try { const card = await api.createSpecialistCard({ title: newCardTitle.trim() }); setCards((prev)=>[ ...prev, card ]); setOpenCardId(card.id); setNewCardTitle(''); setShowNewCardForm(false); } catch (err) { setError(err.message || t('common.error')); } finally{ setCreatingCard(false); } } async function handleDeleteCard(id) { if (!confirm(t('profile.cards.delete_confirm'))) return; try { await api.deleteSpecialistCard(id); setCards((prev)=>prev.filter((c)=>c.id !== id)); if (openCardId === id) setOpenCardId(null); } catch (err) { setError(err.message || t('common.error')); } } if (isPending || loading) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const dateLocale = locale === 'en' ? 'en-US' : locale === 'ru' ? 'ru-RU' : 'el-GR'; const isSpecialist = user?.role === 'specialist'; const isAdmin = user?.role === 'admin'; const showSpecialistTabs = isSpecialist || isAdmin; const initials = user ? `${user.firstName?.[0] ?? ''}${user.lastName?.[0] ?? ''}`.toUpperCase() : '?'; const hasAutoResponse = !!dashData?.features?.hasAutoResponse; const tabIcons = { info: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" }) }), finance: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 6v12m-3-2.818l.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.879 4.006 0l.415.33M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), cards: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M20.25 14.15v4.073a2.25 2.25 0 01-2.25 2.25h-12a2.25 2.25 0 01-2.25-2.25V6a2.25 2.25 0 012.25-2.25h4.073M15.75 3h5.25v5.25M15.75 3l-9 9" }) }), notifications: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), reviews: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.562.562 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.562.562 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" }) }), referral: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244" }) }), auto_response: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" }) }), site: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" }) }) }; const tabs = showSpecialistTabs ? [ { id: 'info', label: t('profile.tab.info') }, { id: 'finance', label: t('profile.tab.finance') }, { id: 'cards', label: t('profile.tab.cards') }, { id: 'notifications', label: t('profile.tab.notifications') }, { id: 'reviews', label: t('profile.tab.reviews') }, { id: 'referral', label: t('profile.tab.referral') }, ...hasAutoResponse ? [ { id: 'auto_response', label: t('profile.tab.auto_response', 'Авто-ответ') } ] : [], ...dashData?.features?.hasPersonalSite ? [ { id: 'site', label: t('profile.tab.site') } ] : [] ] : [ { id: 'info', label: t('profile.tab.info') }, { id: 'finance', label: t('profile.tab.finance') }, { id: 'notifications', label: t('profile.tab.notifications') }, { id: 'reviews', label: t('profile.tab.reviews') }, { id: 'referral', label: t('profile.tab.referral') }, ...dashData?.features?.hasPersonalSite ? [ { id: 'site', label: t('profile.tab.site') } ] : [] ]; return /*#__PURE__*/ _jsxs("div", { className: "max-w-4xl mx-auto px-4 py-8", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-4 mb-6", children: [ /*#__PURE__*/ _jsx("div", { className: "w-14 h-14 rounded-full flex-shrink-0 overflow-hidden border-2 border-white/40 flex items-center justify-center text-blue-700 text-xl font-bold bg-blue-100 cursor-pointer", onClick: ()=>{ setActiveTab('info'); fileRef.current?.click(); }, title: t('profile.photo.change'), children: user?.image ? /*#__PURE__*/ _jsx("img", { src: user.image, alt: user.name, className: "w-full h-full object-cover" }) : initials }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-xl font-bold text-white leading-tight", children: user?.firstName ? `${user.firstName} ${user.lastName ?? ''}`.trim() : user?.name ?? t('nav.profile') }), myRating && /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-1 mt-0.5", children: [ /*#__PURE__*/ _jsx("span", { className: "text-yellow-300", children: "★" }), /*#__PURE__*/ _jsx("span", { className: "font-semibold text-white text-sm", children: Number(myRating).toFixed(1) }), myReviews !== null && myReviews.length > 0 && /*#__PURE__*/ _jsxs("span", { className: "text-white/60 text-xs", children: [ "(", myReviews.length, ")" ] }) ] }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-6 items-start", children: [ tabs.length > 1 && /*#__PURE__*/ _jsx("aside", { className: "w-52 shrink-0 hidden sm:block", children: /*#__PURE__*/ _jsx("nav", { className: "rounded-2xl overflow-hidden bg-white/10 backdrop-blur-sm", children: tabs.map((tab)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setActiveTab(tab.id), className: `w-full text-left px-4 py-3 text-sm font-medium transition border-b border-white/10 last:border-0 flex items-center gap-3 ${activeTab === tab.id ? 'bg-white text-blue-700' : 'text-white/80 hover:bg-white/10 hover:text-white'}`, children: [ tabIcons[tab.id], /*#__PURE__*/ _jsx("span", { children: tab.label }) ] }, tab.id)) }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ tabs.length > 1 && /*#__PURE__*/ _jsx("div", { className: "flex sm:hidden bg-white/15 backdrop-blur rounded-xl p-1 mb-4 gap-1 overflow-x-auto", children: tabs.map((tab)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setActiveTab(tab.id), className: `flex-1 min-w-fit px-3 py-2 text-xs font-medium rounded-lg transition whitespace-nowrap flex flex-col items-center gap-0.5 ${activeTab === tab.id ? 'bg-white text-blue-700 shadow-sm' : 'text-white/80 hover:text-white hover:bg-white/10'}`, children: [ tabIcons[tab.id], /*#__PURE__*/ _jsx("span", { children: tab.label }) ] }, tab.id)) }), activeTab === 'cards' && /*#__PURE__*/ _jsxs("div", { className: "space-y-4", children: [ error && /*#__PURE__*/ _jsx("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between", children: [ /*#__PURE__*/ _jsxs("p", { className: "text-sm text-white/70", children: [ t('profile.cards.count'), ": ", cards.length, " / ", maxCards === null ? '∞' : maxCards ] }), /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>{ if (maxCards !== null && cards.length >= maxCards) { setShowUpgradeModal(true); } else { setShowNewCardForm(true); } }, className: "flex items-center gap-1.5 text-sm font-medium text-white hover:text-white/80", children: [ "+ ", t('profile.cards.add') ] }) ] }), showNewCardForm && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-blue-200 p-4 space-y-3", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('profile.cards.new_title') }), /*#__PURE__*/ _jsx("input", { value: newCardTitle, onChange: (e)=>setNewCardTitle(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') handleCreateCard(); }, maxLength: 200, placeholder: t('profile.cards.placeholder'), autoFocus: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: handleCreateCard, disabled: creatingCard || !newCardTitle.trim(), className: "px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium disabled:opacity-50", children: creatingCard ? '...' : t('profile.cards.create') }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>{ setShowNewCardForm(false); setNewCardTitle(''); }, className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg text-sm font-medium", children: t('profile.cards.cancel') }) ] }) ] }), cardsLoading && /*#__PURE__*/ _jsx("div", { className: "text-center py-10 text-white/70", children: t('common.loading') }), !cardsLoading && cards.length === 0 && !showNewCardForm && /*#__PURE__*/ _jsxs("div", { className: "text-center py-14 border-2 border-dashed border-white/30 rounded-xl", children: [ /*#__PURE__*/ _jsx("p", { className: "text-white/70 text-sm mb-3", children: t('profile.cards.empty') }), /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setShowNewCardForm(true), className: "text-sm text-white font-medium hover:underline", children: [ "+ ", t('profile.cards.create_first') ] }) ] }), cards.map((card)=>/*#__PURE__*/ _jsx(SpecialistCardEditor, { card: card, isOpen: openCardId === card.id, onToggle: ()=>setOpenCardId(openCardId === card.id ? null : card.id), onUpdate: (updated)=>setCards((prev)=>prev.map((c)=>c.id === updated.id ? updated : c)), onDelete: ()=>handleDeleteCard(card.id), categories: categories, locationTree: locationTree, catLocale: catLocale, locale: locale }, card.id)) ] }), activeTab === 'site' && /*#__PURE__*/ _jsxs("div", { className: "space-y-5", children: [ /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-4", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-1", children: t('profile.site.title') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400", children: t('profile.site_slug_hint') }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs font-medium text-gray-500 mb-1.5", children: t('profile.site.url_label') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [ /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-400 shrink-0", children: "canhelp.gr/site/" }), /*#__PURE__*/ _jsx("input", { value: personalSiteSlug, onChange: (e)=>setPersonalSiteSlug(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, '')), placeholder: "my-slug", maxLength: 50, className: "flex-1 min-w-32 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: handleSaveSiteSlug, disabled: slugSaving, className: "px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50", children: slugSaving ? t('profile.saving') : t('common.save') }), slugSaved && /*#__PURE__*/ _jsxs("span", { className: "text-sm text-green-600", children: [ "✓ ", t('profile.saved') ] }), personalSiteSlug && /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>{ navigator.clipboard.writeText(`${window.location.origin}/site/${personalSiteSlug}`); setSlugCopied(true); setTimeout(()=>setSlugCopied(false), 2000); }, className: "px-3 py-2 border border-gray-300 rounded-lg text-sm text-gray-600 hover:bg-gray-50 flex items-center gap-1.5", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }), slugCopied ? t('profile.site.copied') : t('profile.site.copy') ] }), /*#__PURE__*/ _jsxs("a", { href: `/site/${personalSiteSlug}`, target: "_blank", rel: "noopener noreferrer", className: "px-3 py-2 border border-blue-200 bg-blue-50 rounded-lg text-sm text-blue-600 hover:bg-blue-100 flex items-center gap-1.5", children: [ t('profile.site_open'), /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) }) ] }) ] }) ] }), slugError && /*#__PURE__*/ _jsx("p", { className: "text-xs text-red-500", children: slugError }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-4", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-800", children: t('profile.site.visible_title') }), siteSettingsSaving && /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400", children: t('profile.saving', 'Сохранение...') }) ] }), /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: [ { key: 'showBio', label: t('profile.site.visible.bio', 'Биография') }, { key: 'showRating', label: t('profile.site.visible.rating', 'Рейтинг и отзывы') }, { key: 'showReviews', label: t('profile.site.visible.reviews', 'Раздел с отзывами') }, { key: 'showServices', label: t('profile.site.visible.services', 'Карточки услуг') }, { key: 'showPortfolio', label: t('profile.site.visible.portfolio', 'Портфолио') }, { key: 'showPhone', label: t('profile.site.visible.contacts', 'Контактный телефон') }, { key: 'showFullLastName', label: t('profile.site.visible.full_last_name', 'Фамилия полностью') }, { key: 'showStatus', label: t('profile.site.visible.status', 'Статус «Готов помочь»') } ].map(({ key, label })=>{ const checked = siteSettings[key] !== false // undefined = true by default ; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-3 cursor-pointer group", children: [ /*#__PURE__*/ _jsx("div", { className: `w-5 h-5 rounded border-2 flex items-center justify-center transition shrink-0 ${checked ? 'bg-blue-600 border-blue-600' : 'bg-white border-gray-300 group-hover:border-blue-400'}`, onClick: ()=>{ const next = { ...siteSettings, [key]: !checked }; handleSaveSiteSettings(next); }, children: checked && /*#__PURE__*/ _jsx("svg", { className: "w-3 h-3 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 12.75l6 6 9-13.5" }) }) }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-700 select-none", onClick: ()=>{ const next = { ...siteSettings, [key]: !checked }; handleSaveSiteSettings(next); }, children: label }) ] }, key); }) }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-4", children: t('profile.site.edit_bio_hint', 'Имя и фото всегда отображаются') }), /*#__PURE__*/ _jsxs("div", { className: "mt-6 pt-4 border-t border-gray-100", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('profile.site.theme', 'Тема оформления') }), /*#__PURE__*/ _jsx("div", { className: "flex gap-3", children: [ { value: 'dark', label: t('profile.site.theme.dark', 'Тёмная'), icon: '🌙' }, { value: 'light', label: t('profile.site.theme.light', 'Светлая'), icon: '☀️' } ].map((opt)=>{ const selected = (siteSettings.siteTheme ?? 'dark') === opt.value; return /*#__PURE__*/ _jsxs("button", { onClick: ()=>handleSaveSiteSettings({ ...siteSettings, siteTheme: opt.value }), className: `flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border-2 text-sm font-medium transition ${selected ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-200 bg-white text-gray-500 hover:border-gray-300'}`, children: [ /*#__PURE__*/ _jsx("span", { children: opt.icon }), opt.label ] }, opt.value); }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("div", { className: "flex items-center justify-between mb-4", children: /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-800", children: t('profile.site.stats.title', 'Аналитика сайта') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.site.stats.days', 'последние 30 дней') }) ] }) }), !personalSiteSlug ? /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-400 py-4 text-center", children: t('profile.site.stats.no_slug', 'Укажите адрес сайта, чтобы видеть статистику') }) : siteStatsLoading || siteStats === null ? /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-400 py-4 text-center", children: t('profile.site.stats.loading', 'Загрузка аналитики...') }) : (()=>{ const totalViews = siteStats.reduce((s, d)=>s + d.views, 0); const totalUnique = siteStats.reduce((s, d)=>s + d.unique, 0); const totalMessages = siteStats.reduce((s, d)=>s + d.messages, 0); // Area chart helpers const days = siteStats.map((d)=>d.date); const seriesDef = [ { vals: siteStats.map((d)=>d.views), color: '#3b82f6', fill: '#3b82f615', label: t('profile.site.stats.views', 'Просмотры') }, { vals: siteStats.map((d)=>d.unique), color: '#8b5cf6', fill: '#8b5cf610', label: t('profile.site.stats.unique', 'Уникальные') }, { vals: siteStats.map((d)=>d.messages), color: '#10b981', fill: '#10b98110', label: t('profile.site.stats.messages', 'Сообщения') } ]; const maxVal = Math.max(...seriesDef.flatMap((s)=>s.vals), 1); const W = 580; const H = 160; const padL = 36; const padB = 22; const chartW = W - padL - 4; const chartH = H - padB; const stepX = chartW / (days.length - 1); function pts(vals) { return vals.map((v, i)=>[ padL + i * stepX, chartH - v / maxVal * chartH ]); } function smoothPath(points) { if (points.length < 2) return ''; let d = `M ${points[0][0].toFixed(1)} ${points[0][1].toFixed(1)}`; for(let i = 1; i < points.length; i++){ const cpx = ((points[i - 1][0] + points[i][0]) / 2).toFixed(1); d += ` C ${cpx} ${points[i - 1][1].toFixed(1)} ${cpx} ${points[i][1].toFixed(1)} ${points[i][0].toFixed(1)} ${points[i][1].toFixed(1)}`; } return d; } function areaPath(vals) { const points = pts(vals); const line = smoothPath(points); if (!line) return ''; const lastX = points[points.length - 1][0].toFixed(1); return `${line} L ${lastX} ${chartH.toFixed(1)} L ${padL.toFixed(1)} ${chartH.toFixed(1)} Z`; } function fmtY(v) { return v >= 1000 ? `${Math.round(v / 1000)}K` : String(v); } const yTicks = [ 0, Math.round(maxVal / 3), Math.round(maxVal * 2 / 3), maxVal ]; const xTicks = days.map((d, i)=>({ i, label: d.slice(8) })).filter((_, i)=>i % 7 === 0 || i === days.length - 1); return /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-3 gap-3 mb-5", children: [ { label: t('profile.site.stats.total_views', 'Просмотры'), value: totalViews, color: 'text-blue-600', bg: 'bg-blue-50' }, { label: t('profile.site.stats.total_unique', 'Уник. посетители'), value: totalUnique, color: 'text-violet-600', bg: 'bg-violet-50' }, { label: t('profile.site.stats.total_messages', 'Сообщения'), value: totalMessages, color: 'text-emerald-600', bg: 'bg-emerald-50' } ].map((card)=>/*#__PURE__*/ _jsxs("div", { className: `${card.bg} rounded-xl p-3 text-center`, children: [ /*#__PURE__*/ _jsx("div", { className: `text-2xl font-bold ${card.color}`, children: card.value }), /*#__PURE__*/ _jsx("div", { className: "text-xs text-gray-500 mt-0.5", children: card.label }) ] }, card.label)) }), /*#__PURE__*/ _jsx("div", { className: "flex items-center gap-4 mb-2", children: seriesDef.map((s)=>/*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5 text-xs text-gray-500", children: [ /*#__PURE__*/ _jsx("span", { className: "w-3 h-0.5 inline-block rounded", style: { background: s.color } }), s.label ] }, s.label)) }), /*#__PURE__*/ _jsx("div", { className: "overflow-x-auto", children: /*#__PURE__*/ _jsxs("svg", { viewBox: `0 0 ${W} ${H + 12}`, className: "w-full", style: { minWidth: 320 }, children: [ yTicks.map((v)=>{ const y = chartH - v / maxVal * chartH; return /*#__PURE__*/ _jsxs("g", { children: [ /*#__PURE__*/ _jsx("line", { x1: padL, y1: y, x2: W - 4, y2: y, stroke: "#f3f4f6", strokeWidth: 1 }), /*#__PURE__*/ _jsx("text", { x: padL - 5, y: y + 3.5, textAnchor: "end", fontSize: 9, fill: "#9ca3af", children: fmtY(v) }) ] }, v); }), xTicks.map(({ i })=>/*#__PURE__*/ _jsx("line", { x1: padL + i * stepX, y1: 0, x2: padL + i * stepX, y2: chartH, stroke: "#f9fafb", strokeWidth: 1 }, `vg-${i}`)), xTicks.map(({ i, label })=>/*#__PURE__*/ _jsx("text", { x: padL + i * stepX, y: H + 10, textAnchor: "middle", fontSize: 9, fill: "#9ca3af", children: label }, i)), seriesDef.map((s, si)=>/*#__PURE__*/ _jsx("path", { d: areaPath(s.vals), fill: s.fill }, `fill-${si}`)), seriesDef.map((s, si)=>/*#__PURE__*/ _jsx("path", { d: smoothPath(pts(s.vals)), fill: "none", stroke: s.color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }, `line-${si}`)), seriesDef.map((s, si)=>{ const points = pts(s.vals); const last = points[points.length - 1]; return /*#__PURE__*/ _jsx("circle", { cx: last[0], cy: last[1], r: 4, fill: "white", stroke: s.color, strokeWidth: 2 }, `dot-${si}`); }), /*#__PURE__*/ _jsx("line", { x1: padL, y1: chartH, x2: W - 4, y2: chartH, stroke: "#e5e7eb", strokeWidth: 1 }) ] }) }) ] }); })() ] }) ] }), activeTab === 'reviews' && /*#__PURE__*/ _jsx("div", { className: "space-y-4", children: myReviews === null ? /*#__PURE__*/ _jsx("div", { className: "text-center py-10 text-white/70", children: t('common.loading') }) : myReviews.length === 0 ? /*#__PURE__*/ _jsxs("div", { className: "text-center py-20 text-white/60", children: [ /*#__PURE__*/ _jsx("p", { className: "text-4xl mb-3", children: "⭐" }), /*#__PURE__*/ _jsx("p", { children: t('profile.no_reviews') }) ] }) : myReviews.map(({ review, author })=>/*#__PURE__*/ _jsx("div", { className: "bg-white rounded-xl border border-gray-200 p-4", children: /*#__PURE__*/ _jsxs("div", { className: "flex items-start gap-3", children: [ /*#__PURE__*/ _jsx("div", { className: "w-9 h-9 rounded-full bg-gray-100 flex-shrink-0 flex items-center justify-center text-gray-600 text-sm font-bold overflow-hidden", children: author?.image ? /*#__PURE__*/ _jsx("img", { src: author.image, alt: author.name, className: "w-full h-full object-cover" }) : author?.name?.[0]?.toUpperCase() ?? '?' }), /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-1", children: [ /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-800", children: author?.name ?? '—' }), /*#__PURE__*/ _jsxs("span", { className: "text-yellow-400", children: [ '★'.repeat(review.rating), '☆'.repeat(5 - review.rating) ] }) ] }), review.comment && /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-600", children: review.comment }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-1", children: new Date(review.createdAt).toLocaleDateString() }) ] }) ] }) }, review.id)) }), activeTab === 'finance' && /*#__PURE__*/ _jsxs("div", { className: "space-y-5", children: [ /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-3", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('profile.balance') }), /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setTopUpAmount(10); setTopUpError(''); setShowTopUpModal(true); }, className: "flex items-center gap-1.5 text-sm font-medium text-blue-600 hover:text-blue-700 hover:bg-blue-50 px-3 py-1.5 rounded-lg transition-colors", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('profile.balance.topup') ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 p-4 bg-green-50 rounded-xl border border-green-100", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-6 h-6 text-green-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), /*#__PURE__*/ _jsxs("span", { className: "text-xl font-bold text-green-700", children: [ parseFloat(user?.balance ?? '0').toFixed(2), " EUR" ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-2", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-sm font-semibold text-gray-800", children: t('profile.balance.history', 'Архив операций') }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400", children: t('profile.balance.history.last', 'Последние операции') }) ] }), balanceHistory.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "rounded-xl border border-dashed border-gray-200 px-4 py-6 text-sm text-gray-400 text-center", children: t('profile.balance.history.empty', 'Операций пока нет') }) : /*#__PURE__*/ _jsx("div", { className: "space-y-2", children: balanceHistory.map((entry)=>{ const isCredit = entry.direction === 'credit'; const amount = Number(entry.amount).toFixed(2); const badgeClass = isCredit ? 'bg-emerald-50 text-emerald-700 border-emerald-100' : 'bg-rose-50 text-rose-700 border-rose-100'; const title = entry.kind === 'topup' ? t('profile.balance.history.kind.topup', 'Пополнение баланса') : entry.kind === 'plan_purchase' ? t('profile.balance.history.kind.plan_purchase', 'Списание за тариф') : entry.kind === 'admin_topup' ? t('profile.balance.history.kind.admin_topup', 'Пополнение администратором') : t('profile.balance.history.kind.admin_adjustment', 'Корректировка администратором'); return /*#__PURE__*/ _jsxs("div", { className: "rounded-xl border border-gray-200 px-4 py-3", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-start justify-between gap-3", children: [ /*#__PURE__*/ _jsxs("div", { className: "min-w-0", children: [ /*#__PURE__*/ _jsx("div", { className: "text-sm font-medium text-gray-900", children: entry.description || title }), /*#__PURE__*/ _jsx("div", { className: "text-xs text-gray-500 mt-1", children: new Date(entry.createdAt).toLocaleString(dateLocale) }) ] }), /*#__PURE__*/ _jsxs("div", { className: `shrink-0 rounded-full border px-2.5 py-1 text-xs font-semibold ${badgeClass}`, children: [ isCredit ? '+' : '-', amount, " ", entry.currency ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-2 text-xs text-gray-500", children: [ t('profile.balance.history.balance_after', 'Баланс после'), ": ", Number(entry.balanceAfter).toFixed(2), " ", entry.currency ] }) ] }, entry.id); }) }) ] }) ] }), showTopUpModal && /*#__PURE__*/ _jsx("div", { className: "fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-black/40 backdrop-blur-sm", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl shadow-2xl w-full max-w-sm p-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-5", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-gray-900", children: t('profile.balance.topup.title') }), /*#__PURE__*/ _jsx("button", { onClick: ()=>setShowTopUpModal(false), className: "text-gray-400 hover:text-gray-600", children: /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }) ] }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500 mb-3", children: t('profile.balance.topup.hint') }), /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-4 gap-2 mb-4", children: [ 5, 10, 20, 50 ].map((v)=>/*#__PURE__*/ _jsxs("button", { onClick: ()=>setTopUpAmount(v), className: `py-2 rounded-xl text-sm font-semibold border transition-colors ${Number(topUpAmount) === v ? 'bg-blue-600 text-white border-blue-600' : 'border-gray-200 text-gray-700 hover:border-blue-400'}`, children: [ "€", v ] }, v)) }), /*#__PURE__*/ _jsxs("div", { className: "mb-5", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.balance.topup.amount') }), /*#__PURE__*/ _jsxs("div", { className: "relative", children: [ /*#__PURE__*/ _jsx("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm", children: "€" }), /*#__PURE__*/ _jsx("input", { type: "number", min: "1", max: "9999", step: "1", value: topUpAmount, onChange: (e)=>setTopUpAmount(e.target.value), className: "w-full pl-7 pr-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), topUpError && /*#__PURE__*/ _jsx("p", { className: "text-sm text-red-600 mb-3", children: topUpError }), /*#__PURE__*/ _jsx("button", { onClick: handleTopUp, disabled: topUpLoading || !Number(topUpAmount) || Number(topUpAmount) < 1, className: "w-full py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed text-white font-semibold rounded-xl transition-colors flex items-center justify-center gap-2", children: topUpLoading ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 animate-spin", fill: "none", viewBox: "0 0 24 24", children: [ /*#__PURE__*/ _jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /*#__PURE__*/ _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v8z" }) ] }), t('profile.balance.topup.loading') ] }) : t('profile.balance.topup.submit') }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-3", children: t('profile.plan.title') }), user?.plan ? /*#__PURE__*/ _jsxs("div", { className: "flex items-start gap-3 p-4 bg-blue-50 rounded-xl border border-blue-100", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-6 h-6 text-blue-500 shrink-0 mt-0.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-900", children: user.plan.name }), user.plan.description && /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: user.plan.description }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-3 mt-2 text-xs text-gray-500", children: [ /*#__PURE__*/ _jsxs("span", { className: "font-medium text-blue-700", children: [ user.plan.price, " ", user.plan.currency ] }), user.plan.maxCards != null ? /*#__PURE__*/ _jsxs("span", { children: [ t('profile.plan.cards_up_to'), " ", user.plan.maxCards ] }) : /*#__PURE__*/ _jsx("span", { children: t('profile.plan.cards_unlimited') }), user.plan.maxTasks != null && /*#__PURE__*/ _jsxs("span", { children: [ t('profile.plan.tasks_up_to'), " ", user.plan.maxTasks ] }), user.plan.maxOffers != null && /*#__PURE__*/ _jsxs("span", { children: [ t('profile.plan.offers_up_to'), " ", user.plan.maxOffers ] }), /*#__PURE__*/ _jsx("span", { className: user.planExpiresAt && new Date(user.planExpiresAt) < new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) ? 'text-red-500 font-medium' : '', children: user.planExpiresAt ? `${t('profile.plan.valid_until')} ${new Date(user.planExpiresAt).toLocaleDateString()}` : t('profile.plan.no_expiry') }) ] }), (user.plan.features ?? []).length > 0 && /*#__PURE__*/ _jsx("ul", { className: "mt-2 space-y-0.5", children: user.plan.features.map((f, i)=>/*#__PURE__*/ _jsxs("li", { className: "text-xs text-gray-600 flex items-center gap-1.5", children: [ /*#__PURE__*/ _jsx("span", { className: "text-green-500", children: "✓" }), " ", f ] }, i)) }) ] }) ] }) : /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 p-4 bg-gray-50 rounded-xl border border-gray-100", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-700", children: t('profile.plan.basic') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.plan.contact_upgrade') }) ] }) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "text-center", children: /*#__PURE__*/ _jsxs("a", { href: "/pricing", className: "inline-flex items-center gap-1.5 text-sm font-medium text-white/70 hover:text-white transition", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 7l5 5m0 0l-5 5m5-5H6" }) }), t('pricing.title', 'Тарифы') ] }) }) ] }), activeTab !== 'cards' && activeTab !== 'reviews' && activeTab !== 'finance' && activeTab !== 'site' && /*#__PURE__*/ _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [ error && /*#__PURE__*/ _jsx("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), saved && /*#__PURE__*/ _jsxs("div", { className: "bg-green-50 text-green-700 p-3 rounded-lg text-sm", children: [ "✓ ", t('profile.saved') ] }), activeTab === 'notifications' && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('notifications.title') }), notifySaved && /*#__PURE__*/ _jsxs("div", { className: "bg-green-50 text-green-700 p-3 rounded-lg text-sm", children: [ "✓ ", t('notifications.saved') ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-start justify-between gap-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsx("p", { className: "font-medium text-gray-800 text-sm", children: t('chat.notif_messages') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: t('notifications.messages.desc') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: notifySaving, onClick: async ()=>{ const next = !notifMessages; setNotifMessages(next); setNotifySaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ notifMessages: next }) }); setNotifySaved(true); setTimeout(()=>setNotifySaved(false), 2500); } catch { setNotifMessages(!next); } finally{ setNotifySaving(false); } }, className: `relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 ${notifMessages ? 'bg-blue-600' : 'bg-gray-200'}`, role: "switch", "aria-checked": notifMessages, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notifMessages ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }), showSpecialistTabs && /*#__PURE__*/ _jsxs("div", { className: `flex items-start justify-between gap-4 ${!user?.plan?.notifyNewTasks ? 'opacity-60' : ''}`, children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsx("p", { className: "font-medium text-gray-800 text-sm", children: t('notifications.email.new_tasks') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: t('notifications.email.new_tasks.desc') }), !user?.plan?.notifyNewTasks && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-amber-600 mt-1", children: [ "\uD83D\uDD12 ", t('notifications.plan_required') ] }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: notifySaving || !user?.plan?.notifyNewTasks, onClick: async ()=>{ const next = !notifyNewTasks; setNotifyNewTasks(next); setNotifySaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ notifyNewTasks: next }) }); setNotifySaved(true); setTimeout(()=>setNotifySaved(false), 2500); } catch { setNotifyNewTasks(!next); } finally{ setNotifySaving(false); } }, className: `relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 ${notifyNewTasks ? 'bg-blue-600' : 'bg-gray-200'}`, role: "switch", "aria-checked": notifyNewTasks, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notifyNewTasks ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }), activeTab === 'referral' && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-5", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('profile.referral.title') }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500", children: t('profile.referral.desc') }), !referralLoaded ? /*#__PURE__*/ _jsx("div", { className: "text-sm text-gray-400", children: t('common.loading') }) : referralCode ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs font-medium text-gray-500 mb-1.5", children: t('profile.referral.link_label') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ _jsx("input", { readOnly: true, value: `${"undefined" !== 'undefined' ? window.location.origin : ''}/register?ref=${referralCode}`, className: "flex-1 text-sm border border-gray-200 rounded-lg px-3 py-2 bg-gray-50 text-gray-700 focus:outline-none" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>{ navigator.clipboard.writeText(`${window.location.origin}/register?ref=${referralCode}`); setReferralCopied(true); setTimeout(()=>setReferralCopied(false), 2000); }, className: "px-3 py-2 rounded-lg border border-gray-200 text-sm font-medium hover:bg-gray-50 transition whitespace-nowrap", children: referralCopied ? t('profile.referral.copied') : t('profile.referral.copy') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 p-4 bg-blue-50 rounded-xl", children: [ /*#__PURE__*/ _jsx("div", { className: "text-2xl font-bold text-blue-700", children: referralCount }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-blue-700", children: t('profile.referral.invited_count') }) ] }) ] }) : /*#__PURE__*/ _jsx("div", { className: "text-sm text-gray-400", children: t('profile.referral.no_code') }) ] }), activeTab === 'auto_response' && /*#__PURE__*/ _jsx(AutoResponseTab, { categories: categories, locationTree: locationTree, loaded: arLoaded, onLoad: ()=>{ if (arLoaded) return; api.getAutoResponseSettings().then((s)=>{ setAutoResponse(s); setArLoaded(true); }).catch(()=>setArLoaded(true)); }, settings: autoResponse, saving: arSaving, saved: arSaved, onSave: async (data)=>{ setArSaving(true); setArSaved(false); try { const updated = await api.updateAutoResponseSettings(data); setAutoResponse(updated); setArSaved(true); setTimeout(()=>setArSaved(false), 2500); } catch {} finally{ setArSaving(false); } }, t: t, catLocale: catLocale }), activeTab === 'info' && /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-4", children: t('profile.photo') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-5", children: [ /*#__PURE__*/ _jsxs("div", { className: "relative", children: [ user?.image ? /*#__PURE__*/ _jsx("img", { src: user.image, alt: user.name, className: "w-20 h-20 rounded-full object-cover border-2 border-gray-200" }) : /*#__PURE__*/ _jsx("div", { className: "w-20 h-20 rounded-full bg-blue-100 flex items-center justify-center text-blue-700 text-2xl font-bold border-2 border-gray-200", children: initials }), avatarUploading && /*#__PURE__*/ _jsx("div", { className: "absolute inset-0 rounded-full bg-black/40 flex items-center justify-center", children: /*#__PURE__*/ _jsx("div", { className: "w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" }) }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>fileRef.current?.click(), disabled: avatarUploading, className: "bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg text-sm font-medium disabled:opacity-50", children: t('profile.photo.change') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('profile.photo.hint') }), /*#__PURE__*/ _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handleAvatarChange }) ] }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-4", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('profile.basic_info') }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('register.first_name') }), /*#__PURE__*/ _jsx("input", { value: formData.firstName, onChange: (e)=>setFormData({ ...formData, firstName: e.target.value }), required: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('register.last_name') }), /*#__PURE__*/ _jsx("input", { value: formData.lastName, onChange: (e)=>setFormData({ ...formData, lastName: e.target.value }), required: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: "Email" }), /*#__PURE__*/ _jsx("input", { value: user?.email, disabled: true, className: "w-full border border-gray-200 rounded-lg px-3 py-2 text-sm text-gray-400 bg-gray-50 cursor-not-allowed" }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mt-1.5", children: [ user?.emailVerified ? /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1 text-xs text-green-600", children: [ /*#__PURE__*/ _jsx("span", { className: "inline-block w-1.5 h-1.5 rounded-full bg-green-500" }), t('profile.email.verified') ] }) : /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1 text-xs text-amber-600", children: [ /*#__PURE__*/ _jsx("span", { className: "inline-block w-1.5 h-1.5 rounded-full bg-amber-500" }), t('profile.email.not_verified') ] }), !user?.emailVerified && /*#__PURE__*/ _jsx("button", { type: "button", disabled: resendState !== 'idle', onClick: handleResendVerification, className: "text-xs text-blue-600 hover:underline disabled:opacity-60 disabled:no-underline", children: resendState === 'sending' ? t('login.unverified.sending') : resendState === 'sent' ? t('login.unverified.sent') : t('login.unverified.resend') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.phone') }), /*#__PURE__*/ _jsx("input", { type: "tel", value: formData.phone, onChange: (e)=>setFormData({ ...formData, phone: e.target.value }), placeholder: t('profile.phone.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.bio') }), /*#__PURE__*/ _jsx("textarea", { value: formData.bio, onChange: (e)=>setFormData({ ...formData, bio: e.target.value }), rows: 3, maxLength: 1000, placeholder: t('profile.bio.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm resize-none" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.language') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mb-2", children: t('profile.language.hint') }), /*#__PURE__*/ _jsxs("select", { value: formData.locale, onChange: (e)=>setFormData({ ...formData, locale: e.target.value }), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400", children: [ /*#__PURE__*/ _jsx("option", { value: "el", children: "Ελληνικά" }), /*#__PURE__*/ _jsx("option", { value: "en", children: "English" }), /*#__PURE__*/ _jsx("option", { value: "ru", children: "Русский" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.languages') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mb-2", children: t('profile.languages.hint') }), /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2", children: [ { code: 'el', flag: '🇬🇷', label: 'Ελληνικά' }, { code: 'en', flag: '🇬🇧', label: 'English' }, { code: 'ru', flag: '🇷🇺', label: 'Русский' }, { code: 'uk', flag: '🇺🇦', label: 'Українська' }, { code: 'de', flag: '🇩🇪', label: 'Deutsch' }, { code: 'fr', flag: '🇫🇷', label: 'Français' }, { code: 'it', flag: '🇮🇹', label: 'Italiano' }, { code: 'es', flag: '🇪🇸', label: 'Español' }, { code: 'ar', flag: '🇸🇦', label: 'العربية' }, { code: 'zh', flag: '🇨🇳', label: '中文' } ].map(({ code, flag, label })=>{ const selected = selectedLanguages.includes(code); return /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setSelectedLanguages(selected ? selectedLanguages.filter((l)=>l !== code) : [ ...selectedLanguages, code ]), className: `flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm border transition ${selected ? 'bg-blue-600 border-blue-600 text-white' : 'bg-white border-gray-300 text-gray-700 hover:border-blue-400'}`, children: [ /*#__PURE__*/ _jsx("span", { children: flag }), /*#__PURE__*/ _jsx("span", { children: label }) ] }, code); }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-3", children: t('profile.role') }), /*#__PURE__*/ _jsx("div", { className: `inline-flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium ${isSpecialist ? 'bg-purple-100 text-purple-700' : isAdmin ? 'bg-red-100 text-red-700' : 'bg-gray-100 text-gray-600'}`, children: isSpecialist ? t('profile.role.specialist') : isAdmin ? t('profile.role.admin') : t('profile.role.customer') }), !isSpecialist && !isAdmin && /*#__PURE__*/ _jsxs("div", { className: "mt-4 p-4 bg-purple-50 rounded-xl", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-600 mb-3", children: t('profile.become_specialist.desc') }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: handleBecomeSpecialist, disabled: becomingSpecialist, className: "bg-purple-600 hover:bg-purple-700 text-white px-5 py-2 rounded-lg text-sm font-semibold disabled:opacity-50", children: becomingSpecialist ? t('common.loading') : t('profile.become_specialist') }) ] }) ] }), (isSpecialist ? dashData?.features?.hasCanHelpNowStatus : dashData?.features?.hasNeedHelpStatus) && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-4", children: t('status.title', 'Статус') }), isSpecialist && /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('status.can_help_now', 'Готов помочь сейчас') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('status.can_help_now_hint', 'Ваша карточка показывается вверху') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: statusToggling === 'canhelp_now', onClick: async ()=>{ setStatusToggling('canhelp_now'); const nextActive = !myStatuses.includes('canhelp_now'); try { const res = await api.toggleStatus('canhelp_now', nextActive); setMyStatuses((prev)=>res.isActive ? [ ...prev.filter((s)=>s !== 'canhelp_now'), 'canhelp_now' ] : prev.filter((s)=>s !== 'canhelp_now')); } catch {} finally{ setStatusToggling(null); } }, className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${myStatuses.includes('canhelp_now') ? 'bg-green-500' : 'bg-gray-300'} disabled:opacity-50`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${myStatuses.includes('canhelp_now') ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }), !isSpecialist && !isAdmin && /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('status.need_help', 'Нужна помощь') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('status.need_help_hint', 'Специалисты смогут вам предложить помощь') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: statusToggling === 'need_help', onClick: async ()=>{ setStatusToggling('need_help'); const nextActive = !myStatuses.includes('need_help'); try { const res = await api.toggleStatus('need_help', nextActive); setMyStatuses((prev)=>res.isActive ? [ ...prev.filter((s)=>s !== 'need_help'), 'need_help' ] : prev.filter((s)=>s !== 'need_help')); } catch {} finally{ setStatusToggling(null); } }, className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${myStatuses.includes('need_help') ? 'bg-blue-500' : 'bg-gray-300'} disabled:opacity-50`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${myStatuses.includes('need_help') ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }), isSpecialist && (dashData?.plan?.tier === 'pro' || dashData?.plan?.tier === 'ultimate') && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-4", children: t('profile.show_contact', 'Показывать контакты') }), /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('profile.show_contact_hint', 'Клиенты видят ваш телефон') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.show_contact_desc', 'Позволяет клиентам связаться напрямую') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setShowContactInfo((v)=>!v), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${showContactInfo ? 'bg-blue-500' : 'bg-gray-300'}`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${showContactInfo ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }) ] }), /*#__PURE__*/ _jsx("button", { type: "submit", disabled: saving, className: `w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed ${activeTab === 'notifications' || activeTab === 'referral' || activeTab === 'auto_response' ? 'hidden' : ''}`, children: saving ? t('profile.saving') : t('common.save') }) ] }), showUpgradeModal && /*#__PURE__*/ _jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl shadow-xl p-6 w-full max-w-md", children: [ /*#__PURE__*/ _jsx("div", { className: "text-center mb-5", children: /*#__PURE__*/ _jsx("span", { className: "text-5xl", children: "\uD83D\uDE80" }) }), /*#__PURE__*/ _jsx("h2", { className: "text-lg font-bold text-gray-900 text-center mb-2", children: t('profile.upgrade.cards_limit') }), /*#__PURE__*/ _jsxs("p", { className: "text-sm text-gray-600 text-center mb-4", children: [ user?.plan?.name ?? t('profile.plan.basic'), " — ", t('profile.plan.cards_up_to'), " ", maxCards ] }), user?.plan && /*#__PURE__*/ _jsxs("div", { className: "bg-gray-50 rounded-xl p-4 mb-5 text-sm text-gray-600 text-center", children: [ /*#__PURE__*/ _jsx("span", { className: "font-medium text-gray-800", children: t('profile.upgrade.plan') }), ' ', user.plan.name, " — ", user.plan.price, " ", user.plan.currency ] }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 text-center mb-5", children: t('profile.upgrade.contact') }), /*#__PURE__*/ _jsx("button", { onClick: ()=>setShowUpgradeModal(false), className: "w-full bg-blue-600 hover:bg-blue-700 text-white py-2.5 rounded-xl text-sm font-semibold", children: t('profile.upgrade.ok') }) ] }) }) ] }) ] }) ] }); } `   /opt/canhelp/apps/web/src/app/profile. f  /hijkl14cdb12c1efe2f87 01  u SpecialistCardEditorAutoResponseTabProfilePageInnertProfilePage EyB/opt/canhelp/apps/web/src/app/profile/page.tsx w!~(yB~(yB3f6aa2a134aeb787 ` d `=@ a=@ A `> A `= AE `4 AFs `- At `!Q A ci'iF0 A ci'ia A! A @@J A + @=`'@=`F0 A/F @=`'@=`aF ASr @D`@D`>0 Av @D`@D`Y false Ax @> `RA> 0 A @> `pA>  @8oo a=@)) `>** `=,, `4-- `-pp `! ED A%.   w'' b ED AT\   b" * A@ A   b ( =< A   c " * 98 A   c ( 0 54 A.6     c & . 10 Az   c*2 -, A   c(0 )( A   c2: %$ APX   c08 !  A   c*2  A   c,4  A   c&.  Aks   c8@  A   c*2    A   c&.   A   c$, &% A9?   c# /. A~   c7@ dapi A  A   c [ A:R  A:=   c%"%: V A   A    c::* M A  A   @`@`) G A  A     @`@`6 12 A    @`@` -. A   @`@` )* AAF   @`"@`' +, ACG   @`*@`. '( A8<   @`*@`. #$ A;?   @`"@`&   A   @`0@`4  A  } @`"@`&  A "   y @`$@`)  Aj n   u @`"@`&  A!#!  q @`B@`F  A&#+#  m @`"@`'  A##  i @`@@`E  Ah$l$  e @`2@`6  A&&  a @`2@`6  AL)Q)  ] @`B@`G  A **  Y @`L@`P  A**  U @`U@`Z  A,,  Q @`B@`F  A..  M @`2@`7  AP/T/  I @`:@`>  A33  E @`:@`>  A85<5  A @`M@`Q  As6x6  = C  A99  9 @)`F@)`J  AV;[;  5 @/`9@/`>  A;;  1 @1`:@1`?  A<<  - @4`B@4`F  A>>  ) @:`B@:`G  A@ @  % @=`V@=`Z  AdBhB  ! @F`Q@F`U  ACC   @J`I@J`N  ADD   @M`J@M`N  A4G8G  {{ @S`J@S`N  AII  ww @_`E@_`I  AKK   ss @e`9@e`>  AELJL   oo @g`:@g`?  A;M?M  kk @j`B@j`F  AkOoO  gg @p`B@p`F  AQQ  cc @v`R@v`V  ARR  __ @z`I@z`N  ASS  [[ @}`J@}`N  AUU  WW @`J@`N  AXX  SS @`E@`J  AWY\Y  OO @`K@`P  AYY  KK @`:@`> yz A[[  GG @`]@`b  A[[ 4CC @`c@`l wx A\\  ?? @`F@`J mn A9^>^  ;; @`C@`H A?^H^ 488 @`I@`R lm A_`  44 @`:@`> hi AMbQb  00 @`K@`O de Aqcuc  ,, @`7@`; Z[ A1d6d  (( @`V@`[ \] AHeLe  $$ @`B@`F RS Aff     @`B@`G TU Ahh   @`J@`N JK Ajj   @`J@`O LM Aoo   @`P@`T HI Arpvp   @`P@`T >? Arr     @`E@`J @A Ass   @`2@`6 67 Auu   @`=@`B 89 Aww   @`)@`- ./ Amxrx   @`(@`- 01 Ayy   @`&@`* ,- Ayy   @`&@`* "# Azz   @`&@`+  A{{   @ `.@ `3  ! A{|   @ `6@ `:  A+}/}  ~ @`6@`:  AY^  z @`.@`3  A  v @`6@`:  A  r @`6@`:  A  n @(`&@(`+   A:>  j @+`.@+`2  A  f @1`.@1`2  A     @B@B`  A   ~~ @C@C`  A   @]`&@]`*  A@E   @l`@l`  A   @o`@o`  A %   @q`(@q`-  Aʐϐ   @t`&@t`+  A/3   @v`.@v`2  A.2   @z`.@z`2  A   @`&@`*  AϔӔ   @`4@`8  A   @`@`  A   @`"@`&  A   @`"@`'  A8=   @`*@`/  A   @`2@`6  Aę   @`2@`6  A:?   @`*@`/  A   @`2@`6  AÝǝ  {{ @`2@`6  Afk  ww @`"@`'  AàǠ  ss @`*@`.  AΡҡ  oo @`*@`.  Ạѣ  kk @`"@`'  A)-  gg @`*@`.  A6:  cc @`*@`.  Arw  __ @`@`  A   [[ @`"@`&  A  WW @`"@`&  AW\  SS @`3@`8  A  OO @`"@`&  Aجܬ  KK @`"@`&  AKO  GG @`1@`5 {| A$(  {CC @`@`S @@ vw ASW   O== @`@`  AX` 4 @`@`& mn A  55 @` @`$  A   B @`@`  A'   @`@`(  AT^   @`)@`3  A|   @`@`#  A   @+`&@+`.  A   @,`@,`$  A2:   @-`"@-`*  Abj   @.` @.`(  A   @/`@/`&  Aȸ   @0`@0`&  A   @1`$@1`,  A   @8`6@8`>  A   @:`@:`&  A   @;`$@;`,  APX   @<`,@<`4  A   @=`(@=`0  Aźͺ   @>`,@>`4  A    @?`,@?`4  ABJ   @@`2@@`:  A   @A`4@A`<  Aֻ޻   @C`(@C`0  A   @D`,@D`4  Aow   @F`8@F`@  A   @G`2@G`:  A׼ݼ   @H`@H`  A5=   @J`0@J`8  At|   @K`.@K`6  A   @L`,@L`4  A  {{ @M`*@M`2  AGO  ww @O`*@O`2  A  ss @Q`,@Q`4  Aؾ  oo @R`.@R`6  A  kk @S`0@S`8  AV^  {gg @T`0@T`8  A  wcc @V`0@V`8  A  s__ @W`*@W`2  A(0  o[[ @X`,@X`4  Aai  kWW @Y`(@Y`0 |{ A  gSS @Z`0@Z`8 xw A  cOO @\`$@\`, ts A%-  _KK @]`(@]`0 po Ack  [GG @^`0@^`8 lk A  WCC @_`4@_`< hg A  S?? @``(@``0 dc A  O;; @a`&@a`. `_ AMU  K77 @b`(@b`0 \[ A  G33 @c`&@c`. XW A  C// @d`2@d`: TS A   ?++ @e`,@e`4 PO AGO  ;'' @f`8@f`@ LK A~  7## @g`&@g`. HG A  3 @h`4@h`< DC A  / @i`,@i`4 @? A3;  + @j`$@j`, <; Ahp  ' @k`$@k`, 87 A  # @l`"@l`* 7 A  A  UU @s`*@s`; authClientsendVerificationEmail A@`  A@J   @`@`= VU Acl   @`7@`@ M' A  A  EE @@`  A    @`&@`.  A   @`0@`8  AGO   @`$@`, A@ A   @`7@`@ + A,  A  00 @@` 87 A   @`7@`@   An~  Anq  '' @@` /. ADM   @`7@`@ +* A   @`7@`@  AJU  AJM   @` @` 3 Ap  Aps   @` @` 3 A  A   @` @` Z A  A     @` @` X A  A   @` @` J A'  A   @` @`!  A+<  A+.   @`@`! 8 AZr  AZ]   @`4@`L  A  A   @`"@`-  AQ\  AQT   @`"@`-  A5@  A58   @`"@`-  A  A   @,`@,`  A  A   @E`@E`  A   A   @Y`@Y`7  A?W  A?B   @l`@l`*  Aos   @t`@t`!  A   @`@`   A   @`$@`(  A,0   @`@`#  A    @`$@`(  A   @`@`!  Ax|   @`$@`(  A  } @`%@`)  A  y @`$@`(  A  u @`@`#  A  q @`$@`(  A  m @` @`$  A  i @`$@`(  A37  e @`%@`)  A  a @`$@`(  Apt  ] @`@`   AKO  Y @`$@`(  A  U @#`@#`  Arw  Q @&`@&`  A  M~~ @)`"@)`&  A    Izz @0`>@0`B  A    Evv @6`"@6`'  A    Arr @9`*@9`.  A    =nn @=`6@=`;  A    9jj @@`2@@`6  A  5ff @D`2@D`6  A  1bb @H``@H`e  A  -^^ @V`@V`  A  )ZZ @Y`5@Y`9  A  %VV @[`0@[`4  A  !RR @]`D@]`I  A  NN @c`6@c`: |} A  JJ @j`"@j`' ~ A  FF @m`=@m`A tu A  BB @o`H@o`M vw A   >> @u`:@u`> lm A8=   :: @{`C@{`H no A  66 @~`;@~`? de A  22 @`2@`7 `a A  .. @`:@`? \] AT!Y!  ** @`:@`? XY A%%  && @`E@`J Z[ A&&  "" @`:@`> VW A''   @`:@`> LM As+x+   @`:@`? NO AI,M,   @`B@`F JK A..   @`B@`F FG A22   @`B@`F <= A33     @`m@`r >? A44   @`:@`> 45 A55   @`:@`? 67 A88   @`D@`H ,- Az<<   @`B@`G () A=$=   @`2@`7 $% A >>   @`:@`? &' A>>   @`B@`F "# A??   @`B@`F  AyA~A   @`:@`?  AB B   @`B@`F  AcChC   @`B@`G  AhDlD   @`J@`N  AEE   @ `J@ `N  AII   @`:@`?  AwJ{J   @`B@`F  AM!M   @ `O@ `T  A&O+O   @'`V@'`[0 A,O5O 4 @'`\@'`e  AOO   @)`J@)`O  AvSzS   @2`R@2`V  AUU   @8``@8`d  A3Y8Y   @A`J@A`O  A\\  ~ @H`R@H`V  AN^R^  z @N``@N`d  Aaa  v @Z`G@Z`K  AGcLc  r @``2@``7  A)d.d  n @c`:@c`?  Aee  j @f`B@f`F  A|ff  f @j`X@j`\  A!h%h  b @p`:@p`>  Ahsms  ^ @`I@`N  Azt~t  Z @`J@`N  A*x.x  V @`c@`g  AUzYz  R @`\@``  A||  N @`J@`N  A  J{{ @`:@`>  AHM  Fww @`:@`?  A6:  Bss @`B@`F  A  >oo @`B@`F  Ahm  :kk @`Q@`V  A  6gg @`R@`V  A  2cc @`2@`7  Aw{  .__ @`:@`>  A27  *[[ @`H@`M  AǑˑ  &WW @`F@`J  A37  "SS @`F@`J  A@D  OO @`N@`R  A  KK @`h@`l yz A5:  GG @H`E@H`J A;D 4DD @H`K@H`T xy Aέҭ  @@ @J`F@J`J no A   << @_`X@_`] pq AEI  88 @b`V@b`Z lm Aѷշ  44 @f`V@f`Z hi A  00 @m`F@m`J ^_ A  ,, @o`g@o`l `a A.2  (( @r`V@r`Z \] Anr  $$ @|`F@|`J RS A*/     @~`T@~`Y NO A:?   @`]@`b PQ A   @`^@`b LM A   @`^@`b HI A   @`f@`j DE A     @`m@`q @A A   @`i@`m <= Az~   @`i@`m 89 A   @`]@`a 45 A   @`R@`V 01 ATX   @`E@`I ,- A   @`M@`Q "# A   @`L@`Q $% A   @`6@`:  ! A   @`6@`:  A   @`W@`[  AAF   @`@@`E  A   @`>@`B  ACG   @`\@``  A   @`>@`C  A   @`F@`K  A   @`N@`R  Az   @`N@`S  A`d   @`X@`\  A   @ `F@ `J  A$   @`E@`J  A   @`2@`7  A   @`:@`?  A   @`B@`F  A  { @!`B@!`G  A  w @)`J@)`N  A  s @/`X@/`\  A  o @:`:@:`?  A  k @=`B@=`F  A  g @C`P@C`T  A/4  c @I`B@I`G  A  _ @R`:@R`?  Asx  [ @U`B@U`G  A}  W @X`J@X`N  A  S @\`J@\`N  A    O @b``@b`d  Av z   K|| @e`G@e`K  A  Gxx @l`Q@l`V  A   Ctt @o`R@o`W  AFK  ?pp @r`Z@r`_  Ay}  ;ll @u`b@u`f  AFJ  7hh @y`b@y`f  A  3dd @`Z@`_  A  /`` @`R@`W  A/!3!  +\\ @`D@`H  A""  'XX @`@@`E  A# #  #TT @`>@`C  A$ $  PP @`F@`J  Aj%n%  LL @`F@`J  A&&  HH @`T@`X |} A((  DD @`X@`\ xy A1+5+  @@ @`>@`B tu Aj,n,   << @`>@`B jk AQ.V.  88 @`M@`R fg A11  44 @`>@`C hi Ab2f2  00 @`F@`J ^_ A33  ,, @`F@`K `a A44  (( @`N@`R \] AO6S6  $$ @`N@`R XY A::     @`L@`P TU A;;   @`>@`B JK A==   @`[@`` A=> 4 @`a@`j CD A>>   @`J@`O EF AL@P@     @`R@`V AB AC C     @ `R@ `V 78 AFF   @ `2@ `7 9: AGG   @ `:@ `> /0 AHH   @ `G@ `L 12 AJJ   @ `B@ `F -. AKK   @ `P@ `T #$ ANN   @$ `B@$ `G %& ANN   @' `J@' `N !" AdPhP   @+ `c@+ `g  AQQ   @/ `J@/ `O  ARR   @2 `R@2 `W  AUU   @: `o@: `t  AWW   @@ `W@@ `[  A-Y2Y   @C `p@C `u  A[[   @J `q@J `v  A^^   @Q `R@Q `V  Aaa   @W `s@W `w  Aaa   @Y `w@Y `|  A;c?c   @\ `Z@\ `^  Aff   @h `?@h `D  Agg   @k `B@k `F  Aii   @q `P@q `T  Akk   @w `B@w `G  All  | @y `J@y `N  Amm  x @} `J@} `N  A_pcp  t @ `2@ `6  App  p @ `@@ `E  AIrMr  l @ `>@ `B  A t t  h @ `L@ `P  Aww  d C   Axx  ` @ `;@ `?  Ayy  \ @ `;@ `@  Azz  X @ `S@ `X  A{{  T @ `:@ `>  A||  P @ `I@ `N  A~~  L}} @ `:@ `?  A  Hyy @ `B@ `G  A  Duu @ `J@ `N  A  @qq @ `J@ `N  A  <mm @ `B@ `F UP Ado  Adg  7nn @ `F@ `Q  A  3dd @ `P@ `T  A  /`` @ `P@ `U  A܏  +\\ @ `B@ `G  AƐʐ  'XX @ `J@ `N  A9=  #TT @ `J@ `N  A˓Г  PP @ `i@ `n  A}  LL @ `B@ `F 4/ A'  A  MM @ `F@ `Q {| Aqu  CC @ `P@ `T qr Aáȡ  ?? @# `N@# `S st A   ;; @& `:@& `> op A֣ڣ  77 @* `:@* `> kl A   33 @. `L@. `P ab A   // @1 `N@1 `S A  4,, @1 `T@1 `] Z[ A  (( @3 `B@3 `G \] A37  $$ @5 `J@5 `N RS A     @9 `J@9 `O TU A©   @< `R@< `V PQ A(,   @A `R@A `V FG A   @O `B@O `G HI A   @R `J@R `N DE A      @V `J@V `N @A A     @] `?@] `C <= A   @c `S@c `W Y A,  A   @i `,@i `G U A"@  A"%   @u `F@u `d () A   @ `J@ `O` A 4 @ `P@ `Y !" Ain   @ `:@ `? #$ Acg   @ `B@ `F  A   @ `B@ `G  A   @ `J@ `O  A   @ ``@ `d  A[_   @ `W@ `[  AEI   @ `e@ `i    ATX   @ ``@ `d  Afk   @ `J@ `O  A   @ `R@ `V  A   @ `R@ `V  A   @ `R@ `V  AZ_   @ `:@ `?  A^b   @ `B@ `F  A   @ `B@ `G  A   @ `J@ `O  AHL  ~ @ `R@ `V  A  z @ `R@ `V  A  v @ `J@ `O  A  r @ `R@ `V  ABF  n @ `R@ `V  A  j @ `B@ `G  Adh  f @ `J@ `N  A  b @ `J@ `N  A  ^ @ `J@ `O  A  Z @ `h@ `m  A:>  V @ `Z@ `^  A27  R @ `W@ `\  Auy  N @ `Z@ `^  A  J{{ @ `j@ `n  A   Fww @ `B@ `G  A  Bss @ `J@ `N  A   >oo @ `J@ `N  ADI  :kk @# `B@# `G  A  6gg @% `J@% `N  AQU  2cc @) `J@) `N  A  .__ @6 `B@6 `G  Alp  *[[ @8 `J@8 `N  A  &WW @< `J@< `N  AEJ  "SS @@ `J@@ `O  Acg  OO @H `R@H `V  A  KK @L `R@L `V  A    GG @P `R@P `V uv AZ _   CC @X `B@X `G wx A    ?? @Z `J@Z `N st Amq   ;; @^ `J@^ `N op A  77 @b `J@b `N ef A`!e!  33 @ `Y@ `^ gh A?%C%  // @ `Z@ `^ cd AW&[&  ++ @ `Z@ `^ YZ A<)A)  '' @ `:@ `? [\ A6*:*  ## @ `B@ `F WX Ax+|+   @ `B@ `F MN A--   @ `_@ `d OP A..   @ `J@ `N KL AC0G0   @ `J@ `N AB Aa4f4   C  CD A[5_5     @ `B@ `F 9: A66   @ `R@ `W 56 A77   @ `J@ `O 78 A88   @ `R@ `V 34 A :$:   @ `R@ `V /0 AG<K<   @ `J@ `N K A>>  A>>   @ `Z@ `j &' AiCmC   @ `X@ `\  AEE   @ `_@ `d  AFF   @ `J@ `O  AGG   @ `R@ `V  AII   @ `R@ `V  AAKEK   @ `J@ `N . AMM  AMM   @ `Z@ `j    ARRVR   @ `X@ `\  A5U:U   C! !   A/V3V   @$ `B@$ `F  AWW   @( `B@( `G  AXX   @+ `J@+ `O  AYY]Y   @- `R@- `V  A[ [   @1 `R@1 `V  A1]5]   @7 `J@7 `N  A_#_   @; `X@; `\  Aaa  | @E `2@E `6  Add  x @M `>@M `B  AFeKe  t @O `8@O `=  A f$f  p @R `6@R `:  Aff  l @T `D@T `H  Agg  h @Y `6@Y `:  Ai#i  d @] `6@] `;  Akk  ` @g `D@g `I  All  \ @j `>@j `B  Aoo  X @v `6@v `:  App  T @z `6@z `:  ~/* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect, useCallback } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { getMyAvailability, setAvailability, setAvailabilityRange, request } from '@/lib/api'; const STATUS_CYCLE = { available: 'busy', busy: null }; const WEEK_DAYS_BY_LOCALE = { ru: [ 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс' ], en: [ 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su' ], el: [ 'Δε', 'Τρ', 'Τε', 'Πε', 'Πα', 'Σά', 'Κυ' ] }; const MONTHS_BY_LOCALE = { ru: [ 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' ], en: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], el: [ 'Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος' ] }; function toMonthKey(year, month) { return `${year}-${String(month + 1).padStart(2, '0')}`; } function toDateKey(year, month, day) { return `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; } export default function SchedulePage() { const { data: session, isPending } = useSession(); const router = useRouter(); const searchParams = useSearchParams(); const { locale, t } = useLocale(); const now = new Date(); const [viewYear, setViewYear] = useState(now.getFullYear()); const [viewMonth, setViewMonth] = useState(now.getMonth()); // availability map: 'YYYY-MM-DD' → 'available'|'busy' const [avail, setAvail] = useState({}); const [saving, setSaving] = useState(null) // date being saved ; // Range selection state const [rangeStart, setRangeStart] = useState(null); const [rangeMode, setRangeMode] = useState(false); const [rangeStatus, setRangeStatus] = useState('available'); // Google Calendar state const [gcalStatus, setGcalStatus] = useState(null); const [gcalLoading, setGcalLoading] = useState(false); const [gcalToast, setGcalToast] = useState(null); const today = new Date().toISOString().slice(0, 10); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); if (!isPending && session && session.user?.role !== 'specialist' && session.user?.role !== 'admin') router.push('/profile'); }, [ session, isPending ]); // Load Google Calendar status const loadGcalStatus = useCallback(()=>{ request('/google/calendar/status').then(setGcalStatus).catch(()=>setGcalStatus({ connected: false })); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; loadGcalStatus(); // Handle callback redirect params const gcalParam = searchParams.get('gcal'); if (gcalParam === 'connected') { setGcalToast(t('schedule.gcalConnected')); setTimeout(()=>setGcalToast(null), 5000); router.replace('/schedule'); } else if (gcalParam === 'error') { setGcalToast(t('schedule.gcalError')); setTimeout(()=>setGcalToast(null), 5000); router.replace('/schedule'); } }, [ session ]); const loadMonth = useCallback((year, month)=>{ const key = toMonthKey(year, month); getMyAvailability(key).then((rows)=>{ setAvail((prev)=>{ const next = { ...prev }; rows.forEach((r)=>{ next[r.date] = r.status; }); return next; }); }).catch(()=>{}); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; loadMonth(viewYear, viewMonth); // preload next month too const next = new Date(viewYear, viewMonth + 1, 1); loadMonth(next.getFullYear(), next.getMonth()); }, [ session, viewYear, viewMonth, loadMonth ]); function prevMonth() { if (viewMonth === 0) { setViewYear((y)=>y - 1); setViewMonth(11); } else setViewMonth((m)=>m - 1); } function nextMonth() { if (viewMonth === 11) { setViewYear((y)=>y + 1); setViewMonth(0); } else setViewMonth((m)=>m + 1); } async function toggleDay(dateKey) { if (dateKey < today) return; // past — ignore if (rangeMode) { if (!rangeStart) { setRangeStart(dateKey); return; } // Second click — apply range const from = rangeStart < dateKey ? rangeStart : dateKey; const to = rangeStart < dateKey ? dateKey : rangeStart; setRangeStart(null); setSaving('range'); try { await setAvailabilityRange(from, to, rangeStatus); // Update local state setAvail((prev)=>{ const next = { ...prev }; const cur = new Date(from); const end = new Date(to); while(cur <= end){ const d = cur.toISOString().slice(0, 10); if (d >= today) next[d] = rangeStatus; cur.setDate(cur.getDate() + 1); } return next; }); } catch {} setSaving(null); return; } const current = avail[dateKey] ?? null; const next = current === null ? 'available' : STATUS_CYCLE[current]; setSaving(dateKey); // Optimistic setAvail((prev)=>({ ...prev, [dateKey]: next })); try { await setAvailability(dateKey, next); } catch { // Revert on error setAvail((prev)=>({ ...prev, [dateKey]: current })); } setSaving(null); } if (isPending) return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-gray-500", children: t('common.loading') }); const role = session?.user?.role; if (!session || role !== 'specialist' && role !== 'admin') return null; const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; async function connectGcal() { window.location.href = `${apiBase}/api/google/calendar/connect`; } async function disconnectGcal() { if (!confirm(t('schedule.gcalDisconnectConfirm'))) return; setGcalLoading(true); try { await request('/google/calendar/disconnect', { method: 'DELETE' }); setGcalStatus({ connected: false }); } catch {} setGcalLoading(false); } async function importFromGcal() { setGcalLoading(true); try { const res = await request('/google/calendar/import', { method: 'POST' }); setGcalToast(t('schedule.gcalImportDone').replace('{n}', String(res.imported ?? 0))); setTimeout(()=>setGcalToast(null), 5000); // Refresh calendar display loadMonth(viewYear, viewMonth); } catch {} setGcalLoading(false); } return /*#__PURE__*/ _jsxs("div", { className: "max-w-3xl mx-auto px-4 py-10", children: [ gcalToast && /*#__PURE__*/ _jsx("div", { className: "fixed top-4 right-4 z-50 bg-white border border-gray-200 shadow-lg rounded-xl px-4 py-3 text-sm text-gray-800 max-w-xs", children: gcalToast }), /*#__PURE__*/ _jsxs("div", { className: "mb-8", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-2xl font-bold text-white", children: t('schedule.title') }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-white/70 mt-1", children: t('schedule.subtitle') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-4 mb-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ _jsx("span", { className: "w-6 h-6 rounded-lg bg-emerald-100 border-2 border-emerald-400 flex items-center justify-center text-xs", children: "✓" }), t('schedule.available') ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ _jsx("span", { className: "w-6 h-6 rounded-lg bg-red-100 border-2 border-red-400 flex items-center justify-center text-xs", children: "✗" }), t('schedule.busy') ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ _jsx("span", { className: "w-6 h-6 rounded-lg bg-white/20 border border-white/30" }), t('schedule.unset') ] }), /*#__PURE__*/ _jsx("div", { className: "text-xs text-white/50 self-center", children: t('schedule.click_hint') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 mb-6 p-3 bg-white rounded-xl border border-gray-200", children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [ /*#__PURE__*/ _jsx("div", { onClick: ()=>{ setRangeMode((v)=>!v); setRangeStart(null); }, className: `w-10 h-6 rounded-full transition-colors relative cursor-pointer ${rangeMode ? 'bg-blue-500' : 'bg-gray-200'}`, children: /*#__PURE__*/ _jsx("span", { className: `absolute top-1 w-4 h-4 bg-white rounded-full shadow transition-transform ${rangeMode ? 'translate-x-5' : 'translate-x-1'}` }) }), /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-700", children: t('schedule.range_mode') }) ] }), rangeMode && /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 ml-4", children: [ /*#__PURE__*/ _jsx("button", { onClick: ()=>setRangeStatus('available'), className: `px-3 py-1 rounded-lg text-sm font-medium border transition ${rangeStatus === 'available' ? 'bg-emerald-100 border-emerald-400 text-emerald-700' : 'bg-white border-gray-200 text-gray-500'}`, children: t('schedule.available') }), /*#__PURE__*/ _jsx("button", { onClick: ()=>setRangeStatus('busy'), className: `px-3 py-1 rounded-lg text-sm font-medium border transition ${rangeStatus === 'busy' ? 'bg-red-100 border-red-400 text-red-700' : 'bg-white border-gray-200 text-gray-500'}`, children: t('schedule.busy') }), rangeStart && /*#__PURE__*/ _jsx("span", { className: "text-xs text-blue-600", children: t('schedule.range_from').replace('{date}', rangeStart) }) ] }) ] }), /*#__PURE__*/ _jsx(AvailCalendar, { year: viewYear, month: viewMonth, avail: avail, saving: saving, rangeStart: rangeStart, today: today, onToggle: toggleDay, onPrev: prevMonth, onNext: nextMonth }), /*#__PURE__*/ _jsxs("div", { className: "mt-6 bg-white rounded-2xl border border-gray-200 p-5 shadow-sm", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-4", children: [ /*#__PURE__*/ _jsxs("svg", { width: "22", height: "22", viewBox: "0 0 48 48", fill: "none", children: [ /*#__PURE__*/ _jsx("rect", { width: "48", height: "48", rx: "8", fill: "#fff" }), /*#__PURE__*/ _jsx("path", { d: "M34 14H14a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2V16a2 2 0 0 0-2-2z", fill: "#4285F4" }), /*#__PURE__*/ _jsx("path", { d: "M28 20h-8v2h8v-2zm0 4h-8v2h8v-2zm-2 4h-6v2h6v-2z", fill: "#fff" }), /*#__PURE__*/ _jsx("circle", { cx: "18", cy: "18", r: "2", fill: "#DB4437" }), /*#__PURE__*/ _jsx("circle", { cx: "30", cy: "18", r: "2", fill: "#DB4437" }), /*#__PURE__*/ _jsx("rect", { x: "17", y: "12", width: "2", height: "6", rx: "1", fill: "#DB4437" }), /*#__PURE__*/ _jsx("rect", { x: "29", y: "12", width: "2", height: "6", rx: "1", fill: "#DB4437" }) ] }), /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-900 text-sm", children: t('schedule.googleCalendar') }) ] }), gcalStatus === null ? /*#__PURE__*/ _jsx("div", { className: "text-xs text-gray-400", children: t('common.loading') }) : gcalStatus.connected ? /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [ /*#__PURE__*/ _jsx("circle", { cx: "8", cy: "8", r: "8", fill: "#22c55e" }), /*#__PURE__*/ _jsx("path", { d: "M5 8l2 2 4-4", stroke: "#fff", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) ] }), /*#__PURE__*/ _jsxs("span", { className: "text-sm text-gray-700", children: [ t('schedule.connectedAs'), " ", /*#__PURE__*/ _jsx("span", { className: "font-medium", children: gcalStatus.email }) ] }) ] }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400", children: t('schedule.gcalAutoSyncNote') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-2", children: [ /*#__PURE__*/ _jsx("button", { onClick: importFromGcal, disabled: gcalLoading, className: "px-3 py-1.5 rounded-lg border border-blue-200 bg-blue-50 text-blue-700 text-xs font-medium hover:bg-blue-100 disabled:opacity-50 transition", children: gcalLoading ? t('common.loading') : t('schedule.importFromGoogle') }), /*#__PURE__*/ _jsx("button", { onClick: disconnectGcal, disabled: gcalLoading, className: "px-3 py-1.5 rounded-lg border border-gray-200 bg-white text-gray-500 text-xs font-medium hover:bg-gray-50 disabled:opacity-50 transition", children: t('schedule.disconnectGoogle') }) ] }) ] }) : /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500", children: t('schedule.gcalConnectDesc') }), /*#__PURE__*/ _jsxs("button", { onClick: connectGcal, className: "flex items-center gap-2 px-4 py-2 rounded-xl border border-gray-200 bg-white hover:bg-gray-50 transition text-sm font-medium text-gray-700", children: [ /*#__PURE__*/ _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 48 48", fill: "none", children: [ /*#__PURE__*/ _jsx("path", { d: "M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z", fill: "#FFC107" }), /*#__PURE__*/ _jsx("path", { d: "M6.3 14.7l7 5.1C15 16.1 19.1 13 24 13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 16.3 2 9.7 7.4 6.3 14.7z", fill: "#FF3D00" }), /*#__PURE__*/ _jsx("path", { d: "M24 46c5.5 0 10.5-1.9 14.4-5.1l-6.7-5.5C29.5 37 26.9 38 24 38c-6.1 0-11.2-4-13-9.5l-7 5.4C7.6 41.9 15.2 46 24 46z", fill: "#4CAF50" }), /*#__PURE__*/ _jsx("path", { d: "M44.5 20H24v8.5h11.8c-.9 2.8-2.8 5.1-5.3 6.6l6.7 5.5C41.5 37.3 45 31.1 45 24c0-1.3-.2-2.7-.5-4z", fill: "#1976D2" }) ] }), t('schedule.connectGoogle') ] }) ] }) ] }) ] }); } function AvailCalendar({ year, month, avail, saving, rangeStart, today, onToggle, onPrev, onNext }) { const { locale, t } = useLocale(); const weekDays = WEEK_DAYS_BY_LOCALE[locale] ?? WEEK_DAYS_BY_LOCALE.ru; const months = MONTHS_BY_LOCALE[locale] ?? MONTHS_BY_LOCALE.ru; const firstDay = new Date(year, month, 1); // Monday-based: 0=Mon, 6=Sun const startDow = (firstDay.getDay() + 6) % 7; const daysInMonth = new Date(year, month + 1, 0).getDate(); const prevMonthDays = new Date(year, month, 0).getDate(); const cells = []; // Leading days from prev month for(let i = startDow - 1; i >= 0; i--){ cells.push({ day: prevMonthDays - i, cur: false, dateKey: '' }); } // Current month days for(let d = 1; d <= daysInMonth; d++){ cells.push({ day: d, cur: true, dateKey: toDateKey(year, month, d) }); } // Trailing days const remainder = cells.length % 7; if (remainder !== 0) { for(let d = 1; d <= 7 - remainder; d++){ cells.push({ day: d, cur: false, dateKey: '' }); } } // Count summary — only future dates (>= today) const monthPrefix = toDateKey(year, month, 1).slice(0, 7); const availCount = Object.entries(avail).filter(([k, v])=>k.startsWith(monthPrefix) && k >= today && v === 'available').length; const busyCount = Object.entries(avail).filter(([k, v])=>k.startsWith(monthPrefix) && k >= today && v === 'busy').length; return /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl border border-gray-200 overflow-hidden shadow-sm", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-100", children: [ /*#__PURE__*/ _jsx("button", { onClick: onPrev, className: "w-8 h-8 rounded-lg hover:bg-gray-100 flex items-center justify-center text-gray-500 transition", children: "‹" }), /*#__PURE__*/ _jsxs("div", { className: "text-center", children: [ /*#__PURE__*/ _jsxs("h2", { className: "font-semibold text-gray-900", children: [ months[month], " ", year ] }), /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-400 mt-0.5", children: [ /*#__PURE__*/ _jsxs("span", { className: "text-emerald-600 font-medium", children: [ availCount, " ", t('schedule.free') ] }), ' · ', /*#__PURE__*/ _jsxs("span", { className: "text-red-500 font-medium", children: [ busyCount, " ", t('schedule.busy_count') ] }) ] }) ] }), /*#__PURE__*/ _jsx("button", { onClick: onNext, className: "w-8 h-8 rounded-lg hover:bg-gray-100 flex items-center justify-center text-gray-500 transition", children: "›" }) ] }), /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-7 border-b border-gray-100", children: weekDays.map((d)=>/*#__PURE__*/ _jsx("div", { className: "py-2 text-center text-xs font-medium text-gray-400", children: d }, d)) }), /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-7", children: cells.map((cell, idx)=>{ if (!cell.cur) { return /*#__PURE__*/ _jsx("div", { className: "p-1 h-12 flex items-center justify-center text-sm text-gray-200", children: cell.day }, `empty-${idx}`); } const status = avail[cell.dateKey] ?? null; const isPast = cell.dateKey < today; const isToday = cell.dateKey === today; const isSaving = saving === cell.dateKey; const isRangeStart = rangeStart === cell.dateKey; let cellCls = 'h-12 flex flex-col items-center justify-center rounded-xl m-0.5 text-sm font-medium transition-all select-none '; if (isPast) { cellCls += 'text-gray-200 cursor-default '; } else if (status === 'available') { cellCls += 'bg-emerald-100 border-2 border-emerald-400 text-emerald-700 cursor-pointer hover:bg-emerald-200 '; } else if (status === 'busy') { cellCls += 'bg-red-100 border-2 border-red-400 text-red-700 cursor-pointer hover:bg-red-200 '; } else { cellCls += 'bg-gray-50 border border-gray-200 text-gray-700 cursor-pointer hover:bg-blue-50 hover:border-blue-300 '; } if (isToday) cellCls += 'ring-2 ring-blue-400 ring-offset-1 '; if (isRangeStart) cellCls += '!ring-2 !ring-blue-500 !ring-offset-1 scale-105 '; if (isSaving) cellCls += 'opacity-60 pointer-events-none '; return /*#__PURE__*/ _jsxs("button", { className: cellCls, onClick: ()=>onToggle(cell.dateKey), disabled: isPast || isSaving, title: status === 'available' ? t('schedule.available') : status === 'busy' ? t('schedule.busy') : t('schedule.click_to_set'), children: [ /*#__PURE__*/ _jsx("span", { children: cell.day }), !isPast && status === 'available' && /*#__PURE__*/ _jsx("span", { className: "text-[9px] leading-none text-emerald-600", children: t('schedule.available').toLowerCase() }), !isPast && status === 'busy' && /*#__PURE__*/ _jsx("span", { className: "text-[9px] leading-none text-red-500", children: t('schedule.busy').toLowerCase() }), isSaving && /*#__PURE__*/ _jsx("span", { className: "text-[8px] text-gray-400", children: "..." }) ] }, cell.dateKey); }) }) ] }); } `  /opt/canhelp/apps/web/src/app/schedule  B   DEFGH5b71f60a7723a9fd     Q toMonthKeytoDateKeyAvailCalendarSTATUS_CYCLEWEEK_DAYS_BY_LOCALEMONTHS_BY_LOCALEMSchedulePage EyB/opt/canhelp/apps/web/src/app/schedule/page.tsx P! fyBfyBe2bd59a5d453624e  d a=| b=| `}@ `9 A `= A `( AK `- AL `^ AH_ A9_ aZ@%' AIh @`@`30 Al @`@`N `jUU b=| `9 `= `( `-VV `^` aZ@% %$ A   \   c[)[3  A   c\\  A   c]](  A   c^^#  ALT   c`$`,  A   ca&a.  A    ccc&  A0 8    cd d(   A    cg(g0    A    ch&h.  A     ci*i2  Ak s    ck(k0  A    cl*l2  A    cm&m. $# A\ e    co7o@ JI A    cww&  A    cxx  A~    c|7|@ >= A   @`@`! ;: A5F   @@`    A   @`7@`@ 54 ATh   @`@`* 0/ A5D   @`@`! &' AQU   @`(@`,  A   @`@`  A   @`@`%  A    @ `@ `  A !   @ `'@ `+    A!!   @`@`  A^"b"   @`"@`&    A###   @`"@`&  A##   @`@`  A}$$   @!`"@!`'  A.%2%  { @$`*@$`.  A&&  w @+`"@+`'  AY']'  s @.`*@.`.  A((  o @5`"@5`'  Aw){)  k @8`*@8`.  A**  g @>`"@>`&  Aq+v+  c @D`@D`  A(,-,  _ @G`"@G`'  A,,  [ @J`*@J`.  A{..  W @P`8@P`<  A//  S @T`*@T`.  A00  O @Z`/@Z`4  Ad1h1  K @]`*@]`.  A5393  G @b`*@b`.  A44  C @g`8@g`<  A96=6  ? @o`@o`  A77  ; @z`@z`  AS8X8  7 @}`"@}`'  A88  3~~ @`*@`/  A:#:  /zz @`2@`6  AY;];  +vv @`2@`6  At<x<  'rr @`2@`6  Aq=u=  #nn @`2@`6  A>>  jj @`2@`6  A??  ff @`2@`6  A|AA  bb @`2@`6  ARCVC  ^^ @`*@`.  ADD  ZZ @`8@`<  A?EDE   VV @`>@`C  AEE  RR @`*@`/  AFF  NN @`2@`7  AGG  JJ @`:@`> ~ A@IDI  FF @`:@`> tu AYK^K  BB @`2@`7 vw ALL  >> @`:@`> rs A+N/N  :: @`*@`. hi AOO  66 @`*@`/ jk AOO  22 @`2@`6 fg AQQ  .. @`2@`6 \] A*T/T  ** @`'@`, ^_ ATT  && @`*@`. TU AUU  "" @`*@`/ PQ AVV   @`2@`7 RS ATXXX   @ `:@ `> NO AZ Z   @`:@`> JK Ah[l[   @`:@`> FG A\\   @`:@`>  A__    @'`@'`# 78 A{ee   @O`@O` 34 Aff   @R`@R` 56 Aff   @U`"@U`& +, Agg   @Z`"@Z`' '( Arhwh   @]`*@]`/ #$ Aii   @e`*@e`/   Ajj   @h`2@h`7  All   @q`2@q`7  Ann   @}`"@}`&  Aoo   @`@`  Ayp}p   @`:@`>  AIqMq   @`@`   A rr   @`-@`1  Axx   @`)@`.  Azz   @`*@`.  Azz   @`O@`S  A{{   @`J@`N  A||   @`6@`:  /* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/navigation'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import * as api from '@/lib/api'; const TOTAL_STEPS = 5; // ─── Step indicator ──────────────────────────────────────────────────────── function StepIndicator({ current, total }) { return /*#__PURE__*/ _jsx("div", { className: "flex items-center justify-center gap-2 mb-8", children: Array.from({ length: total }, (_, i)=>i + 1).map((n)=>/*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ _jsx("div", { className: `w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold transition-colors ${n < current ? 'bg-green-500 text-white' : n === current ? 'bg-blue-600 text-white ring-4 ring-blue-200' : 'bg-gray-200 text-gray-400'}`, children: n < current ? /*#__PURE__*/ _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: /*#__PURE__*/ _jsx("path", { d: "M2 7l4 4 6-6", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) : n }), n < total && /*#__PURE__*/ _jsx("div", { className: `w-8 h-0.5 ${n < current ? 'bg-green-500' : 'bg-gray-200'}` }) ] }, n)) }); } // ─── Step 1: Welcome ─────────────────────────────────────────────────────── function Step1Welcome({ t, onNext }) { return /*#__PURE__*/ _jsxs("div", { className: "text-center", children: [ /*#__PURE__*/ _jsx("div", { className: "w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6", children: /*#__PURE__*/ _jsxs("svg", { width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "#2563eb", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [ /*#__PURE__*/ _jsx("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }), /*#__PURE__*/ _jsx("circle", { cx: "12", cy: "7", r: "4" }) ] }) }), /*#__PURE__*/ _jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-2", children: t('specialist_setup.step1.title') }), /*#__PURE__*/ _jsx("p", { className: "text-blue-600 font-medium mb-4", children: t('specialist_setup.step1.subtitle') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm leading-relaxed mb-8 max-w-sm mx-auto", children: t('specialist_setup.step1.desc') }), /*#__PURE__*/ _jsxs("div", { className: "bg-gray-50 rounded-xl p-5 text-left mb-8 max-w-sm mx-auto", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-semibold text-gray-700 mb-3", children: t('specialist_setup.step1.what_next') }), /*#__PURE__*/ _jsx("ul", { className: "space-y-2", children: [ t('specialist_setup.step1.item1'), t('specialist_setup.step1.item2'), t('specialist_setup.step1.item3'), t('specialist_setup.step1.item4'), t('specialist_setup.step1.item5') ].map((item, i)=>/*#__PURE__*/ _jsxs("li", { className: "flex items-center gap-2 text-sm text-gray-600", children: [ /*#__PURE__*/ _jsx("span", { className: "w-5 h-5 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center text-xs font-bold shrink-0", children: i + 1 }), item ] }, i)) }) ] }), /*#__PURE__*/ _jsxs("button", { onClick: onNext, className: "w-full max-w-xs bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 transition", children: [ t('specialist_setup.next'), " →" ] }) ] }); } // ─── Step 2: Basic profile ───────────────────────────────────────────────── function Step2Profile({ t, onNext, onBack }) { const [bio, setBio] = useState(''); const [phone, setPhone] = useState(''); const [saving, setSaving] = useState(false); const [avatarUrl, setAvatarUrl] = useState(null); const [uploading, setUploading] = useState(false); const fileRef = useRef(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.request('/users/me', {}).then((u)=>{ setBio(u.bio ?? ''); setPhone(u.phone ?? ''); setAvatarUrl(u.image ?? null); }).catch(()=>{}); }, []); async function handleAvatarChange(e) { const file = e.target.files?.[0]; if (!file) return; setUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); const fullUrl = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}${url}`; await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ image: fullUrl }) }); setAvatarUrl(fullUrl); } catch {} finally{ setUploading(false); if (fileRef.current) fileRef.current.value = ''; } } async function handleSave() { setSaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ bio: bio || undefined, phone: phone || undefined }) }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step2.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step2.subtitle') }), /*#__PURE__*/ _jsxs("div", { className: "mb-5", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step2.photo_label') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-4", children: [ /*#__PURE__*/ _jsx("div", { className: "w-16 h-16 rounded-full bg-gray-100 border-2 border-gray-200 overflow-hidden shrink-0 flex items-center justify-center", children: avatarUrl ? /*#__PURE__*/ _jsx("img", { src: avatarUrl, alt: "", className: "w-full h-full object-cover" }) : /*#__PURE__*/ _jsxs("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "#9ca3af", strokeWidth: "2", children: [ /*#__PURE__*/ _jsx("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }), /*#__PURE__*/ _jsx("circle", { cx: "12", cy: "7", r: "4" }) ] }) }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>fileRef.current?.click(), disabled: uploading, className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium text-gray-700 disabled:opacity-50 transition", children: uploading ? t('specialist_setup.step2.photo_uploading') : t('specialist_setup.step2.photo_btn') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('specialist_setup.step2.photo_hint') }) ] }), /*#__PURE__*/ _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handleAvatarChange }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-4", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step2.bio_label') }), /*#__PURE__*/ _jsx("textarea", { value: bio, onChange: (e)=>setBio(e.target.value), rows: 4, maxLength: 1000, placeholder: t('specialist_setup.step2.bio_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step2.phone_label') }), /*#__PURE__*/ _jsx("input", { type: "tel", value: phone, onChange: (e)=>setPhone(e.target.value), placeholder: t('specialist_setup.step2.phone_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 3: Service card ────────────────────────────────────────────────── function Step3Card({ t, onNext, onBack, onCardCreated }) { const [title, setTitle] = useState(''); const [desc, setDesc] = useState(''); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); async function handleSave() { if (!title.trim()) { setError(t('specialist_setup.step3.title_required')); return; } setError(''); setSaving(true); try { const card = await api.createSpecialistCard({ title: title.trim(), description: desc || undefined }); onCardCreated(card); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step3.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step3.subtitle') }), /*#__PURE__*/ _jsxs("div", { className: "mb-4", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step3.title_label') }), /*#__PURE__*/ _jsx("input", { value: title, onChange: (e)=>{ setTitle(e.target.value); if (error) setError(''); }, maxLength: 200, placeholder: t('specialist_setup.step3.title_placeholder'), className: `w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 ${error ? 'border-red-400' : 'border-gray-300'}` }), error && /*#__PURE__*/ _jsx("p", { className: "text-red-500 text-xs mt-1", children: error }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step3.desc_label') }), /*#__PURE__*/ _jsx("textarea", { value: desc, onChange: (e)=>setDesc(e.target.value), rows: 5, maxLength: 1000, placeholder: t('specialist_setup.step3.desc_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 4: Skills & Categories ────────────────────────────────────────── function Step4Skills({ t, onNext, onBack, card, catLocale }) { const [skills, setSkills] = useState(card?.skills ?? []); const [skillInput, setSkillInput] = useState(''); const [categories, setCategories] = useState(card?.categories ?? []); const [allCategories, setAllCategories] = useState([]); const [suggestions, setSuggestions] = useState([]); const [saving, setSaving] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.getCategories().then(setAllCategories).catch(()=>{}); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.getSkillSuggestions(categories.length > 0 ? categories : undefined).then(setSuggestions).catch(()=>{}); }, [ categories ]); function addSkill(s) { const trimmed = s.trim(); if (trimmed && !skills.includes(trimmed)) setSkills([ ...skills, trimmed ]); setSkillInput(''); } function toggleCategory(slug, childSlugs = []) { if (categories.includes(slug)) { setCategories(categories.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setCategories([ ...new Set([ ...categories, slug, ...childSlugs ]) ]); } } async function handleSave() { if (!card) { onNext(); return; } setSaving(true); try { await api.updateSpecialistCard(card.id, { skills, categories }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step4.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step4.subtitle') }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step4.skills_label') }), skills.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2 mb-2", children: skills.map((s)=>/*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5 bg-blue-50 text-blue-700 text-sm px-3 py-1 rounded-full", children: [ s, /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setSkills(skills.filter((x)=>x !== s)), className: "text-blue-400 hover:text-blue-700 leading-none text-base", children: "\xd7" }) ] }, s)) }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2", children: [ /*#__PURE__*/ _jsx("input", { value: skillInput, onChange: (e)=>setSkillInput(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') { e.preventDefault(); addSkill(skillInput); } }, placeholder: t('specialist_setup.step4.skills_placeholder'), className: "flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>addSkill(skillInput), className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium", children: t('specialist_setup.step4.skills_add') }) ] }), suggestions.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-1.5 mt-2", children: suggestions.map((s)=>s.names[catLocale] ?? s.names.el).filter((name, i, arr)=>arr.indexOf(name) === i && !skills.includes(name)).slice(0, 12).map((name)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>addSkill(name), className: "text-xs px-2.5 py-1 border border-gray-200 rounded-full text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: [ "+ ", name ] }, name)) }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step4.categories_label') }), /*#__PURE__*/ _jsx("div", { className: "space-y-2 max-h-64 overflow-y-auto border border-gray-200 rounded-xl p-3", children: allCategories.map((cat)=>{ const catName = cat.names?.[catLocale] ?? cat.names?.el ?? cat.slug; const children = cat.children ?? []; const childSlugs = children.map((c)=>c.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: categories.includes(cat.slug), onChange: ()=>toggleCategory(cat.slug, childSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("span", { className: "text-sm font-medium text-gray-800", children: [ cat.icon && /*#__PURE__*/ _jsx("span", { className: "mr-1", children: cat.icon }), catName ] }) ] }), children.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-1.5 space-y-1.5", children: children.map((sub)=>{ const subName = sub.names?.[catLocale] ?? sub.names?.el ?? sub.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: categories.includes(sub.slug), onChange: ()=>toggleCategory(sub.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: subName }) ] }, sub.id); }) }) ] }, cat.id); }) }) ] }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 5: Geography ───────────────────────────────────────────────────── function Step5Geography({ t, onNext, onBack, card, catLocale }) { const [locations, setLocations] = useState(card?.locations ?? []); const [locationTree, setLocationTree] = useState([]); const [saving, setSaving] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.getLocations().then(setLocationTree).catch(()=>{}); }, []); function toggleLocation(slug, childSlugs = []) { if (locations.includes(slug)) { setLocations(locations.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocations([ ...new Set([ ...locations, slug, ...childSlugs ]) ]); } } async function handleSave() { if (!card) { onNext(); return; } setSaving(true); try { await api.updateSpecialistCard(card.id, { locations }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step5.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: t('specialist_setup.step5.subtitle') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mb-5", children: t('specialist_setup.step5.hint') }), /*#__PURE__*/ _jsx("div", { className: "space-y-3 max-h-72 overflow-y-auto border border-gray-200 rounded-xl p-3 mb-6", children: locationTree.map((city)=>{ const cityName = city.names?.[catLocale] ?? city.names?.el ?? city.slug; const districts = city.children ?? []; const districtSlugs = districts.map((d)=>d.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: locations.includes(city.slug), onChange: ()=>toggleLocation(city.slug, districtSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-800", children: cityName }) ] }), districts.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-1.5 space-y-1.5", children: districts.map((d)=>{ const dName = d.names?.[catLocale] ?? d.names?.el ?? d.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: locations.includes(d.slug), onChange: ()=>toggleLocation(d.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: dName }) ] }, d.id); }) }) ] }, city.id); }) }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving, isLast: true }) ] }); } // ─── Done screen ─────────────────────────────────────────────────────────── function StepDone({ t }) { return /*#__PURE__*/ _jsxs("div", { className: "text-center py-4", children: [ /*#__PURE__*/ _jsx("div", { className: "w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-6", children: /*#__PURE__*/ _jsx("svg", { width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "#16a34a", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /*#__PURE__*/ _jsx("path", { d: "M20 6L9 17l-5-5" }) }) }), /*#__PURE__*/ _jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-2", children: t('specialist_setup.done.title') }), /*#__PURE__*/ _jsx("p", { className: "text-green-600 font-medium mb-4", children: t('specialist_setup.done.subtitle') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm leading-relaxed mb-8 max-w-sm mx-auto", children: t('specialist_setup.done.desc') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col sm:flex-row gap-3 justify-center", children: [ /*#__PURE__*/ _jsx("a", { href: "/profile", className: "px-6 py-3 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 transition text-center", children: t('specialist_setup.go_to_profile') }), /*#__PURE__*/ _jsx("a", { href: "/tasks", className: "px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition text-center", children: t('specialist_setup.browse_tasks') }) ] }) ] }); } // ─── Navigation buttons ──────────────────────────────────────────────────── function NavButtons({ t, onBack, onNext, loading, isLast }) { return /*#__PURE__*/ _jsxs("div", { className: "flex gap-3 pt-2", children: [ /*#__PURE__*/ _jsxs("button", { type: "button", onClick: onBack, className: "flex-1 px-4 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition", children: [ "← ", t('specialist_setup.back') ] }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: onNext, disabled: loading, className: "flex-[2] px-4 py-3 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 transition", children: loading ? '...' : isLast ? t('specialist_setup.finish') : `${t('specialist_setup.next')} →` }) ] }); } // ─── Main page ───────────────────────────────────────────────────────────── export default function SpecialistSetupPage() { const { data: session, isPending } = useSession(); const router = useRouter(); const { t, locale } = useLocale(); const [step, setStep] = useState(1); const [card, setCard] = useState(null); const catLocale = locale === 'ru' ? 'ru' : locale === 'en' ? 'en' : 'el'; process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); if (!isPending && session && session.user?.role !== 'specialist') router.push('/become-specialist'); }, [ session, isPending ]); if (isPending || !session) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const isDone = step > TOTAL_STEPS; return /*#__PURE__*/ _jsx("div", { className: "min-h-screen py-10 px-4", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-lg mx-auto", children: [ /*#__PURE__*/ _jsxs("div", { className: "text-center mb-6", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-lg font-semibold text-white/90", children: t('specialist_setup.page_title') }), !isDone && /*#__PURE__*/ _jsx("p", { className: "text-sm text-white/50 mt-0.5", children: t('specialist_setup.step_of').replace('{current}', String(step)).replace('{total}', String(TOTAL_STEPS)) }) ] }), !isDone && /*#__PURE__*/ _jsx(StepIndicator, { current: step, total: TOTAL_STEPS }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl border border-gray-200 p-6 shadow-sm", children: [ isDone && /*#__PURE__*/ _jsx(StepDone, { t: t }), step === 1 && /*#__PURE__*/ _jsx(Step1Welcome, { t: t, onNext: ()=>setStep(2) }), step === 2 && /*#__PURE__*/ _jsx(Step2Profile, { t: t, onNext: ()=>setStep(3), onBack: ()=>setStep(1) }), step === 3 && /*#__PURE__*/ _jsx(Step3Card, { t: t, onNext: ()=>setStep(4), onBack: ()=>setStep(2), onCardCreated: setCard }), step === 4 && /*#__PURE__*/ _jsx(Step4Skills, { t: t, onNext: ()=>setStep(5), onBack: ()=>setStep(3), card: card, catLocale: catLocale }), step === 5 && /*#__PURE__*/ _jsx(Step5Geography, { t: t, onNext: ()=>setStep(6), onBack: ()=>setStep(4), card: card, catLocale: catLocale }) ] }), step >= 2 && step <= TOTAL_STEPS && /*#__PURE__*/ _jsx("div", { className: "text-center mt-4", children: /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setStep(step + 1), className: "text-sm text-white/50 hover:text-white/80 transition", children: t('specialist_setup.skip') }) }) ] }) }); } `   6/opt/canhelp/apps/web/src/app/specialist-setupF ~  G9beba116abc2ee05 HI   ` StepIndicatorStep1WelcomeStep2ProfileStep3CardStep4SkillsStep5GeographyStepDoneNavButtonsTOTAL_STEPSSpecialistSetupPage EyB/opt/canhelp/apps/web/src/app/specialist-setup/page.tsx !pJ yB`J yB386cb8af793ff7aa `  d a=| b=| `}@ `4 A `, A `( A5 `- A6W `!c A @`'@`F0 A @`'@`a_ A @`@`>0 A @`@`Y A Aڊ @@J @ b=|DD `4EE `,GG `(HH `- `!  A    b   A  || c16  AAE  xx c"&  A  tt c>B  A  pp c48  A!%  ll c!/!3  Ach   ygg c**  A  cc c--  Ag l   __ c/(/-  A   [[ c9&9*  A   WW c<&<*  Az ~   SS cDD  A1 5   OO cHH  A   KK cLL yz A  GG cPP {| ASW  CC cS"S& wx A04  ?? cW"W& mn A  ;; c_7_< op A  77 cb2b6 ef A  33 cll  A   @ cyy"   A   czz&    A   c{ {(  A   c|&|.  AGO   c}&}.  Alr   c~~ (' A   c7@  A  A   @@`  A7B  A7:   @`@`  A  A     @`@` 56 ABG   @`@` 78 A   @`@` 34 A59   @`@` )* A   @`@` +, AS W    @`"@`& !" A0!5!   @`"@`' #$ A!!   @`*@`.   A""   @`D@`H  A##   @`3@`8  A`%d%   @`6@`:  A,&0&   @`6@`:    A''   @`*@`/    A( (   @`2@`6  Aq*u*   @`2@`6  A++   @`*@`.  Ao-t-   @`@`  A--   @`"@`&  A..   @`"@`&  A00   @`@`  A91=1   @ `"@ `&  A 2$2   @`"@`&  A33   @`@`  AO5W5   ee @#`@#`&  Ay55  aa @$`@$`$  A55  ]] @%` @%`(  A55  YY @&`@&`&  A66  A66   @/`@/`7  A77   @9`@9`  A68:8   @;`@;`  A88   @?`@?`  A99   @C`@C`  A ::   @F`"@F`&  A::   @J`"@J`&  AI=M=  }} @T`+@T`/  A>>  yy @Z`@Z`  A>>  uu @]`"@]`&  Af?j?  qq @a`"@a`&  AnArA  mm @k`@k` ML ABB   z## @v` @v`( HG ACC   @w`(@w`0 DC AGCOC   @x`(@x`0 @? ACC   @y`.@y`6 <; ACC   @z`*@z`2 87 ACD   @{` @{`( ba AEDND     @|`7@|`@ o3 A]DnD  A]D`D  QQ @}@}` YX ADD   @`7@`@ * AD E  ADD  HH @@` % AHH  AHH  CC @`@`* kl AnIsI  99 @`@` mn AII  55 @`@` ij AaJeJ  11 @`@` _` AKK  -- @`@` ab AKK  )) @`"@`& ]^ A|LL  %% @`7@`; ST A MM  !! @`@@`E UV AN#N   @`2@`6 KL APP   @`"@`' MN APP   @`*@`. IJ ASS   @`*@`. EF A~UU     @`<@`@ ;< AVV     C 78 AXX   @`@` 9: AJYNY   @`"@`& 56 A6Z:Z   @`"@`& +, A \\   @`1@`6 '( Az\\   @`2@`7 )* AX]\]   @`:@`>   AO_T_   @`:@`? !" AI`M`   @ `N@ `R  A^bbb  | @`I@`M  Acc  x @`A@`F  Add  t @`B@`F  Aff  p @`B@`F   A%i)i  l @-`@-`  Ajj    @8`&@8`.  Ajj   @9`,@9`4  Akk   @:` @:`(  AOkXk   @;`7@;`@  Agkwk  Agkjk   @<@<`  Amm  Amm   @R`@R`*  Ann   @Z`@Z`  Ann   @\`@\`  Aoo   @``@``  AGpKp   @d`@d`  App   @h`@h`  Arr   @n`)@n`.  As s   @p`*@p`/  Ass   @s`2@s`6  Auu   @y`2@y`6  Avv   @`B@`F  Axx   @`9@`>  Axx   @`:@`>  Azz   @`:@`>  A||   @`@`  A~ ~   }} @`@`  Al~p~  yy @`@`  A  uu @`(@`,  A  qq @`,@`0  A  mm @`@`  AɁ́  ii @`@`  A{  ee @`@`  AEJ  aa @`@`  A߃  ]] @`"@`&  A"  YY @`"@`&  A   fTT @`@`  Ax}  PP @`@`  A  LL @`@`\ @@J !  A3=   X @`)@`3  AT]   @`@`  A{   @`@`#  A   @`@`$  A͋Ջ   @`@`$ DC Abk   @`7@`@ fg A  .. @`@`! bc AMQ  ** @`@` XY A  && @` @`% TU A  "" @`@`# VW A   @ `&@ `* RS A   @`1@`5 NO A   @`)@`- DE Arw   @`@`# FG A-1   @`0@`4 BC A     @`4@`8 >? Aim   @#`4@#`8 :; AW[   @(`4@(`8 67 Avz   @.`4@.`8 23 A   @5`4@5`8 ./ A>B   @>`B@>`F *+ A   @@`,@@`0  /* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState, useEffect, useRef } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { useLocation } from '@/context/location'; import { createTask, getCategories, getLocations, getSpecialists } from '@/lib/api'; import { formatShortName } from '@/lib/formatName'; import { formatLastSeen } from '@/lib/formatLastSeen'; import { TaskLocationPicker } from '@/components/TaskLocationPicker'; import { TaskCategoryPicker } from '@/components/TaskCategoryPicker'; import { TurnstileWidget } from '@/components/Turnstile'; import { CAPTCHA_ENABLED } from '@/components/Turnstile'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const localISO = (d)=>{ const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; }; export default function CreateTaskPage() { const { data: session, isPending } = useSession(); const router = useRouter(); const searchParams = useSearchParams(); const preselectedCategory = searchParams.get('category') ?? ''; const { t, locale } = useLocale(); const [categories, setCategories] = useState([]); const [locations, setLocations] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [topSpecialists, setTopSpecialists] = useState([]); const [deadline, setDeadline] = useState(()=>{ const d = new Date(); d.setDate(d.getDate() + 1); return localISO(d); }); const [calendarMonth, setCalendarMonth] = useState(()=>{ const d = new Date(); d.setDate(d.getDate() + 1); return localISO(d).slice(0, 7); }); const calendarInputRef = useRef(null); const [specialistAvailMap, setSpecialistAvailMap] = useState({}); const [invitedIds, setInvitedIds] = useState(new Set()); const [captchaToken, setCaptchaToken] = useState(CAPTCHA_ENABLED ? '' : 'dev'); const { locationSlug: ctxLocation } = useLocation(); const [selectedLocation, setSelectedLocation] = useState(''); const [selectedCategory, setSelectedCategory] = useState(preselectedCategory); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (ctxLocation) setSelectedLocation(ctxLocation); }, [ ctxLocation ]); const [images, setImages] = useState([]); const [photoUploading, setPhotoUploading] = useState(false); const fileInputRef = useRef(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); getCategories().then(setCategories).catch(()=>{}); getLocations().then(setLocations).catch(()=>{}); }, [ session, isPending ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!selectedCategory) { setTopSpecialists([]); return; } getSpecialists({ limit: '5', category: selectedCategory }).then((r)=>setTopSpecialists(r.data)).catch(()=>{}); }, [ selectedCategory ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!deadline || topSpecialists.length === 0) return; const month = deadline.slice(0, 7); const ids = topSpecialists.map((u)=>u.id); Promise.all(ids.map((id)=>fetch(`${API}/api/availability/user/${id}?month=${month}`, { credentials: 'include' }).then((r)=>r.ok ? r.json() : []).then((rows)=>{ const row = rows.find((r)=>r.date === deadline); return { id, status: row?.status ?? null }; }).catch(()=>({ id, status: null })))).then((results)=>{ const map = {}; results.forEach(({ id, status })=>{ map[id] = status; }); setSpecialistAvailMap(map); }); }, [ deadline, topSpecialists ]); async function handlePhotoChange(e) { const file = e.target.files?.[0]; if (!file) return; setPhotoUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${API}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); setImages((prev)=>[ ...prev, `${API}${url}` ]); } catch { setError(t('profile.upload.error')); } finally{ setPhotoUploading(false); if (fileInputRef.current) fileInputRef.current.value = ''; } } async function handleSubmit(e) { e.preventDefault(); setError(''); setLoading(true); const form = new FormData(e.currentTarget); const data = { title: form.get('title'), description: form.get('description'), category: form.get('category') || undefined, location: form.get('location') || undefined, budget: form.get('budget') ? Number(form.get('budget')) : undefined, budgetNegotiable: form.get('budgetNegotiable') === 'on', deadline: form.get('deadline') ? new Date(form.get('deadline')).toISOString() : undefined, timeSlot: form.get('timeSlot') || undefined, district: form.get('district') || undefined, street: form.get('street') || undefined, houseNumber: form.get('houseNumber') || undefined, confidentialNote: form.get('confidentialNote') || undefined, images: images.length > 0 ? images : undefined, status: 'open', locale: locale, inviteSpecialistIds: invitedIds.size > 0 ? [ ...invitedIds ] : undefined }; try { const task = await createTask({ ...data, captchaToken }); router.push(`/tasks/${task.id}`); } catch (err) { setError(err.message || t('create.error')); } finally{ setLoading(false); } } if (isPending) return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const dateLocale = locale === 'ru' ? 'ru-RU' : locale === 'en' ? 'en-US' : 'el-GR'; const todayMidnight = new Date(); todayMidnight.setHours(0, 0, 0, 0); const [cmYear, cmMonth] = calendarMonth.split('-').map(Number); const daysInMonth = new Date(cmYear, cmMonth, 0).getDate(); const calendarDates = []; for(let day = 1; day <= daysInMonth; day++){ const d = new Date(cmYear, cmMonth - 1, day); if (d >= todayMidnight) calendarDates.push(d); } const monthOptions = Array.from({ length: 12 }, (_, i)=>{ const d = new Date(); d.setDate(1); d.setMonth(d.getMonth() + i); return { value: localISO(d).slice(0, 7), label: d.toLocaleDateString(dateLocale, { month: 'long', year: 'numeric' }) }; }); const sidebarTitle = t('tasks.new.top_specialists'); return /*#__PURE__*/ _jsxs("div", { className: "max-w-5xl mx-auto px-3 sm:px-4 py-6 sm:py-8", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-xl sm:text-2xl font-bold text-white mb-4 sm:mb-6", children: t('create.title') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col lg:flex-row gap-6 lg:gap-8 items-start", children: [ /*#__PURE__*/ _jsx("div", { className: "flex-1 min-w-0 w-full", children: /*#__PURE__*/ _jsxs("form", { onSubmit: handleSubmit, className: "bg-white rounded-xl border border-gray-200 p-4 sm:p-6 space-y-4 sm:space-y-5", children: [ error && /*#__PURE__*/ _jsx("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.category') }), /*#__PURE__*/ _jsx(TaskCategoryPicker, { categories: categories, locale: catLocale, value: selectedCategory, onChange: setSelectedCategory, placeholder: t('create.field.category.select') }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.location') }), /*#__PURE__*/ _jsx(TaskLocationPicker, { locations: locations, value: selectedLocation, onChange: setSelectedLocation, anyLabel: t('create.field.location.any'), allLabel: t('create.field.location.all') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.title'), " ", /*#__PURE__*/ _jsx("span", { className: "text-red-500", children: "*" }) ] }), /*#__PURE__*/ _jsx("input", { name: "title", required: true, minLength: 5, maxLength: 200, placeholder: t('create.field.title.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.description'), " ", /*#__PURE__*/ _jsx("span", { className: "text-red-500", children: "*" }) ] }), /*#__PURE__*/ _jsx("textarea", { name: "description", required: true, minLength: 20, rows: 4, placeholder: t('create.field.description.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.budget') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-3", children: [ /*#__PURE__*/ _jsx("input", { name: "budget", type: "number", min: 1, step: 1, placeholder: t('create.field.budget.placeholder'), className: "w-full sm:flex-1 border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer select-none", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", name: "budgetNegotiable", className: "w-4 h-4 rounded border-gray-300 text-blue-600" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-700", children: t('create.field.budget_negotiable') }) ] }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-2", children: [ /*#__PURE__*/ _jsx("label", { className: "text-sm font-medium text-gray-700 shrink-0", children: t('create.field.deadline') }), /*#__PURE__*/ _jsx("select", { value: calendarMonth, onChange: (e)=>setCalendarMonth(e.target.value), className: "flex-1 border border-gray-300 rounded-lg px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400", children: monthOptions.map((mo)=>/*#__PURE__*/ _jsx("option", { value: mo.value, children: mo.label }, mo.value)) }), /*#__PURE__*/ _jsx("button", { type: "button", title: "Открыть календарь", onClick: ()=>{ try { calendarInputRef.current?.showPicker(); } catch { calendarInputRef.current?.click(); } }, className: "shrink-0 w-8 h-8 flex items-center justify-center rounded-lg border border-gray-300 text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: /*#__PURE__*/ _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [ /*#__PURE__*/ _jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), /*#__PURE__*/ _jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), /*#__PURE__*/ _jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), /*#__PURE__*/ _jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" }) ] }) }), /*#__PURE__*/ _jsx("input", { ref: calendarInputRef, type: "date", min: localISO(todayMidnight), value: deadline, onChange: (e)=>{ if (!e.target.value) return; setDeadline(e.target.value); setCalendarMonth(e.target.value.slice(0, 7)); }, className: "absolute w-0 h-0 opacity-0 pointer-events-none" }) ] }), /*#__PURE__*/ _jsx("div", { className: "flex gap-2 overflow-x-auto pb-1 snap-x snap-mandatory", children: calendarDates.map((d)=>{ const iso = localISO(d); const isSelected = deadline === iso; const dayName = d.toLocaleDateString(dateLocale, { weekday: 'short' }); const dayNum = d.getDate(); return /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setDeadline(iso), className: `flex-shrink-0 snap-start flex flex-col items-center justify-center w-14 h-16 rounded-xl border-2 transition select-none ${isSelected ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-200 bg-white text-gray-700 hover:border-blue-300 hover:bg-gray-50'}`, children: [ /*#__PURE__*/ _jsx("span", { className: "text-xs font-medium uppercase leading-none mb-0.5", children: dayName }), /*#__PURE__*/ _jsx("span", { className: "text-xl font-bold leading-none", children: dayNum }) ] }, iso); }) }), /*#__PURE__*/ _jsx("input", { type: "hidden", name: "deadline", value: deadline }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.time_slot') }), /*#__PURE__*/ _jsxs("select", { name: "timeSlot", className: "w-full border border-gray-300 rounded-lg px-3 py-2", children: [ /*#__PURE__*/ _jsx("option", { value: "", children: t('create.field.time_slot.any') }), /*#__PURE__*/ _jsx("option", { value: "morning", children: t('create.field.time_slot.morning') }), /*#__PURE__*/ _jsx("option", { value: "afternoon", children: t('create.field.time_slot.afternoon') }), /*#__PURE__*/ _jsx("option", { value: "evening", children: t('create.field.time_slot.evening') }), /*#__PURE__*/ _jsx("option", { value: "weekend", children: t('create.field.time_slot.weekend') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('create.field.address') }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-2 sm:gap-3", children: [ /*#__PURE__*/ _jsx("input", { name: "district", placeholder: t('create.field.address.district'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("input", { name: "street", placeholder: t('create.field.address.street'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("input", { name: "houseNumber", placeholder: t('create.field.address.house'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('create.field.photos') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-2 mb-2", children: [ images.map((url, i)=>/*#__PURE__*/ _jsxs("div", { className: "relative w-20 h-20 rounded-lg overflow-hidden border border-gray-200", children: [ /*#__PURE__*/ _jsx("img", { src: url, alt: "", className: "w-full h-full object-cover" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setImages((prev)=>prev.filter((_, j)=>j !== i)), className: "absolute top-0.5 right-0.5 bg-black/50 text-white rounded-full w-5 h-5 flex items-center justify-center text-xs hover:bg-black/70", children: "\xd7" }) ] }, i)), images.length < 5 && /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>fileInputRef.current?.click(), disabled: photoUploading, className: "w-20 h-20 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400 hover:border-blue-400 hover:text-blue-400 text-xs disabled:opacity-50", children: photoUploading ? '...' : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("span", { className: "text-2xl leading-none", children: "+" }), /*#__PURE__*/ _jsx("span", { children: t('create.field.photos.add') }) ] }) }) ] }), /*#__PURE__*/ _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", className: "hidden", onChange: handlePhotoChange }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.confidential'), /*#__PURE__*/ _jsxs("span", { className: "ml-2 text-xs font-normal text-gray-400", children: [ "\uD83D\uDD12 ", t('create.field.confidential.hint') ] }) ] }), /*#__PURE__*/ _jsx("textarea", { name: "confidentialNote", rows: 2, placeholder: t('create.field.confidential.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsx(TurnstileWidget, { onSuccess: setCaptchaToken, onError: ()=>setCaptchaToken(''), onExpire: ()=>setCaptchaToken('') }), /*#__PURE__*/ _jsx("button", { type: "submit", disabled: loading || !captchaToken, className: "w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed", children: loading ? t('create.submitting') : t('create.submit') }) ] }) }), /*#__PURE__*/ _jsx("aside", { className: "hidden lg:block lg:w-64 shrink-0", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5 sticky top-24", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-900 mb-4 text-sm", children: sidebarTitle }), !selectedCategory ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 text-center py-4", children: t('tasks.new.select_category') }) : topSpecialists.length === 0 ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 text-center py-4", children: t('specialists.empty') }) : /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: topSpecialists.map((u)=>{ const name = formatShortName(u.firstName, u.lastName, u.name); const initials = `${u.firstName?.[0] ?? ''}${u.lastName?.[0] ?? ''}`.toUpperCase() || u.name?.[0]?.toUpperCase() || '?'; const seen = formatLastSeen(u.lastSeenAt, t); const avail = specialistAvailMap[u.id]; const isInvited = invitedIds.has(u.id); return /*#__PURE__*/ _jsxs("div", { className: "rounded-lg border border-gray-100 hover:bg-gray-50 transition", children: [ /*#__PURE__*/ _jsxs(Link, { href: `/users/${u.id}`, target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-3 p-2", children: [ /*#__PURE__*/ _jsx("div", { className: "w-12 h-12 rounded-full bg-blue-100 flex-shrink-0 flex items-center justify-center text-blue-700 font-bold text-sm overflow-hidden border border-gray-100", children: u.image ? /*#__PURE__*/ _jsx("img", { src: u.image, alt: name, className: "w-full h-full object-cover" }) : initials }), /*#__PURE__*/ _jsxs("div", { className: "min-w-0 flex-1", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: name }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-1.5 flex-wrap", children: [ u.rating ? /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-500", children: [ "★ ", Number(u.rating).toFixed(1) ] }) : seen ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400", children: seen }) : null, typeof u.reviewCount === 'number' && u.reviewCount > 0 && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-400", children: [ u.reviewCount, " ", t('reviews.count') ] }), typeof u.positivePercent === 'number' && u.reviewCount > 0 && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-green-600", children: [ u.positivePercent, "% \uD83D\uDC4D" ] }), avail === 'available' && /*#__PURE__*/ _jsxs("span", { className: "inline-flex items-center gap-0.5 text-xs font-medium text-green-700 bg-green-100 px-1.5 py-0.5 rounded-full", children: [ /*#__PURE__*/ _jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-green-500 inline-block" }), t('schedule.available') ] }), avail === 'busy' && /*#__PURE__*/ _jsxs("span", { className: "inline-flex items-center gap-0.5 text-xs font-medium text-red-700 bg-red-100 px-1.5 py-0.5 rounded-full", children: [ /*#__PURE__*/ _jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-red-500 inline-block" }), t('schedule.busy') ] }) ] }) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "px-2 pb-2", children: /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setInvitedIds((prev)=>{ const next = new Set(prev); if (next.has(u.id)) next.delete(u.id); else next.add(u.id); return next; }), className: `w-full text-xs font-medium py-1 rounded-lg transition ${isInvited ? 'bg-blue-600 text-white hover:bg-blue-700' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`, children: isInvited ? t('tasks.new.invited') : t('tasks.new.invite') }) }) ] }, u.id); }) }) ] }) }) ] }) ] }); } ` KL  Mg/opt/canhelp/apps/web/src/app/tasks/neww   x240f89a542bbde09 yz   APIlocalISOCreateTaskPage EyB/opt/canhelp/apps/web/src/app/tasks/new/page.tsx !NyBNyB01674a403543b1bf ` d `=@ a=@ A `4 A `= A$ ` A%M `( AN{ `- A| `1 A `T A6 `3 A7m `6 An c E A c E A3 c 9 A4m c9 Az c +0 A c F A A~ a@ @ a=@pp `4qq `= `rr `(ss `-@/context/location `1 `T rr `3 @/lib/formatLastSeen `6` @/components/TaskLocationPicker c E` @/components/TaskCategoryPicker c E` @/components/Turnstile c 9` c9 Az  cF a@ vu A   [[ c)3 fe A  TT c hg A(  PP c( nm A  QQ c# on A  FF c(0 kj A  BB c&. gf A#+  >> c"* cb ARZ  :: c& _^ A  66 c 0 8 [Z A  22 c!$!, WV Aem  .. c&.&6 ts A   ** c++# ON AIQ  && c,8,@ KJ A  "" c-(-0 GF A   c.,.4 CAPTCHA_ENABLED A 4` c.5.D useLocation A     c/*/5 98 AU ]    c040< 54 A      c141< _^ A    c272@ -, A}    c7 7( )( A    c8088 FE A    c99 ON A* 3    c:7:@ \[ A}   ?? c<< ]\ A   ;; c== CB AT ]    cB7B@ *) A   33 cGG ;: A    cN7N@  Ajt  ++ @`@`) YZ A  !! @`(@`, OP A   @`@` QR A  } @`@` GH AN S   y @`@` IJ A   u @`"@`& ?@ Ah!m!  q   @`0@`5 AB A""  m   @`7@`; 78 Av#{#  i @`.@`3 34 AL$Q$  e @`6@`; 56 A$$  a @`>@`B 12 A&&  ] @`>@`B TaskCategoryPicker A &2& 4X` LL @`C@`U "# A((  T @`6@`; $% A))  P @`>@`B  ! A^*b*  L @`>@`B TaskLocationPicker Ac*u* 4G` 99 @`C@`U  A"-'-  C @`.@`3   A--  ? @`6@`;  A//  ; @`>@`B    Af0j0  7 @`6@`:  A3 3  3 @`.@`3  Ay3~3  / @`6@`;  A44  + @`>@`B  AN6R6  ' @`6@`:  A99  # @)`.@)`3  Av9z9   @+`6@+`:  A::   @/`6@/`;  A;;   @2`>@2`B  A2>7>   @:`>@:`C  A@?D?   @=`F@=`J  A@@    @B`F@B`J  A;C@C   @L`.@L`3  ACC   @N`6@N`;  ADD   @Q`>@Q`B  AEE   @U`>@U`B  AGG   @Y`c@Y`g  AII   @^`>@^`B  ALL   @i`L@i`Q  AEOIO   @q`J@q`N  AQQ   @y`J@y`N  AXS\S   @`J@`N  AUU  {{ @`J@`N  AkWoW  ww @`>@`B  A^[b[  ss @`6@`:  A6^;^  oo @`E@`J  A``  kk @`F@`J  Ab b  gg @`F@`J  Ad d  cc @`6@`:  Apeue  __ @`.@`3  Aee  [[ @`6@`:  Agg  WW @`6@`;  AChGh  SS @`>@`B  Acigi  OO @`>@`B  Ajj  KK @`>@`B  Akk  GG @`>@`B {| All  CC @`>@`B qr Ann  ?? @`.@`3 st Aoo  ;; @`6@`: ij ACpHp  77 @`6@`; kl A1q5q  33 @`>@`B gh As s  // @`>@`B cd Att  ++ @`>@`B YZ AAwFw  '' @`.@`3 [\ Aww  ## @`6@`: QR Axx   @`6@`; MN Ayy   @`S@`X OP Azz  { @`J@`N KL A||  w @ `J@ `N GH A  s @`S@`W => A  o   @`e@`j st A 4k @`k@`t ;< A  g @`J@`N 78 A߃  c @`J@`N 34 Aȅ̅  _ @'`6@'`: )* A  [ @0`.@0`3 %& A16  W @2`6@2`; !" Aot  S @6`>@6`C #$ AƋʋ  O @?`6@?`:   A  K @G`.@G`2 TurnstileWidget A$ 4F` << @G`3@G`B  AFJ  B @L`.@L`2  A}  > @U`"@U`&   A   : @W`0@W`5    AВԒ  6 @Z`.@Z`2  Aٓݓ  2 @^`B@^`F  Aܔ  . @a`Q@a`U  A  * @d`3@d`7 +* A  &  @g`5@g`D formatLastSeen A  !  @i`5@i`C  A   @l`=@l`B  A   @o`>@o`C 3 A 4 @o`D@o`H  AW[   @u`F@u`J  A    @w`^@w`b  A    @}`F@}`K  A   @`N@`R  A   @`N@`S  A#(   @`a@`f  Ajn   @`b@`f  A$)   C  A>C   C  A   @`o@`t  Amq   @`^@`b  AЯկ   @`j@`o  AX\  }} @`^@`b  A  yy @`>@`B  A  uu @`L@`P   /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { getTranslations } from '@/lib/translations'; const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ createContext({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } export function LocaleProvider({ children, initialLocale }) { const router = useRouter(); const [locale, setLocaleState] = useState(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = useCallback((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = useCallback((key, fallback)=>getTranslations(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ _jsx(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } export function useLocale() { return useContext(LocaleContext); } `  /opt/canhelp/apps/web/src/context 2  45678836c8699b0c3a935   A readCookieLocaleCOOKIE_KEYDEFAULT_LOCALELocaleContextLocaleProvider? EyB/opt/canhelp/apps/web/src/context/locale.tsx B!`fyBPfyBa87dc9e560a3dfb8 `  d aN~ bN~ `@ `T A `, A6 `5 A%  A  cJ A   A   cKM A; c70 A?V cR A c//70 A  c//R `DD bN~ `T `,II `5 createContext A   b$1 cJ  Aox    c  A   c%- @? A2;   c7@ fe A   c**! ba A    c?? @? A   ** c?+?: VW A1 5    cBB cKM useContext A     cL L   ` or s       @7     -2 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopq EyBrt @ d Ab  A[  a A_ AX c A A c  A A c!!] A A c""3 A A c#& A A c''P A 9 A9 c((5 AA A: c), A6 A6 c-0 A> A7 c13 A A c46 AS  AL  c88G A  A  c995 A D  A D  c:= AL  AE  c>@ A  A  cAC A Q  A Q  cDDD AY  AR  cEH A j  A j  cIL Ar  Ak  cMMK A  A  cNN7 AE u  A> u  cPP7 A}  Av  cQQQ A  A  cRRN Af Af cSSO An Ag cTZ Ar Ak c\_ A/ A/ c``> A7r A0r caaB Az As cbd A; A; ceg AC A< chhh A A cik Af A_ cmmC A< A< cooK AD A= cppQ A A crr8 Ak Ad ctt6 A A cvv6 A' A  cwy A A cz| A= A= c}}L AE A> a~@ AR AR @@ A4 A4 @@`C A< A5 @@ AO AO @@ AW AP @@ AB A B @@`9 AJ; AC; @@ AC A< @@ A A @@ A A @@ A A @@`@ A j Aj @@`h Ar Ak @@ A A @@ A A @@ A  A  @@ A  A  @@ A  A  @@ A C! A C! @@`[ AK!! AD!! @@ A"U" A!U" @@`Z A]"$ AV"$ @@ A$% A$% @@ A%' A%' @@ A%'i' A'i' @@`K Aq'' Aj'' @@`B A(=( A'=( @@`A AE(( A>(( @@ A(V) A(V) @@ A^)) AW)) @@ A*H* A*H* @@`9 AP** AI** @@ A*Q+ A*Q+ @@ AY++ AR++ @@ A ,A, A,A, @@`? AI,, AB,, @@  A,- A,- @ @ `O A#-- A-- @ @ A-g. A-g. @@ Ao.. Ah.. @@ A&// A// @@`g A/[0 A/[0 @@  Ac071 A\071 @!@( A?11 A811 @)A) A11 A11 @*@*`; A13 A13 @+@7 A334 A334 @8@; A;44 A444 @<@> A44 A44 @?@?`U A4:5 A4:5 @@@@`H AB55 A;55 @A@D A5a6 A5a6 @E@H Ai66 Ab66 @I@K A6*7 A6*7 @L@L`X A278 A+78 @M@P A88 A88 @Q@V A88 A88 @W@W`B A9`9 A8`9 @X@X`c Ah9: Aa9: @Y@` A:O; A:O; @a@d AW;; AP;; @e@h A;< A;< @i@n A<= A<= @o@r A=S= A=S= @s@s`; A[== AT== @t@t`? A=n> A=n> @u@{ A>> A>> @}@}`9 A>? A>? @~@ A?@ A?@ @@`E A @@ A@@ @@ A@,A A@,A @@`J A4AsA A-AsA @@`F A{AA AtAA @@`K AB]B AB]B @@`N AeBB A^BB @@ ACcC ACcC @@`N AkCC AdCC @@ ACID ACID @@ AQDD AJDD @@`U AD:E AD:E @@`K ABE{E A;E{E @@`@ AEE A|EE @@` AVFF AOFF @@`Hu A a @0 AY @@T A bKj0 A a+@v A `I `ii aii c c hh c!!]hh c""3hh c#&hh c''Phh c((5hh c),hh c-0hh c13hh c46hh c88Ghh c995hh c:=hh c>@hh cAChh cDDDhh cEHhh cILhh cMMKhh cNN7hh cPP7hh cQQQhh cRRNhh cSSOhh cTZhh c\_hh c``>hh caaBhh cbdhh ceghh chhhhh cikhh cmmChh cooKhh cppQ{{ crr8 ctt6ff cvv6ff cwyff cz|ff c}}Lff a~@ff @@ff @@`Cff @@ff @@ff @@ff @@`9ff @@ff @@ff @@ff @@ff @@`@ff @@`hff @@ff @@ff @@ff @@ff @@ff @@ff @@`[ff @@ff @@`Zff @@ff @@ff @@ff @@`Kff @@`Bff @@`Aff @@ff @@ff @@ff @@`9ff @@ff @@ff @@ff @@`?ff @@ ff @ @ `Off @ @ff @@ff @@ff @@`gff @@ ff @!@(ff @)A)ff @*@*`;ff @+@7ff @8@;ff @<@>ff @?@?`Uff @@@@`Hff @A@Dff @E@Hff @I@Kff @L@L`Xff @M@Pff @Q@Vff @W@W`Bff @X@X`cff @Y@`ff @a@dff @e@hff @i@nff @o@rff @s@s`;ff @t@t`?ff @u@{ff @}@}`9ff @~@ff @@`Eff @@ff @@`Jff @@`Fff @@`Kff @@`Nff @@ff @@`Nff @@ff @@ff @@`Uff @@`Kff @@`@ff @@`ff @@`H  u)/* __next_internal_client_entry_do_not_use__ TaskListClient auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState } from 'react'; import Link from 'next/link'; import { useLocale } from '@/context/locale'; import { getTranslations } from '@/lib/translations'; import { taskTitle, taskDescription, formatPrice } from '@/lib/taskLocale'; import { shortName } from '@/lib/formatName'; const BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function TaskListClient({ initialTasks, initialTotal, filterParams, locale: localeProp, catMap, locMap, mode = 'all' }) { const { locale } = useLocale(); const t = getTranslations(locale); const [tasks, setTasks] = useState(initialTasks); const [total] = useState(initialTotal); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const hasMore = tasks.length < total; async function loadMore() { setLoading(true); try { const nextPage = page + 1; const params = new URLSearchParams({ ...filterParams, page: String(nextPage), limit: '10' }); const endpoint = mode === 'for_me' ? '/tasks/for-me' : '/tasks'; const res = await fetch(`${BASE}/api${endpoint}?${params}`, { credentials: 'include' }); const json = await res.json(); setTasks((prev)=>[ ...prev, ...json.data || [] ]); setPage(nextPage); } finally{ setLoading(false); } } if (tasks.length === 0) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white/70", children: /*#__PURE__*/ _jsx("p", { className: "text-lg", children: t('tasks.empty') }) }); } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("div", { className: "space-y-4", children: tasks.map((row)=>{ const task = row.task || row; const customer = row.customer; return /*#__PURE__*/ _jsx(Link, { href: `/tasks/${task.id}`, className: "block bg-white rounded-xl border border-gray-200 p-5 hover:shadow-md hover:border-blue-300 transition", children: /*#__PURE__*/ _jsxs("div", { className: "flex justify-between items-start gap-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-2", children: [ /*#__PURE__*/ _jsx("span", { className: "text-xs font-medium text-blue-600 bg-blue-50 px-2 py-0.5 rounded-full", children: task.category ? catMap[task.category] ?? task.category : t('tasks.category.general') }), task.location && /*#__PURE__*/ _jsxs("span", { className: "text-xs text-gray-500", children: [ "\uD83D\uDCCD ", locMap[task.location] ?? task.location ] }) ] }), /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-900 text-lg mb-1 truncate", children: taskTitle(task, locale) }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500 line-clamp-2", children: taskDescription(task, locale) }) ] }), /*#__PURE__*/ _jsxs("div", { className: "text-right shrink-0", children: [ task.budget ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("p", { className: "text-lg font-bold text-green-600", children: [ formatPrice(task.budget), "€" ] }), task.budgetNegotiable && /*#__PURE__*/ _jsx("p", { className: "text-xs text-green-600", children: t('task.budget_negotiable') }) ] }) : task.budgetNegotiable ? /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-green-600", children: t('task.budget_negotiable') }) : null, /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-600 mt-1", children: [ /*#__PURE__*/ _jsxs("span", { className: "text-gray-500", children: [ task.deadline ? t('task.deadline') : t('task.created_at'), ": " ] }), new Date(task.deadline ?? task.createdAt).toLocaleDateString(locale === 'ru' ? 'ru-RU' : locale === 'en' ? 'en-US' : 'el-GR') ] }), customer && /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-end gap-1.5 mt-2", children: [ /*#__PURE__*/ _jsxs("div", { className: "text-right", children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 leading-none", children: shortName(customer.name) }), customer.rating && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-yellow-500 leading-none mt-0.5", children: [ "★ ", Number(customer.rating).toFixed(1) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "w-7 h-7 rounded-full overflow-hidden bg-blue-100 shrink-0 flex items-center justify-center", children: customer.image ? /*#__PURE__*/ _jsx("img", { src: customer.image, alt: shortName(customer.name), className: "w-full h-full object-cover" }) : /*#__PURE__*/ _jsx("span", { className: "text-blue-600 font-semibold text-xs", children: shortName(customer.name).charAt(0).toUpperCase() }) }) ] }) ] }) ] }) }, task.id); }) }), hasMore && /*#__PURE__*/ _jsx("div", { className: "flex justify-center mt-8", children: /*#__PURE__*/ _jsx("button", { onClick: loadMore, disabled: loading, className: "px-6 py-2.5 bg-white border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:border-blue-400 hover:text-blue-600 disabled:opacity-50 transition", children: loading ? t('common.loading') : t('tasks.load_more') }) }) ] }); } ` [\  ]w_   40eb0d4529f0b218    ~ EyB/opt/canhelp/apps/web/src/app/tasks/TaskListClient.tsx ! fyBfyB7f97ca44bc313752 `  d `D@ aD@ A `! A ` A `- A > `5 A? `K A `- A p) Ap) @ A b ,0 A b G `3 aD@ `! ` `- `5@/lib/taskLocale `K `- A W `GUU @  A   Q b   A   c    A  {{ c  &  A   ww c    ALT  ss c$  A{  oo c"*  A   c))!  ACG   c+$+(  A   c11  A   c33  A    c8)8-  A   4 c8.82  A    c;0;5  A    c>.>3  Ap u    cA6A;  AL P    cD>DB  A    cHOHT  ABF   cQ6Q: taskTitle A   cS6S?  Ako  {{ cU6U: taskDescription A    cW6WE  A  rr c[.[3  A  nn c^D^I  A 4jj c^J^S  A"  ff c`>`C formatPrice A   cc8cC  A   ]] cgWg[  A  YY clSlW  A  UU cp6p;  A  QQ cs>sC  A  MM c}B}G {| Ay~  II @`>@`C }~ A[_  |EE @`F@`J shortName A#  w @`F@`O no A  s<< @`Y@`^ pq A]"a"  o88 @`>@`B lm Ae#i#  k44 @`]@`a  A#$  g @`=@`F de A$$  c,, @`G@`K  Ay%%  _ @`B@`K \] AX'\'  [$$ @`%@`) XY A''  W   @`(@`,  z/* __next_internal_client_entry_do_not_use__ Footer auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useLocale } from '@/context/locale'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { SocialIcons } from './SocialIcons'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Footer() { const { t } = useLocale(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = useState({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ _jsx("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ _jsx("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ _jsx("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ _jsxs("ul", { className: "space-y-2", children: [ /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ _jsx(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); } ` yz  {/opt/canhelp/apps/web/src/components   11e240092644d6b5    .Footer EyB/opt/canhelp/apps/web/src/components/Footer.tsx !NyBNyBf14695e1ce613064  d a<{ b<{ `|@ `- A `, A ` A! `, Aqy Ajy ar A.M b +0 AQh b F `% b<{ `- `, `./SocialIcons `, A.h  `F ar  A    b  A   b* 2  A>G   c 7 @  A   c    A   c %   A   c#  AZ_   c&+  A   c.2  A   c#.#2  A27   c)&)+  A   c,.,2  A    c0.03  A    c363:  A    c4D4H 4 A  4 c4I4M  AO S    c:6::  A    c;D;H) A  4 c;I;M  A$(   cA6A:  Auy   cBDBH Az~ 4 cBIBM  A    cH6H:  A\`   cIDIH Aae 4 cIIIM  AV[   cS&S+  A   cV.V2  A   cZ.Z2  A   c^.^2 SocialIcons A 4 c^3^>  A   xx cff#   import { createAuthClient } from 'better-auth/react'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export const authClient = createAuthClient({ baseURL: API_URL }); export const { signIn, signOut, signUp, useSession } = authClient; `  R 6  89:;<b1b9fb450fab2e4e   E ,signInsignOutsignUp@ EyB/opt/canhelp/apps/web/src/lib/auth.ts H!`fyBPfyBeca3d166f7d8d806  d `5 `5 A A  A  A  `B& aFe b/0 `i@ bJ better-auth/react `5  createAuthClient A   b* `B `B `B  `B  /* __next_internal_client_entry_do_not_use__ CAPTCHA_ENABLED,TurnstileWidget auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { Turnstile } from '@marsidev/react-turnstile'; const SITE_KEY = process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ?? ''; /** false in dev when NEXT_PUBLIC_TURNSTILE_SITE_KEY is not set */ export const CAPTCHA_ENABLED = !!SITE_KEY; export function TurnstileWidget({ onSuccess, onError, onExpire }) { if (!SITE_KEY) return null; return /*#__PURE__*/ _jsx(Turnstile, { siteKey: SITE_KEY, onSuccess: onSuccess, onError: onError, onExpire: onExpire, options: { theme: 'light', language: 'auto' } }); } `  )     webpack/DefinePlugin process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY "0x4AAAAAAC_FtTQJ0_6Cp9-9"beb826cbecddfa2a    SITE_KEYT EyB/opt/canhelp/apps/web/src/components/Turnstile.tsx !`fyBPfyBebc8fa295ab64b07  d `U@ aU@ A `6 AJm ACm bCm Au An a0 A bA A b; ## aU@@marsidev/react-turnstile `6 bCm99 a ST A   5 b Turnstile A 4 b'   sourcesruntimeRequirementsdatajavascriptwebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource ,webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TasksPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(56057); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(59902); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(75112); /* harmony import */ var _TaskListClient__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(70535); /* harmony import */ var _TaskFiltersClient__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34052); /* harmony import */ var _TasksAuthGuard__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(52386); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource"import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import Link from 'next/link'; import { cookies } from 'next/headers'; import { getCategories, getLocations, getTaskBudgetRange } from '@/lib/api'; import { getTranslations } from '@/lib/translations'; import { TaskListClient } from './TaskListClient'; import { TaskFiltersClient } from './TaskFiltersClient'; import { TasksAuthGuard } from './TasksAuthGuard'; const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export default async function TasksPage({ searchParams }) { const params = await searchParams; const page = Number(params.page || 1); const mode = params.mode === 'all' ? 'all' : 'for_me'; const cookieStore = await cookies(); const locale = cookieStore.get('canhelp_locale')?.value ?? 'el'; const cookieLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const t = getTranslations(locale); const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const cookieHeader = cookieStore.getAll().map((c)=>`${c.name}=${c.value}`).join('; '); let tasks = []; let total = 0; let noCards = false; let categories = []; let locationTree = []; let budgetRange = { min: 0, max: 0 }; const effectiveLocation = params.location ?? cookieLocation; const { q, category } = params; const rangeParams = {}; if (q) rangeParams.q = q; if (category) rangeParams.category = category; if (effectiveLocation) rangeParams.location = effectiveLocation; const effectiveParams = { page: String(page), limit: '10', ...params, ...effectiveLocation ? { location: effectiveLocation } : {} }; delete effectiveParams.mode; try { ; [categories, locationTree, budgetRange] = await Promise.all([ getCategories(), getLocations(), getTaskBudgetRange(Object.keys(rangeParams).length ? rangeParams : undefined) ]); } catch {} try { if (mode === 'for_me') { const forMeParams = new URLSearchParams(effectiveParams); const res = await fetch(`${API_BASE}/api/tasks/for-me?${forMeParams}`, { headers: { Cookie: cookieHeader }, cache: 'no-store' }); if (res.ok) { const json = await res.json(); if (json.noCards) { noCards = true; } else { tasks = json.data ?? []; total = json.total ?? 0; } } } else { const allParams = new URLSearchParams(effectiveParams); const res = await fetch(`${API_BASE}/api/tasks?${allParams}`, { headers: { Cookie: cookieHeader }, cache: 'no-store' }); if (res.ok) { const json = await res.json(); tasks = json.data ?? []; total = json.total ?? 0; } } } catch {} const catMap = {}; for (const cat of categories){ catMap[cat.slug] = cat.names[catLocale] ?? cat.names.el; for (const sub of cat.children ?? []){ catMap[sub.slug] = sub.names[catLocale] ?? sub.names.el; } } const locMap = {}; for (const city of locationTree){ locMap[city.slug] = city.names[catLocale] ?? city.names.el; for (const d of city.children ?? []){ locMap[d.slug] = d.names[catLocale] ?? d.names.el; } } const hasFilter = !!(params.q || params.category || params.location || params.budgetMin || params.budgetMax); const filterParams = {}; if (params.q) filterParams.q = params.q; if (params.category) filterParams.category = params.category; if (params.location) filterParams.location = params.location; if (params.budgetMin) filterParams.budgetMin = params.budgetMin; if (params.budgetMax) filterParams.budgetMax = params.budgetMax; return /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 py-8", children: [ /*#__PURE__*/ _jsx(TasksAuthGuard, {}), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row gap-8", children: [ /*#__PURE__*/ _jsx("aside", { className: "md:w-64 shrink-0", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5 sticky top-24", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-900 mb-4", children: t('tasks.filters') }), /*#__PURE__*/ _jsx(TaskFiltersClient, { categories: categories, locationTree: locationTree, budgetRange: budgetRange, initialMode: mode, initialQ: params.q, initialCategory: params.category, initialLocation: params.location, initialBudgetMin: params.budgetMin, initialBudgetMax: params.budgetMax }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsx("div", { className: "mb-6", children: /*#__PURE__*/ _jsx("h1", { className: "text-xl font-bold text-white", children: hasFilter ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ total, " ", t('tasks.title') ] }) : t('nav.tasks') }) }), noCards ? /*#__PURE__*/ _jsxs("div", { className: "bg-white/15 border border-white/30 rounded-xl p-8 text-center", children: [ /*#__PURE__*/ _jsx("div", { className: "text-4xl mb-3", children: "\uD83D\uDDC2️" }), /*#__PURE__*/ _jsx("p", { className: "text-white font-medium mb-2", children: t('find_tasks.no_cards') }), /*#__PURE__*/ _jsx(Link, { href: "/profile", className: "inline-block mt-2 px-5 py-2 bg-white text-blue-600 rounded-lg text-sm font-medium hover:bg-blue-50 transition", children: t('find_tasks.add_card') }) ] }) : /*#__PURE__*/ _jsx(TaskListClient, { initialTasks: tasks, initialTotal: total, filterParams: filterParams, locale: locale, catMap: catMap, locMap: locMap, mode: mode }, [ mode, params.q, params.category, params.location, params.budgetMin, params.budgetMax, page ].join('|')) ] }) ] }) ] }); } e%UWsu_ QS  hl_  JMgkmu(,D"https://api.canhelp.gr"0(0,next_headers__WEBPACK_IMPORTED_MODULE_2__/* .cookies */ .UL)(0,_lib_translations__WEBPACK_IMPORTED_MODULE_4__/* .getTranslations */ .$)(0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getCategories */ .bW)(0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getLocations */ .Vs)(0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getTaskBudgetRange */ .CC)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)_TasksAuthGuard__WEBPACK_IMPORTED_MODULE_7__.TasksAuthGuard_TaskFiltersClient__WEBPACK_IMPORTED_MODULE_6__.TaskFiltersClientreact_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment(next_link__WEBPACK_IMPORTED_MODULE_1___default())_TaskListClient__WEBPACK_IMPORTED_MODULE_5__.TaskListClient  buffersourcesizemapsR*__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TasksPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(56057); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(59902); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(75112); /* harmony import */ var _TaskListClient__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(70535); /* harmony import */ var _TaskFiltersClient__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34052); /* harmony import */ var _TasksAuthGuard__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(52386); const API_BASE = "https://api.canhelp.gr" || 0; async function TasksPage({ searchParams }) { const params = await searchParams; const page = Number(params.page || 1); const mode = params.mode === 'all' ? 'all' : 'for_me'; const cookieStore = await (0,next_headers__WEBPACK_IMPORTED_MODULE_2__/* .cookies */ .UL)(); const locale = cookieStore.get('canhelp_locale')?.value ?? 'el'; const cookieLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const t = (0,_lib_translations__WEBPACK_IMPORTED_MODULE_4__/* .getTranslations */ .$)(locale); const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const cookieHeader = cookieStore.getAll().map((c)=>`${c.name}=${c.value}`).join('; '); let tasks = []; let total = 0; let noCards = false; let categories = []; let locationTree = []; let budgetRange = { min: 0, max: 0 }; const effectiveLocation = params.location ?? cookieLocation; const { q, category } = params; const rangeParams = {}; if (q) rangeParams.q = q; if (category) rangeParams.category = category; if (effectiveLocation) rangeParams.location = effectiveLocation; const effectiveParams = { page: String(page), limit: '10', ...params, ...effectiveLocation ? { location: effectiveLocation } : {} }; delete effectiveParams.mode; try { ; [categories, locationTree, budgetRange] = await Promise.all([ (0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getCategories */ .bW)(), (0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getLocations */ .Vs)(), (0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getTaskBudgetRange */ .CC)(Object.keys(rangeParams).length ? rangeParams : undefined) ]); } catch {} try { if (mode === 'for_me') { const forMeParams = new URLSearchParams(effectiveParams); const res = await fetch(`${API_BASE}/api/tasks/for-me?${forMeParams}`, { headers: { Cookie: cookieHeader }, cache: 'no-store' }); if (res.ok) { const json = await res.json(); if (json.noCards) { noCards = true; } else { tasks = json.data ?? []; total = json.total ?? 0; } } } else { const allParams = new URLSearchParams(effectiveParams); const res = await fetch(`${API_BASE}/api/tasks?${allParams}`, { headers: { Cookie: cookieHeader }, cache: 'no-store' }); if (res.ok) { const json = await res.json(); tasks = json.data ?? []; total = json.total ?? 0; } } } catch {} const catMap = {}; for (const cat of categories){ catMap[cat.slug] = cat.names[catLocale] ?? cat.names.el; for (const sub of cat.children ?? []){ catMap[sub.slug] = sub.names[catLocale] ?? sub.names.el; } } const locMap = {}; for (const city of locationTree){ locMap[city.slug] = city.names[catLocale] ?? city.names.el; for (const d of city.children ?? []){ locMap[d.slug] = d.names[catLocale] ?? d.names.el; } } const hasFilter = !!(params.q || params.category || params.location || params.budgetMin || params.budgetMax); const filterParams = {}; if (params.q) filterParams.q = params.q; if (params.category) filterParams.category = params.category; if (params.location) filterParams.location = params.location; if (params.budgetMin) filterParams.budgetMin = params.budgetMin; if (params.budgetMax) filterParams.budgetMax = params.budgetMax; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "max-w-7xl mx-auto px-4 py-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_TasksAuthGuard__WEBPACK_IMPORTED_MODULE_7__.TasksAuthGuard, {}), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-col md:flex-row gap-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("aside", { className: "md:w-64 shrink-0", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-5 sticky top-24", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-semibold text-gray-900 mb-4", children: t('tasks.filters') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_TaskFiltersClient__WEBPACK_IMPORTED_MODULE_6__.TaskFiltersClient, { categories: categories, locationTree: locationTree, budgetRange: budgetRange, initialMode: mode, initialQ: params.q, initialCategory: params.category, initialLocation: params.location, initialBudgetMin: params.budgetMin, initialBudgetMax: params.budgetMax }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "mb-6", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-xl font-bold text-white", children: hasFilter ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ total, " ", t('tasks.title') ] }) : t('nav.tasks') }) }), noCards ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white/15 border border-white/30 rounded-xl p-8 text-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-4xl mb-3", children: "\uD83D\uDDC2️" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-white font-medium mb-2", children: t('find_tasks.no_cards') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)((next_link__WEBPACK_IMPORTED_MODULE_1___default()), { href: "/profile", className: "inline-block mt-2 px-5 py-2 bg-white text-blue-600 rounded-lg text-sm font-medium hover:bg-blue-50 transition", children: t('find_tasks.add_card') }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_TaskListClient__WEBPACK_IMPORTED_MODULE_5__.TaskListClient, { initialTasks: tasks, initialTotal: total, filterParams: filterParams, locale: locale, catMap: catMap, locMap: locMap, mode: mode }, [ mode, params.q, params.category, params.location, params.budgetMin, params.budgetMax, page ].join('|')) ] }) ] }) ] }); } {"finalSource":true}  mapbufferedMap  ConcatSourceRawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TasksPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(56057); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(59902); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(75112); /* harmony import */ var _TaskListClient__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(70535); /* harmony import */ var _TaskFiltersClient__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34052); /* harmony import */ var _TasksAuthGuard__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(52386); ReplaceSourceRawSourceXG085undefined87115undefined117155undefined157232undefined234286undefined288337undefined339394undefined396445undefined464494"https://api.canhelp.gr"undefined4995210undefined524538undefined755761(0,next_headers__WEBPACK_IMPORTED_MODULE_2__/* .cookies */ .UL)undefined946960(0,_lib_translations__WEBPACK_IMPORTED_MODULE_4__/* .getTranslations */ .$)undefined19251937(0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getCategories */ .bW)undefined19541965(0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getLocations */ .Vs)undefined19821999(0,_lib_api__WEBPACK_IMPORTED_MODULE_3__/* .getTaskBudgetRange */ .CC)undefined42004204(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined43114314(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined43164329_TasksAuthGuard__WEBPACK_IMPORTED_MODULE_7__.TasksAuthGuardundefined43634367(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined45024505(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined46214625(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined48254828(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined50685071(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined50735089_TaskFiltersClient__WEBPACK_IMPORTED_MODULE_6__.TaskFiltersClientundefined58245828(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined59625965(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined60836086(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined62476251(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined62536261react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined66966700(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined69136916(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined71517154(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined74107413(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined74157418(next_link__WEBPACK_IMPORTED_MODULE_1___default())undefined78407843(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined78457858_TaskListClient__WEBPACK_IMPORTED_MODULE_5__.TaskListClientundefined __webpack_require____webpack_require__.n__webpack_require__.r__webpack_require__.dU   bwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceX /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcefQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); _X[aX^ :@7_=L R E K  R X k q > D v | g_mkq06sy<B_e=Cdj &_>D5;PV CI<Bkq_  D!J!!"V"\"$$%%'$'j'p''(>(D(((W)])*_*I*O***R+X+,,B,H,,,-"---h.n./%///\0b081>111113_344:44444;5A555b6h666+717888889a9g9::P;V;;;<_<==T=Z===>>>>??@ @@@-A3AtAzABB^BdBCCdCjCCCJDHPDDD;EAE|EEOFUF true"https://api.canhelp.gr"00true W/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`);    X /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ Q 164190 trueundefined226256"https://api.canhelp.gr"undefined2612830undefined2873440undefined347353undefined437463trueundefined11121118undefined12501256undefined14111417undefined15051511undefined15571563undefined17151721undefined17961802undefined18501856undefined19711977undefined21032109undefined22042210undefined23802386undefined24522458undefined25062512undefined26292635undefined27282734undefined28292835undefined28982904undefined30543060undefined31793185undefined32553261undefined33903396undefined34463452undefined35283534undefined36073613undefined36873693undefined39473953undefined40814087undefined41444150undefined42114217undefined43124318undefined44124418undefined45174523undefined47034709undefined48494855undefined49254931undefined50855091undefined52205226undefined53535359undefined54085414undefined55105516undefined56175623undefined56945700undefined58305836undefined61296135undefined61976203undefined63336339undefined64806486undefined66656671undefined67236729undefined69726978undefined70837089undefined71907196undefined73617367undefined74267432undefined75317537undefined76957701undefined78387844undefined79577963undefined82148220undefined83228328undefined84248430undefined85168522undefined86998705undefined87908796undefined92389244undefined96239629undefined1001410020undefined1009010096undefined1023610242undefined1030210308undefined1043710443undefined1058310589undefined1076710773undefined1082510831undefined1095210958undefined1109011096undefined1126611272undefined1133011336undefined1146811474undefined1154811554undefined1171311719undefined1188011886undefined1206312069undefined1216712173undefined1238012386undefined1260012606undefined1273212738undefined1279212798undefined1321913225undefined1336413370undefined1346813474undefined1355413560undefined1362713633undefined1376913775undefined1392213928undefined1403414040undefined1412314129undefined1435614362undefined1452214528undefined1458914595undefined1468914695undefined1502215028undefined1518415190undefined1535215358undefined1552415530undefined1564015646undefined1570015706undefined1576415770undefined1606216068undefined1612016126undefined1631716323undefined1638716393undefined1661016616undefined1668516691undefined1675616762undefined1691116917undefined1699016996undefined1717317179undefined1725217258undefined1737017376undefined1748217488undefined1764717653undefined1772317729undefined1778817794undefined1799918005undefined   }webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ChatPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(91864); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(48178); /* harmony import */ var socket_io_client__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(44826); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcem/* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState, useEffect, useRef, useCallback, Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { getChatRooms, getMessages, getDailyUsage } from '@/lib/api'; import { formatShortName } from '@/lib/formatName'; import { io } from 'socket.io-client'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; function ChatPageInner() { const router = useRouter(); const searchParams = useSearchParams(); const { data: session, isPending } = useSession(); const { t, locale } = useLocale(); const [rooms, setRooms] = useState([]); const [loadingRooms, setLoadingRooms] = useState(true); const [activeRoomId, setActiveRoomId] = useState(null); const [messages, setMessages] = useState([]); const [loadingMessages, setLoadingMessages] = useState(false); const [input, setInput] = useState(''); const [connected, setConnected] = useState(false); const [msgLimit, setMsgLimit] = useState(null); const socketRef = useRef(null); const messagesEndRef = useRef(null); const inputRef = useRef(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); }, [ session, isPending ]); // Load chat rooms process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; getChatRooms().then((data)=>{ setRooms(data); const roomParam = searchParams.get('room'); if (roomParam) setActiveRoomId(roomParam); }).catch(()=>{}).finally(()=>setLoadingRooms(false)); getDailyUsage().then((u)=>setMsgLimit({ left: u.messagesLeft, sent: u.messagesSent })).catch(()=>{}); }, [ session ]); // Setup Socket.IO process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; const socket = io(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socketRef.current = socket; socket.on('connect', ()=>setConnected(true)); socket.on('disconnect', ()=>setConnected(false)); socket.on('new_message', (msg)=>{ setMessages((prev)=>{ // avoid duplicate if we get it back from our own send if (prev.some((m)=>m.message.id === msg.id)) return prev; return [ ...prev, { message: msg, sender: session.user ? { id: session.user.id, name: session.user.name ?? '', image: session.user.image ?? undefined } : null } ]; }); // Update lastMessage in rooms list and bubble room to top setRooms((prev)=>{ const updated = prev.map((r)=>r.room.id === msg.roomId ? { ...r, lastMessage: { body: msg.body, createdAt: msg.createdAt, translations: msg.translations ?? null } } : r); return updated.sort((a, b)=>{ const aTime = a.lastMessage?.createdAt ? new Date(a.lastMessage.createdAt).getTime() : new Date(a.room.createdAt).getTime(); const bTime = b.lastMessage?.createdAt ? new Date(b.lastMessage.createdAt).getTime() : new Date(b.room.createdAt).getTime(); return bTime - aTime; }); }); }); socket.on('message_translated', ({ id, roomId, translations })=>{ setMessages((prev)=>prev.map((m)=>m.message.id === id ? { ...m, message: { ...m.message, translations } } : m)); // Also update lastMessage in sidebar if this is the last message of that room if (roomId) { setRooms((prev)=>prev.map((r)=>r.room.id === roomId && r.lastMessage ? { ...r, lastMessage: { ...r.lastMessage, translations } } : r)); } }); return ()=>{ socket.disconnect(); socketRef.current = null; }; }, [ session ]); // Join room and load messages when activeRoomId changes process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!activeRoomId) return; setLoadingMessages(true); setMessages([]); getMessages(activeRoomId).then(setMessages).catch(()=>{}).finally(()=>setLoadingMessages(false)); socketRef.current?.emit('join_room', activeRoomId); socketRef.current?.emit('mark_read', activeRoomId); }, [ activeRoomId ]); // Focus input when active room changes process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!activeRoomId) return; const t = setTimeout(()=>inputRef.current?.focus(), 50); return ()=>clearTimeout(t); }, [ activeRoomId ]); // Auto-scroll on new messages (within container only) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, [ messages ]); const sendMessage = useCallback(()=>{ const body = input.trim(); if (!body || !activeRoomId || !socketRef.current) return; if (msgLimit && msgLimit.left !== null && msgLimit.left <= 0) return; socketRef.current.emit('send_message', { roomId: activeRoomId, body, locale }); setInput(''); // decrement local counter setMsgLimit((prev)=>prev && prev.left !== null ? { ...prev, left: prev.left - 1, sent: prev.sent + 1 } : prev); }, [ input, activeRoomId, msgLimit ]); const handleKeyDown = (e)=>{ if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; const LOCALE_TAG = { ru: 'ru-RU', en: 'en-US', el: 'el-GR' }; const localeTag = LOCALE_TAG[locale] ?? 'el-GR'; function fmtMsgTime(iso) { const d = new Date(iso); const now = new Date(); const diffMin = Math.floor((now.getTime() - d.getTime()) / 60000); if (diffMin < 1) return t('chat.just_now'); if (diffMin < 60) return `${diffMin}${t('chat.min_ago')}`; if (d.toDateString() === now.toDateString()) return d.toLocaleTimeString(localeTag, { hour: '2-digit', minute: '2-digit' }); return d.toLocaleDateString(localeTag, { day: '2-digit', month: '2-digit' }); } if (isPending || loadingRooms) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const activeRoom = rooms.find((r)=>r.room.id === activeRoomId); const currentUserId = session?.user?.id; return /*#__PURE__*/ _jsxs("div", { className: "max-w-5xl mx-auto px-4 py-6 h-[calc(100vh-80px)] flex gap-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "w-72 flex-shrink-0 bg-white rounded-xl border border-gray-200 overflow-hidden flex flex-col", children: [ /*#__PURE__*/ _jsxs("div", { className: "p-4 border-b border-gray-100", children: [ /*#__PURE__*/ _jsx("h1", { className: "font-bold text-gray-900 text-lg", children: t('nav.chat') }), /*#__PURE__*/ _jsxs("div", { className: `flex items-center gap-1.5 mt-1`, children: [ /*#__PURE__*/ _jsx("span", { className: `w-2 h-2 rounded-full ${connected ? 'bg-green-400' : 'bg-gray-300'}` }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400", children: connected ? t('chat.connected') : t('chat.disconnected') }) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "flex-1 overflow-y-auto", children: rooms.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "p-6 text-center text-gray-400 text-sm", children: t('chat.no_rooms') }) : rooms.map(({ room, task, otherUser, lastMessage })=>{ const roomLabel = task?.title ?? (formatShortName(otherUser?.firstName, otherUser?.lastName, otherUser?.name) || t('chat.direct_chat')); const roomSub = task ? formatShortName(otherUser?.firstName, otherUser?.lastName, otherUser?.name) || '' : t('chat.direct_chat'); return /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setActiveRoomId(room.id); setTimeout(()=>inputRef.current?.focus(), 50); }, className: `w-full text-left px-4 py-3 border-b border-gray-50 hover:bg-gray-50 transition ${activeRoomId === room.id ? 'bg-blue-50 border-l-2 border-l-blue-500' : ''}`, children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-start justify-between gap-1", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800 line-clamp-1 flex-1", children: roomLabel }), lastMessage && /*#__PURE__*/ _jsx("span", { className: "text-[10px] text-gray-400 shrink-0 mt-0.5", children: fmtMsgTime(lastMessage.createdAt) }) ] }), lastMessage ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5 line-clamp-1", children: lastMessage.translations?.[locale] ?? lastMessage.body }) : task ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5 line-clamp-1", children: roomSub }) : null ] }, room.id); }) }) ] }), /*#__PURE__*/ _jsx("div", { className: "flex-1 bg-white rounded-xl border border-gray-200 flex flex-col overflow-hidden", children: !activeRoomId ? /*#__PURE__*/ _jsx("div", { className: "flex-1 flex items-center justify-center text-gray-400 text-sm", children: t('chat.select') }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("div", { className: "px-5 py-4 border-b border-gray-100", children: /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-800 text-sm", children: activeRoom?.task?.title ?? (formatShortName(activeRoom?.otherUser?.firstName, activeRoom?.otherUser?.lastName, activeRoom?.otherUser?.name) || t('chat.direct_chat')) }) }), activeRoom?.task && /*#__PURE__*/ _jsxs(Link, { href: `/tasks/${activeRoom.task.id}`, className: "flex items-center gap-3 mx-5 mt-4 px-4 py-3 bg-blue-50 border border-blue-200 rounded-xl hover:bg-blue-100 transition group", children: [ /*#__PURE__*/ _jsx("div", { className: "w-8 h-8 rounded-lg bg-blue-600 flex items-center justify-center flex-shrink-0", children: /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-white", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [ /*#__PURE__*/ _jsx("path", { d: "M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2" }), /*#__PURE__*/ _jsx("rect", { x: "8", y: "2", width: "8", height: "4", rx: "1", ry: "1" }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs text-blue-500 font-medium", children: t('chat.linked_task') }), /*#__PURE__*/ _jsx("p", { className: "text-sm font-semibold text-blue-800 truncate group-hover:underline", children: activeRoom.task.title }) ] }), /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-blue-400 flex-shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /*#__PURE__*/ _jsx("polyline", { points: "9 18 15 12 9 6" }) }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-4 space-y-3", children: [ loadingMessages ? /*#__PURE__*/ _jsx("div", { className: "text-center text-gray-400 text-sm py-10", children: t('common.loading') }) : messages.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "text-center text-gray-400 text-sm py-10", children: t('chat.no_messages') }) : messages.map(({ message, sender })=>{ const isMe = message.senderId === currentUserId; return /*#__PURE__*/ _jsxs("div", { className: `flex gap-2.5 ${isMe ? 'flex-row-reverse' : ''}`, children: [ /*#__PURE__*/ _jsx("div", { className: "w-8 h-8 rounded-full bg-blue-100 flex-shrink-0 flex items-center justify-center text-blue-700 text-xs font-bold overflow-hidden", children: sender?.image ? /*#__PURE__*/ _jsx("img", { src: sender.image, alt: sender.name, className: "w-full h-full object-cover" }) : sender?.name?.[0]?.toUpperCase() ?? '?' }), /*#__PURE__*/ _jsxs("div", { className: `max-w-[70%] ${isMe ? 'items-end' : 'items-start'} flex flex-col gap-1`, children: [ !isMe && /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400 px-1", children: formatShortName(sender?.firstName, sender?.lastName, sender?.name) }), /*#__PURE__*/ _jsx("div", { className: `px-4 py-2 rounded-2xl text-sm leading-relaxed ${isMe ? 'bg-blue-600 text-white rounded-tr-sm' : 'bg-gray-100 text-gray-800 rounded-tl-sm'}`, children: message.translations?.[locale] ?? message.body }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-300 px-1", children: new Date(message.createdAt).toLocaleTimeString(localeTag, { hour: '2-digit', minute: '2-digit' }) }) ] }) ] }, message.id); }), /*#__PURE__*/ _jsx("div", { ref: messagesEndRef }) ] }), /*#__PURE__*/ _jsxs("div", { className: "px-4 py-3 border-t border-gray-100", children: [ msgLimit && msgLimit.left !== null && msgLimit.left <= 0 && /*#__PURE__*/ _jsxs("div", { className: "mb-2 flex items-center gap-2 bg-red-50 border border-red-200 rounded-xl px-3 py-2", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-red-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }) }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-red-700 flex-1", children: t('chat.limit_reached', 'Дневной лимит сообщений исчерпан') }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "text-xs font-medium text-red-700 underline", children: t('plan.upgrade') }) ] }), msgLimit && msgLimit.left !== null && msgLimit.left > 0 && msgLimit.left <= Math.ceil((msgLimit.left + msgLimit.sent) * 0.2) && /*#__PURE__*/ _jsxs("div", { className: "mb-2 flex items-center gap-2 bg-amber-50 border border-amber-200 rounded-xl px-3 py-2", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-amber-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }) }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-amber-700 flex-1", children: t('chat.limit_warning', 'Осталось {n} сообщений сегодня').replace('{n}', String(msgLimit.left)) }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "text-xs font-medium text-amber-700 underline", children: t('plan.upgrade') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2 items-end", children: [ /*#__PURE__*/ _jsx("textarea", { ref: inputRef, value: input, onChange: (e)=>setInput(e.target.value), onKeyDown: handleKeyDown, rows: 1, placeholder: t('chat.placeholder'), disabled: !!(msgLimit && msgLimit.left !== null && msgLimit.left <= 0), className: "flex-1 border border-gray-300 rounded-xl px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none max-h-32 disabled:bg-gray-50 disabled:text-gray-400", style: { minHeight: '40px' } }), /*#__PURE__*/ _jsx("button", { onClick: sendMessage, disabled: !input.trim() || !connected || !!(msgLimit && msgLimit.left !== null && msgLimit.left <= 0), className: "h-10 w-10 bg-blue-600 text-white rounded-xl hover:bg-blue-700 disabled:opacity-40 disabled:cursor-not-allowed flex-shrink-0 flex items-center justify-center", children: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 12h14M12 5l7 7-7 7" }) }) }) ] }) ] }) ] }) }) ] }); } export default function ChatPage() { return /*#__PURE__*/ _jsx(Suspense, { fallback: /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: "..." }), children: /*#__PURE__*/ _jsx(ChatPageInner, {}) }); } al=_:<ce  2Dbg}8@cj_ MT| 49W\iq2_: ;C 14<@ 2!5!""""##,%/%%%&&~'_'((7*;*++N,Q,--..0061911112O2R2223344445_5668899;;<<==:?=?/A2A-B1BBBCCsEwEUFXFyG|G7I;IQJ_TJKKKKMMPP_QcQMRQRFSISTTVVWWWW Z Z[ [\\w^z^_V___sawa/b2b;f>f (/* binding */ ChatPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(91864); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(48178); /* harmony import */ var socket_io_client__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(44826); /* __next_internal_client_entry_do_not_use__ default auto */ const API_URL = "https://api.canhelp.gr" || 0; function ChatPageInner() { const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const searchParams = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)(); const { data: session, isPending } = (0,_lib_auth__WEBPACK_IMPORTED_MODULE_4__/* .useSession */ .wV)(); const { t, locale } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_5__/* .useLocale */ .Y)(); const [rooms, setRooms] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [loadingRooms, setLoadingRooms] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true); const [activeRoomId, setActiveRoomId] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [messages, setMessages] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [loadingMessages, setLoadingMessages] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [input, setInput] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [connected, setConnected] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [msgLimit, setMsgLimit] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const socketRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); const messagesEndRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); const inputRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!isPending && !session) router.push('/login'); }, [ session, isPending ]); // Load chat rooms process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!session) return; (0,_lib_api__WEBPACK_IMPORTED_MODULE_6__/* .getChatRooms */ .Zp)().then((data)=>{ setRooms(data); const roomParam = searchParams.get('room'); if (roomParam) setActiveRoomId(roomParam); }).catch(()=>{}).finally(()=>setLoadingRooms(false)); (0,_lib_api__WEBPACK_IMPORTED_MODULE_6__/* .getDailyUsage */ .z4)().then((u)=>setMsgLimit({ left: u.messagesLeft, sent: u.messagesSent })).catch(()=>{}); }, [ session ]); // Setup Socket.IO process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!session) return; const socket = (0,socket_io_client__WEBPACK_IMPORTED_MODULE_7__.io)(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socketRef.current = socket; socket.on('connect', ()=>setConnected(true)); socket.on('disconnect', ()=>setConnected(false)); socket.on('new_message', (msg)=>{ setMessages((prev)=>{ // avoid duplicate if we get it back from our own send if (prev.some((m)=>m.message.id === msg.id)) return prev; return [ ...prev, { message: msg, sender: session.user ? { id: session.user.id, name: session.user.name ?? '', image: session.user.image ?? undefined } : null } ]; }); // Update lastMessage in rooms list and bubble room to top setRooms((prev)=>{ const updated = prev.map((r)=>r.room.id === msg.roomId ? { ...r, lastMessage: { body: msg.body, createdAt: msg.createdAt, translations: msg.translations ?? null } } : r); return updated.sort((a, b)=>{ const aTime = a.lastMessage?.createdAt ? new Date(a.lastMessage.createdAt).getTime() : new Date(a.room.createdAt).getTime(); const bTime = b.lastMessage?.createdAt ? new Date(b.lastMessage.createdAt).getTime() : new Date(b.room.createdAt).getTime(); return bTime - aTime; }); }); }); socket.on('message_translated', ({ id, roomId, translations })=>{ setMessages((prev)=>prev.map((m)=>m.message.id === id ? { ...m, message: { ...m.message, translations } } : m)); // Also update lastMessage in sidebar if this is the last message of that room if (roomId) { setRooms((prev)=>prev.map((r)=>r.room.id === roomId && r.lastMessage ? { ...r, lastMessage: { ...r.lastMessage, translations } } : r)); } }); return ()=>{ socket.disconnect(); socketRef.current = null; }; }, [ session ]); // Join room and load messages when activeRoomId changes process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!activeRoomId) return; setLoadingMessages(true); setMessages([]); (0,_lib_api__WEBPACK_IMPORTED_MODULE_6__/* .getMessages */ .VL)(activeRoomId).then(setMessages).catch(()=>{}).finally(()=>setLoadingMessages(false)); socketRef.current?.emit('join_room', activeRoomId); socketRef.current?.emit('mark_read', activeRoomId); }, [ activeRoomId ]); // Focus input when active room changes process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!activeRoomId) return; const t = setTimeout(()=>inputRef.current?.focus(), 50); return ()=>clearTimeout(t); }, [ activeRoomId ]); // Auto-scroll on new messages (within container only) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, [ messages ]); const sendMessage = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)(()=>{ const body = input.trim(); if (!body || !activeRoomId || !socketRef.current) return; if (msgLimit && msgLimit.left !== null && msgLimit.left <= 0) return; socketRef.current.emit('send_message', { roomId: activeRoomId, body, locale }); setInput(''); // decrement local counter setMsgLimit((prev)=>prev && prev.left !== null ? { ...prev, left: prev.left - 1, sent: prev.sent + 1 } : prev); }, [ input, activeRoomId, msgLimit ]); const handleKeyDown = (e)=>{ if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; const LOCALE_TAG = { ru: 'ru-RU', en: 'en-US', el: 'el-GR' }; const localeTag = LOCALE_TAG[locale] ?? 'el-GR'; function fmtMsgTime(iso) { const d = new Date(iso); const now = new Date(); const diffMin = Math.floor((now.getTime() - d.getTime()) / 60000); if (diffMin < 1) return t('chat.just_now'); if (diffMin < 60) return `${diffMin}${t('chat.min_ago')}`; if (d.toDateString() === now.toDateString()) return d.toLocaleTimeString(localeTag, { hour: '2-digit', minute: '2-digit' }); return d.toLocaleDateString(localeTag, { day: '2-digit', month: '2-digit' }); } if (isPending || loadingRooms) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const activeRoom = rooms.find((r)=>r.room.id === activeRoomId); const currentUserId = session?.user?.id; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "max-w-5xl mx-auto px-4 py-6 h-[calc(100vh-80px)] flex gap-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "w-72 flex-shrink-0 bg-white rounded-xl border border-gray-200 overflow-hidden flex flex-col", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "p-4 border-b border-gray-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "font-bold text-gray-900 text-lg", children: t('nav.chat') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: `flex items-center gap-1.5 mt-1`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `w-2 h-2 rounded-full ${connected ? 'bg-green-400' : 'bg-gray-300'}` }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-gray-400", children: connected ? t('chat.connected') : t('chat.disconnected') }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex-1 overflow-y-auto", children: rooms.length === 0 ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "p-6 text-center text-gray-400 text-sm", children: t('chat.no_rooms') }) : rooms.map(({ room, task, otherUser, lastMessage })=>{ const roomLabel = task?.title ?? ((0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)(otherUser?.firstName, otherUser?.lastName, otherUser?.name) || t('chat.direct_chat')); const roomSub = task ? (0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)(otherUser?.firstName, otherUser?.lastName, otherUser?.name) || '' : t('chat.direct_chat'); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { onClick: ()=>{ setActiveRoomId(room.id); setTimeout(()=>inputRef.current?.focus(), 50); }, className: `w-full text-left px-4 py-3 border-b border-gray-50 hover:bg-gray-50 transition ${activeRoomId === room.id ? 'bg-blue-50 border-l-2 border-l-blue-500' : ''}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-start justify-between gap-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-800 line-clamp-1 flex-1", children: roomLabel }), lastMessage && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-[10px] text-gray-400 shrink-0 mt-0.5", children: fmtMsgTime(lastMessage.createdAt) }) ] }), lastMessage ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5 line-clamp-1", children: lastMessage.translations?.[locale] ?? lastMessage.body }) : task ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5 line-clamp-1", children: roomSub }) : null ] }, room.id); }) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex-1 bg-white rounded-xl border border-gray-200 flex flex-col overflow-hidden", children: !activeRoomId ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex-1 flex items-center justify-center text-gray-400 text-sm", children: t('chat.select') }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "px-5 py-4 border-b border-gray-100", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "font-semibold text-gray-800 text-sm", children: activeRoom?.task?.title ?? ((0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)(activeRoom?.otherUser?.firstName, activeRoom?.otherUser?.lastName, activeRoom?.otherUser?.name) || t('chat.direct_chat')) }) }), activeRoom?.task && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)((next_link__WEBPACK_IMPORTED_MODULE_3___default()), { href: `/tasks/${activeRoom.task.id}`, className: "flex items-center gap-3 mx-5 mt-4 px-4 py-3 bg-blue-50 border border-blue-200 rounded-xl hover:bg-blue-100 transition group", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-8 h-8 rounded-lg bg-blue-600 flex items-center justify-center flex-shrink-0", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { className: "w-4 h-4 text-white", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M16 4h2a2 2 0 012 2v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6a2 2 0 012-2h2" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("rect", { x: "8", y: "2", width: "8", height: "4", rx: "1", ry: "1" }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-blue-500 font-medium", children: t('chat.linked_task') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-semibold text-blue-800 truncate group-hover:underline", children: activeRoom.task.title }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 text-blue-400 flex-shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("polyline", { points: "9 18 15 12 9 6" }) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1 overflow-y-auto px-5 py-4 space-y-3", children: [ loadingMessages ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center text-gray-400 text-sm py-10", children: t('common.loading') }) : messages.length === 0 ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center text-gray-400 text-sm py-10", children: t('chat.no_messages') }) : messages.map(({ message, sender })=>{ const isMe = message.senderId === currentUserId; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: `flex gap-2.5 ${isMe ? 'flex-row-reverse' : ''}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-8 h-8 rounded-full bg-blue-100 flex-shrink-0 flex items-center justify-center text-blue-700 text-xs font-bold overflow-hidden", children: sender?.image ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: sender.image, alt: sender.name, className: "w-full h-full object-cover" }) : sender?.name?.[0]?.toUpperCase() ?? '?' }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: `max-w-[70%] ${isMe ? 'items-end' : 'items-start'} flex flex-col gap-1`, children: [ !isMe && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-gray-400 px-1", children: (0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)(sender?.firstName, sender?.lastName, sender?.name) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: `px-4 py-2 rounded-2xl text-sm leading-relaxed ${isMe ? 'bg-blue-600 text-white rounded-tr-sm' : 'bg-gray-100 text-gray-800 rounded-tl-sm'}`, children: message.translations?.[locale] ?? message.body }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-gray-300 px-1", children: new Date(message.createdAt).toLocaleTimeString(localeTag, { hour: '2-digit', minute: '2-digit' }) }) ] }) ] }, message.id); }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { ref: messagesEndRef }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "px-4 py-3 border-t border-gray-100", children: [ msgLimit && msgLimit.left !== null && msgLimit.left <= 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-2 flex items-center gap-2 bg-red-50 border border-red-200 rounded-xl px-3 py-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 text-red-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-red-700 flex-1", children: t('chat.limit_reached', 'Дневной лимит сообщений исчерпан') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)((next_link__WEBPACK_IMPORTED_MODULE_3___default()), { href: "/pricing", className: "text-xs font-medium text-red-700 underline", children: t('plan.upgrade') }) ] }), msgLimit && msgLimit.left !== null && msgLimit.left > 0 && msgLimit.left <= Math.ceil((msgLimit.left + msgLimit.sent) * 0.2) && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-2 flex items-center gap-2 bg-amber-50 border border-amber-200 rounded-xl px-3 py-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 text-amber-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-amber-700 flex-1", children: t('chat.limit_warning', 'Осталось {n} сообщений сегодня').replace('{n}', String(msgLimit.left)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)((next_link__WEBPACK_IMPORTED_MODULE_3___default()), { href: "/pricing", className: "text-xs font-medium text-amber-700 underline", children: t('plan.upgrade') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex gap-2 items-end", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { ref: inputRef, value: input, onChange: (e)=>setInput(e.target.value), onKeyDown: handleKeyDown, rows: 1, placeholder: t('chat.placeholder'), disabled: !!(msgLimit && msgLimit.left !== null && msgLimit.left <= 0), className: "flex-1 border border-gray-300 rounded-xl px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none max-h-32 disabled:bg-gray-50 disabled:text-gray-400", style: { minHeight: '40px' } }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: sendMessage, disabled: !input.trim() || !connected || !!(msgLimit && msgLimit.left !== null && msgLimit.left <= 0), className: "h-10 w-10 bg-blue-600 text-white rounded-xl hover:bg-blue-700 disabled:opacity-40 disabled:cursor-not-allowed flex-shrink-0 flex items-center justify-center", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 12h14M12 5l7 7-7 7" }) }) }) ] }) ] }) ] }) }) ] }); } function ChatPage() { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react__WEBPACK_IMPORTED_MODULE_1__.Suspense, { fallback: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-20 text-white", children: "..." }), children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ChatPageInner, {}) }); }    __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ChatPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(91864); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(48178); /* harmony import */ var socket_io_client__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(44826); \61146undefined148222undefined224284undefined286314undefined316355undefined357401undefined403471undefined473523undefined525562undefined580610"https://api.canhelp.gr"undefined6156370undefined686694(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined724738(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)undefined784793(0,_lib_auth__WEBPACK_IMPORTED_MODULE_4__/* .useSession */ .wV)undefined824832(0,_context_locale__WEBPACK_IMPORTED_MODULE_5__/* .useLocale */ .Y)undefined867874(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined925932(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined985992(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10371044(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined11011108(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined11481155(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined12001207(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined12531260(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined12911296(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined13321337(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined13671372(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined14361444(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined16411649(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined16951706(0,_lib_api__WEBPACK_IMPORTED_MODULE_6__/* .getChatRooms */ .Zp)undefined19341946(0,_lib_api__WEBPACK_IMPORTED_MODULE_6__/* .getDailyUsage */ .z4)undefined21912199(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined22602261(0,socket_io_client__WEBPACK_IMPORTED_MODULE_7__.io)undefined51705178(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined52885298(0,_lib_api__WEBPACK_IMPORTED_MODULE_6__/* .getMessages */ .VL)undefined56435651(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined59475955(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined61436153(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined77297732(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined79968000(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined81398143(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined83388342(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined84988501(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined87198723(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined89058908(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined91309133(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined95169519(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined96609663(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined99569970(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)undefined1011010124(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)undefined1026610270(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1080710811(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1102511028(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1134211345(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1174611749(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1202112024(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1241812421(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1259812601(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1279012794(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1279612804react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined1287912882(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1302213025(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1318613200(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)undefined1344113445(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1344713450(next_link__WEBPACK_IMPORTED_MODULE_3___default())undefined1377313776(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1397513979(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1453814541(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1477914782(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1535015354(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1553215535(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1581015813(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1618616189(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1668716690(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1694116945(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1714517148(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1739017393(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1777917783(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1800518008(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1829718300(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1874318747(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1902519028(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1920319217(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_8__/* .formatShortName */ .H)undefined1939219395(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1985019853(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2063020633(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2083120835(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2106921073(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2131821321(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2174021743(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2219722200(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2251022513(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2251522518(next_link__WEBPACK_IMPORTED_MODULE_3___default())undefined2304923053(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2330223305(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2372623729(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2418324186(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2453424537(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2453924542(next_link__WEBPACK_IMPORTED_MODULE_3___default())undefined2494724951(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2513525138(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2617126174(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2668426687(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2711027113(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2770427718undefined2776627769(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2777127778react__WEBPACK_IMPORTED_MODULE_1__.Suspenseundefined2781527818(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2795627959(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined Y  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceB__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ProfilePage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceMw/* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState, useEffect, useRef, Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { useSession, authClient } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import * as api from '@/lib/api'; function SpecialistCardEditor({ card, isOpen, onToggle, onUpdate, onDelete, categories, locationTree, catLocale, locale }) { const { t } = useLocale(); const [cardTab, setCardTab] = useState('main'); const [saving, setSaving] = useState(false); const [savedOk, setSavedOk] = useState(false); const [localTitle, setLocalTitle] = useState(card.title); const [localDesc, setLocalDesc] = useState(card.description ?? ''); const [localSkills, setLocalSkills] = useState(card.skills ?? []); const [skillInput, setSkillInput] = useState(''); const [localCategories, setLocalCategories] = useState(card.categories ?? []); const [localLocations, setLocalLocations] = useState(card.locations ?? []); const [localActive, setLocalActive] = useState(card.isActive); const [apiSkillSugs, setApiSkillSugs] = useState([]); const [portfolio, setPortfolio] = useState(card.portfolio ?? []); const [portfolioUploading, setPortfolioUploading] = useState(false); const [editingItem, setEditingItem] = useState(null); const [editTitle, setEditTitle] = useState(''); const [editDesc, setEditDesc] = useState(''); const portfolioFileRef = useRef(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (cardTab !== 'skills') return; api.getSkillSuggestions(localCategories.length > 0 ? localCategories : undefined).then(setApiSkillSugs).catch(()=>setApiSkillSugs([])); }, [ localCategories, cardTab ]); const lbl = (ru, en, el)=>locale === 'ru' ? ru : locale === 'en' ? en : el; async function saveAll() { setSaving(true); try { const updated = await api.updateSpecialistCard(card.id, { title: localTitle, description: localDesc || null, skills: localSkills, categories: localCategories, locations: localLocations }); onUpdate({ ...updated, portfolio }); setSavedOk(true); setTimeout(()=>setSavedOk(false), 2000); } catch {} finally{ setSaving(false); } } async function toggleActive() { const next = !localActive; setLocalActive(next); try { await api.updateSpecialistCard(card.id, { isActive: next }); } catch {} } function addSkill(s) { const trimmed = s.trim(); if (trimmed && !localSkills.includes(trimmed)) setLocalSkills([ ...localSkills, trimmed ]); setSkillInput(''); } function toggleCategory(slug, childSlugs = []) { if (localCategories.includes(slug)) { setLocalCategories(localCategories.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocalCategories([ ...new Set([ ...localCategories, slug, ...childSlugs ]) ]); } } function toggleLocation(slug, childSlugs = []) { if (localLocations.includes(slug)) { setLocalLocations(localLocations.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocalLocations([ ...new Set([ ...localLocations, slug, ...childSlugs ]) ]); } } async function handlePortfolioUpload(e) { const file = e.target.files?.[0]; if (!file) return; setPortfolioUploading(true); try { const form = new FormData(); form.append('file', file); form.append('cardId', card.id); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}/api/portfolio`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const item = await res.json(); const next = [ ...portfolio, item ]; setPortfolio(next); onUpdate({ ...card, portfolio: next }); } catch {} finally{ setPortfolioUploading(false); if (portfolioFileRef.current) portfolioFileRef.current.value = ''; } } async function handlePortfolioDelete(id) { try { await api.deletePortfolioItem(id); const next = portfolio.filter((p)=>p.id !== id); setPortfolio(next); onUpdate({ ...card, portfolio: next }); } catch {} } async function handlePortfolioSave(id) { try { const item = await api.updatePortfolioItem(id, { title: editTitle, description: editDesc }); setPortfolio((prev)=>prev.map((p)=>p.id === id ? item : p)); setEditingItem(null); } catch {} } const cardTabs = [ { id: 'main', label: t('profile.card.tab.main') }, { id: 'skills', label: t('profile.card.tab.skills') }, { id: 'categories', label: t('profile.card.tab.categories') }, { id: 'geography', label: t('profile.card.tab.geography') }, { id: 'portfolio', label: t('profile.card.tab.portfolio') } ]; return /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 overflow-hidden", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-gray-100", children: [ /*#__PURE__*/ _jsxs("button", { type: "button", onClick: onToggle, className: "flex-1 flex items-center gap-3 text-left", children: [ /*#__PURE__*/ _jsx("span", { className: "text-sm font-semibold text-gray-800 flex-1", children: localTitle || card.title }), /*#__PURE__*/ _jsx("span", { className: "text-gray-400 text-xs", children: isOpen ? '▲' : '▼' }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", title: t('profile.card.active'), onClick: toggleActive, className: `w-8 h-5 rounded-full transition-colors flex-shrink-0 ${localActive ? 'bg-green-400' : 'bg-gray-300'}`, children: /*#__PURE__*/ _jsx("span", { className: `block w-4 h-4 rounded-full bg-white shadow transition-transform mx-0.5 ${localActive ? 'translate-x-3' : ''}` }) }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: onDelete, className: "text-red-400 hover:text-red-600 text-sm px-1 flex-shrink-0", title: t('profile.card.delete'), children: "\uD83D\uDDD1" }) ] }), isOpen && /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("div", { className: "flex overflow-x-auto border-b border-gray-100 bg-gray-50 gap-0", children: cardTabs.map((t)=>/*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setCardTab(t.id), className: `px-4 py-2.5 text-xs font-medium whitespace-nowrap border-b-2 transition -mb-px ${cardTab === t.id ? 'border-blue-500 text-blue-600 bg-white' : 'border-transparent text-gray-500 hover:text-gray-700'}`, children: t.label }, t.id)) }), /*#__PURE__*/ _jsxs("div", { className: "p-4", children: [ cardTab === 'main' && /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsx("input", { value: localTitle, onChange: (e)=>setLocalTitle(e.target.value), maxLength: 200, placeholder: t('profile.cards.new_title'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("textarea", { value: localDesc, onChange: (e)=>setLocalDesc(e.target.value), rows: 4, maxLength: 1000, placeholder: t('profile.bio.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), cardTab === 'skills' && /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ localSkills.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2", children: localSkills.map((s)=>/*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5 bg-blue-50 text-blue-700 text-sm px-3 py-1 rounded-full", children: [ s, /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setLocalSkills(localSkills.filter((x)=>x !== s)), className: "text-blue-400 hover:text-blue-700 leading-none", children: "\xd7" }) ] }, s)) }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2", children: [ /*#__PURE__*/ _jsx("input", { value: skillInput, onChange: (e)=>setSkillInput(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') { e.preventDefault(); addSkill(skillInput); } }, placeholder: t('profile.card.skill.add'), className: "flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>addSkill(skillInput), className: "px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium", children: "+" }) ] }), apiSkillSugs.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-1.5", children: apiSkillSugs.map((s)=>s.names[catLocale] ?? s.names.el).filter((name, i, arr)=>arr.indexOf(name) === i && !localSkills.includes(name)).slice(0, 16).map((name)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>addSkill(name), className: "text-xs px-2.5 py-1 border border-gray-200 rounded-full text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: [ "+ ", name ] }, name)) }) ] }), cardTab === 'categories' && /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: categories.map((cat)=>{ const catName = cat.names?.[catLocale] ?? cat.names?.el ?? cat.slug; const children = cat.children ?? []; const childSlugs = children.map((c)=>c.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localCategories.includes(cat.slug), onChange: ()=>toggleCategory(cat.slug, childSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("span", { className: "text-sm font-medium text-gray-800", children: [ cat.icon && /*#__PURE__*/ _jsx("span", { className: "mr-1", children: cat.icon }), catName ] }) ] }), children.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-2 space-y-2", children: children.map((sub)=>{ const subName = sub.names?.[catLocale] ?? sub.names?.el ?? sub.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localCategories.includes(sub.slug), onChange: ()=>toggleCategory(sub.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: subName }) ] }, sub.id); }) }) ] }, cat.id); }) }), cardTab === 'geography' && /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: locationTree.map((city)=>{ const cityName = city.names?.[catLocale] ?? city.names?.el ?? city.slug; const districts = city.children ?? []; const districtSlugs = districts.map((d)=>d.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localLocations.includes(city.slug), onChange: ()=>toggleLocation(city.slug, districtSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-800", children: cityName }) ] }), districts.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-2 space-y-2", children: districts.map((d)=>{ const dName = d.names?.[catLocale] ?? d.names?.el ?? d.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: localLocations.includes(d.slug), onChange: ()=>toggleLocation(d.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: dName }) ] }, d.id); }) }) ] }, city.id); }) }), cardTab === 'portfolio' && /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ portfolio.length < 20 && /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>portfolioFileRef.current?.click(), disabled: portfolioUploading, className: "flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium disabled:opacity-50", children: portfolioUploading ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("span", { className: "w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" }), t('profile.card.photo.uploading') ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ "\uD83D\uDCF7 ", t('profile.card.photo.add') ] }) }), /*#__PURE__*/ _jsx("input", { ref: portfolioFileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handlePortfolioUpload }) ] }), portfolio.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "text-center py-8 text-gray-400 text-sm border-2 border-dashed border-gray-200 rounded-xl", children: t('profile.card.photo.empty') }) : /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-3", children: portfolio.map((item)=>/*#__PURE__*/ _jsxs("div", { className: "group relative rounded-xl overflow-hidden border border-gray-200 bg-gray-50", children: [ /*#__PURE__*/ _jsx("img", { src: item.imageUrl, alt: item.title ?? '', className: "w-full aspect-square object-cover" }), /*#__PURE__*/ _jsxs("div", { className: "absolute inset-0 bg-black/0 group-hover:bg-black/50 transition-all flex flex-col justify-between p-2", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>handlePortfolioDelete(item.id), className: "self-end opacity-0 group-hover:opacity-100 transition w-7 h-7 rounded-full bg-red-500 text-white text-sm flex items-center justify-center hover:bg-red-600", children: "\xd7" }), /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>{ setEditingItem(item); setEditTitle(item.title ?? ''); setEditDesc(item.description ?? ''); }, className: "opacity-0 group-hover:opacity-100 transition text-xs text-white bg-black/50 hover:bg-black/70 rounded-lg px-2 py-1", children: [ "✏️ ", t('profile.card.item.edit') ] }) ] }), item.title && /*#__PURE__*/ _jsx("div", { className: "px-2 py-1.5", children: /*#__PURE__*/ _jsx("p", { className: "text-xs font-medium text-gray-700 truncate", children: item.title }) }) ] }, item.id)) }) ] }), cardTab !== 'portfolio' && /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 mt-4 pt-4 border-t border-gray-100", children: [ /*#__PURE__*/ _jsx("button", { type: "button", disabled: saving, onClick: saveAll, className: "px-5 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-semibold disabled:opacity-50", children: saving ? '...' : t('profile.card.save') }), savedOk && /*#__PURE__*/ _jsxs("span", { className: "text-sm text-green-600", children: [ "✓ ", t('profile.card.saved') ] }) ] }) ] }) ] }), editingItem && /*#__PURE__*/ _jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl shadow-xl p-6 w-full max-w-md", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-800 mb-4", children: t('profile.card.item.edit') }), /*#__PURE__*/ _jsx("img", { src: editingItem.imageUrl, alt: "", className: "w-full h-40 object-cover rounded-xl mb-4" }), /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.card.item.title') }), /*#__PURE__*/ _jsx("input", { value: editTitle, onChange: (e)=>setEditTitle(e.target.value), maxLength: 200, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.card.item.desc') }), /*#__PURE__*/ _jsx("textarea", { value: editDesc, onChange: (e)=>setEditDesc(e.target.value), rows: 3, maxLength: 1000, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-3 mt-5", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>handlePortfolioSave(editingItem.id), className: "flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 rounded-lg text-sm font-medium", children: t('profile.card.item.save') }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setEditingItem(null), className: "flex-1 bg-gray-100 hover:bg-gray-200 text-gray-700 py-2 rounded-lg text-sm font-medium", children: t('profile.card.item.cancel') }) ] }) ] }) }) ] }); } // ─── AutoResponseTab ─────────────────────────────────────────────────────── function AutoResponseTab({ categories, locationTree, loaded, onLoad, settings, saving, saved, onSave, t, catLocale }) { const { useEffect: _ue, useState: _us } = { useEffect, useState }; const [enabled, setEnabled] = _us(false); const [minBudget, setMinBudget] = _us(''); const [maxBudget, setMaxBudget] = _us(''); const [defaultPrice, setDefaultPrice] = _us(''); const [defaultMessage, setDefaultMessage] = _us(''); const [maxPerDay, setMaxPerDay] = _us(''); const [selCategories, setSelCategories] = _us([]); const [selLocations, setSelLocations] = _us([]); _ue(()=>{ onLoad(); }, []); _ue(()=>{ if (!settings) return; setEnabled(settings.enabled); setMinBudget(settings.minBudget != null ? String(settings.minBudget) : ''); setMaxBudget(settings.maxBudget != null ? String(settings.maxBudget) : ''); setDefaultPrice(settings.defaultPrice != null ? String(settings.defaultPrice) : ''); setDefaultMessage(settings.defaultMessage ?? ''); setMaxPerDay(settings.maxAutoOffersPerDay != null ? String(settings.maxAutoOffersPerDay) : ''); setSelCategories(settings.categories ?? []); setSelLocations(settings.locations ?? []); }, [ settings ]); if (!loaded) return /*#__PURE__*/ _jsx("div", { className: "text-center py-10 text-white/60", children: t('common.loading') }); const flatLocations = []; function flatten(nodes) { for (const n of nodes){ flatLocations.push({ id: n.id, name: n.name }); if (n.children?.length) flatten(n.children); } } flatten(locationTree); return /*#__PURE__*/ _jsxs("div", { className: "space-y-4", children: [ /*#__PURE__*/ _jsx("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "font-medium text-gray-800", children: t('auto_response.title', 'Авто-ответ') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('auto_response.desc', 'Автоматически отвечать на подходящие задачи') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setEnabled((v)=>!v), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${enabled ? 'bg-blue-500' : 'bg-gray-300'}`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${enabled ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5 space-y-4", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-medium text-gray-800 text-sm", children: t('auto_response.budget_range', 'Бюджет задачи') }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.min_budget', 'Мин. €') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "0", value: minBudget, onChange: (e)=>setMinBudget(e.target.value), placeholder: "0", className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.max_budget', 'Макс. €') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "0", value: maxBudget, onChange: (e)=>setMaxBudget(e.target.value), placeholder: "∞", className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.default_price', 'Цена по умолчанию €') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "0", value: defaultPrice, onChange: (e)=>setDefaultPrice(e.target.value), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.max_per_day', 'Макс. авто-офертов/день') }), /*#__PURE__*/ _jsx("input", { type: "number", min: "1", max: "50", value: maxPerDay, onChange: (e)=>setMaxPerDay(e.target.value), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.default_message', 'Текст авто-ответа') }), /*#__PURE__*/ _jsx("textarea", { value: defaultMessage, onChange: (e)=>setDefaultMessage(e.target.value), rows: 4, maxLength: 2000, placeholder: t('auto_response.message_placeholder', 'Здравствуйте! Я могу помочь с этой задачей...'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), categories.length > 0 && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-medium text-gray-800 text-sm mb-3", children: t('auto_response.categories', 'Категории задач') }), /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2 max-h-40 overflow-y-auto", children: categories.map((cat)=>{ const name = cat[`name_${catLocale}`] || cat.name_el || cat.name; const sel = selCategories.includes(cat.id); return /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setSelCategories(sel ? selCategories.filter((c)=>c !== cat.id) : [ ...selCategories, cat.id ]), className: `px-3 py-1.5 rounded-lg text-xs border transition ${sel ? 'bg-blue-600 border-blue-600 text-white' : 'bg-white border-gray-300 text-gray-700 hover:border-blue-400'}`, children: name }, cat.id); }) }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: saving, onClick: ()=>onSave({ enabled, minBudget: minBudget ? Number(minBudget) : null, maxBudget: maxBudget ? Number(maxBudget) : null, defaultPrice: defaultPrice ? Number(defaultPrice) : null, defaultMessage: defaultMessage || null, maxAutoOffersPerDay: maxPerDay ? Number(maxPerDay) : null, categories: selCategories.length > 0 ? selCategories : null, locations: selLocations.length > 0 ? selLocations : null }), className: "w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50", children: saving ? t('common.loading') : saved ? t('auto_response.saved', 'Сохранено ✓') : t('common.save') }) ] }); } export default function ProfilePage() { return /*#__PURE__*/ _jsx(Suspense, { fallback: null, children: /*#__PURE__*/ _jsx(ProfilePageInner, {}) }); } function ProfilePageInner() { const router = useRouter(); const searchParams = useSearchParams(); const { data: session, isPending } = useSession(); const { t, locale } = useLocale(); const validTabs = [ 'info', 'finance', 'cards', 'notifications', 'reviews', 'referral', 'auto_response', 'site' ]; const initialTab = searchParams.get('tab') ?? 'info'; const [activeTab, setActiveTab] = useState(validTabs.includes(initialTab) ? initialTab : 'info'); const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [saved, setSaved] = useState(false); const [error, setError] = useState(''); const [formData, setFormData] = useState({ firstName: '', lastName: '', phone: '', bio: '', locale: 'el' }); const [selectedLanguages, setSelectedLanguages] = useState([]); // Specialist cards const [cards, setCards] = useState([]); const [maxCards, setMaxCards] = useState(1); const [cardsLoading, setCardsLoading] = useState(false); const [openCardId, setOpenCardId] = useState(null); const [creatingCard, setCreatingCard] = useState(false); const [newCardTitle, setNewCardTitle] = useState(''); const [showNewCardForm, setShowNewCardForm] = useState(false); const [showUpgradeModal, setShowUpgradeModal] = useState(false); // Reference data const [categories, setCategories] = useState([]); const [locationTree, setLocationTree] = useState([]); // Become specialist const [becomingSpecialist, setBecomingSpecialist] = useState(false); const [avatarUploading, setAvatarUploading] = useState(false); const fileRef = useRef(null); // Notification preferences const [notifyNewTasks, setNotifyNewTasks] = useState(false); const [notifMessages, setNotifMessages] = useState(true); const [notifySaving, setNotifySaving] = useState(false); const [notifySaved, setNotifySaved] = useState(false); // Email verification resend const [resendState, setResendState] = useState('idle'); // Referral info const [referralCode, setReferralCode] = useState(null); const [referralCount, setReferralCount] = useState(0); const [referralCopied, setReferralCopied] = useState(false); const [referralLoaded, setReferralLoaded] = useState(false); // Balance top-up modal const [showTopUpModal, setShowTopUpModal] = useState(false); const [topUpAmount, setTopUpAmount] = useState(10); const [topUpLoading, setTopUpLoading] = useState(false); const [topUpError, setTopUpError] = useState(''); const [balanceHistory, setBalanceHistory] = useState([]); // Plan data + statuses const [dashData, setDashData] = useState(null); const [myStatuses, setMyStatuses] = useState([]); const [statusToggling, setStatusToggling] = useState(null); const [personalSiteSlug, setPersonalSiteSlug] = useState(''); const [slugSaving, setSlugSaving] = useState(false); const [slugSaved, setSlugSaved] = useState(false); const [slugCopied, setSlugCopied] = useState(false); const [slugError, setSlugError] = useState(''); const [showContactInfo, setShowContactInfo] = useState(false); const [siteSettings, setSiteSettings] = useState({}); const [siteSettingsSaving, setSiteSettingsSaving] = useState(false); const [siteStats, setSiteStats] = useState(null); const [siteStatsLoading, setSiteStatsLoading] = useState(false); const [autoResponse, setAutoResponse] = useState(null); const [arLoaded, setArLoaded] = useState(false); const [arSaving, setArSaving] = useState(false); const [arSaved, setArSaved] = useState(false); async function handleTopUp() { const amount = Number(topUpAmount); if (!amount || amount < 1) return; setTopUpLoading(true); setTopUpError(''); try { const { url, params } = await api.initiateTopUp(amount); // Build and auto-submit form to ePay const form = document.createElement('form'); form.method = 'POST'; form.action = url; Object.entries(params).forEach(([k, v])=>{ const input = document.createElement('input'); input.type = 'hidden'; input.name = k; input.value = v; form.appendChild(input); }); document.body.appendChild(form); form.submit(); } catch (e) { setTopUpError(e?.message || t('profile.balance.topup.error')); setTopUpLoading(false); } } async function handleResendVerification() { if (!user?.email || resendState !== 'idle') return; setResendState('sending'); const callbackURL = `${window.location.origin}/profile`; const result = await authClient.sendVerificationEmail({ email: user.email, callbackURL }); if (result?.error) { setResendState('idle'); } else { setResendState('sent'); } } process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (activeTab !== 'referral' || referralLoaded) return; api.getMyReferralInfo().then((r)=>{ setReferralCode(r.referralCode); setReferralCount(r.referralCount); }).catch(()=>{}).finally(()=>setReferralLoaded(true)); }, [ activeTab ]); // Reviews const [myReviews, setMyReviews] = useState(null); const [reviewsLoading, setReviewsLoading] = useState(false); const [myRating, setMyRating] = useState(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (activeTab !== 'reviews' || myReviews !== null || reviewsLoading) return; setReviewsLoading(true); api.getMyReviews().then(setMyReviews).catch(()=>setMyReviews([])).finally(()=>setReviewsLoading(false)); }, [ activeTab ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (activeTab !== 'site' || siteStats !== null || siteStatsLoading) return; setSiteStatsLoading(true); api.getSiteStats().then((res)=>setSiteStats(res.days)).catch(()=>setSiteStats([])).finally(()=>setSiteStatsLoading(false)); }, [ activeTab ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); }, [ session, isPending ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; Promise.all([ api.request('/users/me'), api.getCategories(), api.getLocations(), api.getMyDashboard().catch(()=>null), api.getMyStatuses().catch(()=>[]), api.getBalanceHistory(8).catch(()=>[]) ]).then(([u, cats, locs, dash, statusRes, history])=>{ setUser(u); setFormData({ firstName: u.firstName ?? '', lastName: u.lastName ?? '', phone: u.phone ?? '', bio: u.bio ?? '', locale: u.locale ?? 'el' }); setSelectedLanguages(u.languages ?? []); setNotifyNewTasks(u.notifyNewTasks ?? false); setNotifMessages(u.notifMessages ?? true); setCategories(cats); setLocationTree(locs); setDashData(dash); setMyStatuses((statusRes ?? []).filter((s)=>s.isActive).map((s)=>s.statusType)); setBalanceHistory(history); setPersonalSiteSlug(u.personalSiteSlug ?? ''); setShowContactInfo(u.showContactInfo ?? false); setSiteSettings(u.siteSettings ?? {}); if (u.role === 'specialist' || u.role === 'admin') { loadCards(); api.getUserRating(u.id).then((r)=>setMyRating(r.avg)).catch(()=>{}); } }).catch(()=>{}).finally(()=>setLoading(false)); }, [ session ]); async function loadCards() { setCardsLoading(true); try { const { cards: c, maxCards: m } = await api.getMySpecialistCards(); setCards(c); setMaxCards(m); } catch {} finally{ setCardsLoading(false); } } async function handleSubmit(e) { e.preventDefault(); setError(''); setSaving(true); try { const updated = await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ firstName: formData.firstName, lastName: formData.lastName, phone: formData.phone || undefined, bio: formData.bio || undefined, locale: formData.locale, languages: selectedLanguages, personalSiteSlug: personalSiteSlug || undefined, showContactInfo }) }); setUser(updated); setSaved(true); setTimeout(()=>setSaved(false), 2500); } catch (err) { setError(err.message || t('common.error')); } finally{ setSaving(false); } } async function handleBecomeSpecialist() { setBecomingSpecialist(true); setError(''); try { const updated = await api.request('/users/me/become-specialist', { method: 'POST' }); setUser(updated); setActiveTab('cards'); loadCards(); } catch (err) { setError(err.message || t('common.error')); } finally{ setBecomingSpecialist(false); } } async function handleSaveSiteSlug() { setSlugSaving(true); setSlugError(''); try { const updated = await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ personalSiteSlug: personalSiteSlug || null }) }); setUser(updated); setPersonalSiteSlug(updated.personalSiteSlug ?? ''); setSlugSaved(true); setTimeout(()=>setSlugSaved(false), 2500); } catch (err) { const code = err?.code ?? ''; if (code === 'SLUG_TAKEN' || err.message === 'This URL is already taken') { setSlugError(t('profile.site.slug_taken', 'Этот адрес уже занят')); } else { setSlugError(err.message || t('common.error')); } } finally{ setSlugSaving(false); } } async function handleSaveSiteSettings(newSettings) { setSiteSettings(newSettings); setSiteSettingsSaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ siteSettings: newSettings }) }); } catch {} finally{ setSiteSettingsSaving(false); } } async function handleAvatarChange(e) { const file = e.target.files?.[0]; if (!file) return; setAvatarUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); const fullUrl = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}${url}`; await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ image: fullUrl }) }); setUser((prev)=>({ ...prev, image: fullUrl })); } catch { setError(t('profile.upload.error')); } finally{ setAvatarUploading(false); } } async function handleCreateCard() { if (!newCardTitle.trim()) return; setCreatingCard(true); try { const card = await api.createSpecialistCard({ title: newCardTitle.trim() }); setCards((prev)=>[ ...prev, card ]); setOpenCardId(card.id); setNewCardTitle(''); setShowNewCardForm(false); } catch (err) { setError(err.message || t('common.error')); } finally{ setCreatingCard(false); } } async function handleDeleteCard(id) { if (!confirm(t('profile.cards.delete_confirm'))) return; try { await api.deleteSpecialistCard(id); setCards((prev)=>prev.filter((c)=>c.id !== id)); if (openCardId === id) setOpenCardId(null); } catch (err) { setError(err.message || t('common.error')); } } if (isPending || loading) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const dateLocale = locale === 'en' ? 'en-US' : locale === 'ru' ? 'ru-RU' : 'el-GR'; const isSpecialist = user?.role === 'specialist'; const isAdmin = user?.role === 'admin'; const showSpecialistTabs = isSpecialist || isAdmin; const initials = user ? `${user.firstName?.[0] ?? ''}${user.lastName?.[0] ?? ''}`.toUpperCase() : '?'; const hasAutoResponse = !!dashData?.features?.hasAutoResponse; const tabIcons = { info: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" }) }), finance: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 6v12m-3-2.818l.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.879 4.006 0l.415.33M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), cards: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M20.25 14.15v4.073a2.25 2.25 0 01-2.25 2.25h-12a2.25 2.25 0 01-2.25-2.25V6a2.25 2.25 0 012.25-2.25h4.073M15.75 3h5.25v5.25M15.75 3l-9 9" }) }), notifications: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), reviews: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.562.562 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.562.562 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" }) }), referral: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244" }) }), auto_response: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" }) }), site: /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" }) }) }; const tabs = showSpecialistTabs ? [ { id: 'info', label: t('profile.tab.info') }, { id: 'finance', label: t('profile.tab.finance') }, { id: 'cards', label: t('profile.tab.cards') }, { id: 'notifications', label: t('profile.tab.notifications') }, { id: 'reviews', label: t('profile.tab.reviews') }, { id: 'referral', label: t('profile.tab.referral') }, ...hasAutoResponse ? [ { id: 'auto_response', label: t('profile.tab.auto_response', 'Авто-ответ') } ] : [], ...dashData?.features?.hasPersonalSite ? [ { id: 'site', label: t('profile.tab.site') } ] : [] ] : [ { id: 'info', label: t('profile.tab.info') }, { id: 'finance', label: t('profile.tab.finance') }, { id: 'notifications', label: t('profile.tab.notifications') }, { id: 'reviews', label: t('profile.tab.reviews') }, { id: 'referral', label: t('profile.tab.referral') }, ...dashData?.features?.hasPersonalSite ? [ { id: 'site', label: t('profile.tab.site') } ] : [] ]; return /*#__PURE__*/ _jsxs("div", { className: "max-w-4xl mx-auto px-4 py-8", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-4 mb-6", children: [ /*#__PURE__*/ _jsx("div", { className: "w-14 h-14 rounded-full flex-shrink-0 overflow-hidden border-2 border-white/40 flex items-center justify-center text-blue-700 text-xl font-bold bg-blue-100 cursor-pointer", onClick: ()=>{ setActiveTab('info'); fileRef.current?.click(); }, title: t('profile.photo.change'), children: user?.image ? /*#__PURE__*/ _jsx("img", { src: user.image, alt: user.name, className: "w-full h-full object-cover" }) : initials }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-xl font-bold text-white leading-tight", children: user?.firstName ? `${user.firstName} ${user.lastName ?? ''}`.trim() : user?.name ?? t('nav.profile') }), myRating && /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-1 mt-0.5", children: [ /*#__PURE__*/ _jsx("span", { className: "text-yellow-300", children: "★" }), /*#__PURE__*/ _jsx("span", { className: "font-semibold text-white text-sm", children: Number(myRating).toFixed(1) }), myReviews !== null && myReviews.length > 0 && /*#__PURE__*/ _jsxs("span", { className: "text-white/60 text-xs", children: [ "(", myReviews.length, ")" ] }) ] }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-6 items-start", children: [ tabs.length > 1 && /*#__PURE__*/ _jsx("aside", { className: "w-52 shrink-0 hidden sm:block", children: /*#__PURE__*/ _jsx("nav", { className: "rounded-2xl overflow-hidden bg-white/10 backdrop-blur-sm", children: tabs.map((tab)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setActiveTab(tab.id), className: `w-full text-left px-4 py-3 text-sm font-medium transition border-b border-white/10 last:border-0 flex items-center gap-3 ${activeTab === tab.id ? 'bg-white text-blue-700' : 'text-white/80 hover:bg-white/10 hover:text-white'}`, children: [ tabIcons[tab.id], /*#__PURE__*/ _jsx("span", { children: tab.label }) ] }, tab.id)) }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ tabs.length > 1 && /*#__PURE__*/ _jsx("div", { className: "flex sm:hidden bg-white/15 backdrop-blur rounded-xl p-1 mb-4 gap-1 overflow-x-auto", children: tabs.map((tab)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setActiveTab(tab.id), className: `flex-1 min-w-fit px-3 py-2 text-xs font-medium rounded-lg transition whitespace-nowrap flex flex-col items-center gap-0.5 ${activeTab === tab.id ? 'bg-white text-blue-700 shadow-sm' : 'text-white/80 hover:text-white hover:bg-white/10'}`, children: [ tabIcons[tab.id], /*#__PURE__*/ _jsx("span", { children: tab.label }) ] }, tab.id)) }), activeTab === 'cards' && /*#__PURE__*/ _jsxs("div", { className: "space-y-4", children: [ error && /*#__PURE__*/ _jsx("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between", children: [ /*#__PURE__*/ _jsxs("p", { className: "text-sm text-white/70", children: [ t('profile.cards.count'), ": ", cards.length, " / ", maxCards === null ? '∞' : maxCards ] }), /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>{ if (maxCards !== null && cards.length >= maxCards) { setShowUpgradeModal(true); } else { setShowNewCardForm(true); } }, className: "flex items-center gap-1.5 text-sm font-medium text-white hover:text-white/80", children: [ "+ ", t('profile.cards.add') ] }) ] }), showNewCardForm && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-blue-200 p-4 space-y-3", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('profile.cards.new_title') }), /*#__PURE__*/ _jsx("input", { value: newCardTitle, onChange: (e)=>setNewCardTitle(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') handleCreateCard(); }, maxLength: 200, placeholder: t('profile.cards.placeholder'), autoFocus: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: handleCreateCard, disabled: creatingCard || !newCardTitle.trim(), className: "px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium disabled:opacity-50", children: creatingCard ? '...' : t('profile.cards.create') }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>{ setShowNewCardForm(false); setNewCardTitle(''); }, className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg text-sm font-medium", children: t('profile.cards.cancel') }) ] }) ] }), cardsLoading && /*#__PURE__*/ _jsx("div", { className: "text-center py-10 text-white/70", children: t('common.loading') }), !cardsLoading && cards.length === 0 && !showNewCardForm && /*#__PURE__*/ _jsxs("div", { className: "text-center py-14 border-2 border-dashed border-white/30 rounded-xl", children: [ /*#__PURE__*/ _jsx("p", { className: "text-white/70 text-sm mb-3", children: t('profile.cards.empty') }), /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setShowNewCardForm(true), className: "text-sm text-white font-medium hover:underline", children: [ "+ ", t('profile.cards.create_first') ] }) ] }), cards.map((card)=>/*#__PURE__*/ _jsx(SpecialistCardEditor, { card: card, isOpen: openCardId === card.id, onToggle: ()=>setOpenCardId(openCardId === card.id ? null : card.id), onUpdate: (updated)=>setCards((prev)=>prev.map((c)=>c.id === updated.id ? updated : c)), onDelete: ()=>handleDeleteCard(card.id), categories: categories, locationTree: locationTree, catLocale: catLocale, locale: locale }, card.id)) ] }), activeTab === 'site' && /*#__PURE__*/ _jsxs("div", { className: "space-y-5", children: [ /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-4", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-1", children: t('profile.site.title') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400", children: t('profile.site_slug_hint') }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-xs font-medium text-gray-500 mb-1.5", children: t('profile.site.url_label') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [ /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-400 shrink-0", children: "canhelp.gr/site/" }), /*#__PURE__*/ _jsx("input", { value: personalSiteSlug, onChange: (e)=>setPersonalSiteSlug(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, '')), placeholder: "my-slug", maxLength: 50, className: "flex-1 min-w-32 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: handleSaveSiteSlug, disabled: slugSaving, className: "px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50", children: slugSaving ? t('profile.saving') : t('common.save') }), slugSaved && /*#__PURE__*/ _jsxs("span", { className: "text-sm text-green-600", children: [ "✓ ", t('profile.saved') ] }), personalSiteSlug && /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>{ navigator.clipboard.writeText(`${window.location.origin}/site/${personalSiteSlug}`); setSlugCopied(true); setTimeout(()=>setSlugCopied(false), 2000); }, className: "px-3 py-2 border border-gray-300 rounded-lg text-sm text-gray-600 hover:bg-gray-50 flex items-center gap-1.5", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }), slugCopied ? t('profile.site.copied') : t('profile.site.copy') ] }), /*#__PURE__*/ _jsxs("a", { href: `/site/${personalSiteSlug}`, target: "_blank", rel: "noopener noreferrer", className: "px-3 py-2 border border-blue-200 bg-blue-50 rounded-lg text-sm text-blue-600 hover:bg-blue-100 flex items-center gap-1.5", children: [ t('profile.site_open'), /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) }) ] }) ] }) ] }), slugError && /*#__PURE__*/ _jsx("p", { className: "text-xs text-red-500", children: slugError }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-4", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-800", children: t('profile.site.visible_title') }), siteSettingsSaving && /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400", children: t('profile.saving', 'Сохранение...') }) ] }), /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: [ { key: 'showBio', label: t('profile.site.visible.bio', 'Биография') }, { key: 'showRating', label: t('profile.site.visible.rating', 'Рейтинг и отзывы') }, { key: 'showReviews', label: t('profile.site.visible.reviews', 'Раздел с отзывами') }, { key: 'showServices', label: t('profile.site.visible.services', 'Карточки услуг') }, { key: 'showPortfolio', label: t('profile.site.visible.portfolio', 'Портфолио') }, { key: 'showPhone', label: t('profile.site.visible.contacts', 'Контактный телефон') }, { key: 'showFullLastName', label: t('profile.site.visible.full_last_name', 'Фамилия полностью') }, { key: 'showStatus', label: t('profile.site.visible.status', 'Статус «Готов помочь»') } ].map(({ key, label })=>{ const checked = siteSettings[key] !== false // undefined = true by default ; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-3 cursor-pointer group", children: [ /*#__PURE__*/ _jsx("div", { className: `w-5 h-5 rounded border-2 flex items-center justify-center transition shrink-0 ${checked ? 'bg-blue-600 border-blue-600' : 'bg-white border-gray-300 group-hover:border-blue-400'}`, onClick: ()=>{ const next = { ...siteSettings, [key]: !checked }; handleSaveSiteSettings(next); }, children: checked && /*#__PURE__*/ _jsx("svg", { className: "w-3 h-3 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 12.75l6 6 9-13.5" }) }) }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-700 select-none", onClick: ()=>{ const next = { ...siteSettings, [key]: !checked }; handleSaveSiteSettings(next); }, children: label }) ] }, key); }) }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-4", children: t('profile.site.edit_bio_hint', 'Имя и фото всегда отображаются') }), /*#__PURE__*/ _jsxs("div", { className: "mt-6 pt-4 border-t border-gray-100", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('profile.site.theme', 'Тема оформления') }), /*#__PURE__*/ _jsx("div", { className: "flex gap-3", children: [ { value: 'dark', label: t('profile.site.theme.dark', 'Тёмная'), icon: '🌙' }, { value: 'light', label: t('profile.site.theme.light', 'Светлая'), icon: '☀️' } ].map((opt)=>{ const selected = (siteSettings.siteTheme ?? 'dark') === opt.value; return /*#__PURE__*/ _jsxs("button", { onClick: ()=>handleSaveSiteSettings({ ...siteSettings, siteTheme: opt.value }), className: `flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border-2 text-sm font-medium transition ${selected ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-200 bg-white text-gray-500 hover:border-gray-300'}`, children: [ /*#__PURE__*/ _jsx("span", { children: opt.icon }), opt.label ] }, opt.value); }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("div", { className: "flex items-center justify-between mb-4", children: /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-800", children: t('profile.site.stats.title', 'Аналитика сайта') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.site.stats.days', 'последние 30 дней') }) ] }) }), !personalSiteSlug ? /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-400 py-4 text-center", children: t('profile.site.stats.no_slug', 'Укажите адрес сайта, чтобы видеть статистику') }) : siteStatsLoading || siteStats === null ? /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-400 py-4 text-center", children: t('profile.site.stats.loading', 'Загрузка аналитики...') }) : (()=>{ const totalViews = siteStats.reduce((s, d)=>s + d.views, 0); const totalUnique = siteStats.reduce((s, d)=>s + d.unique, 0); const totalMessages = siteStats.reduce((s, d)=>s + d.messages, 0); // Area chart helpers const days = siteStats.map((d)=>d.date); const seriesDef = [ { vals: siteStats.map((d)=>d.views), color: '#3b82f6', fill: '#3b82f615', label: t('profile.site.stats.views', 'Просмотры') }, { vals: siteStats.map((d)=>d.unique), color: '#8b5cf6', fill: '#8b5cf610', label: t('profile.site.stats.unique', 'Уникальные') }, { vals: siteStats.map((d)=>d.messages), color: '#10b981', fill: '#10b98110', label: t('profile.site.stats.messages', 'Сообщения') } ]; const maxVal = Math.max(...seriesDef.flatMap((s)=>s.vals), 1); const W = 580; const H = 160; const padL = 36; const padB = 22; const chartW = W - padL - 4; const chartH = H - padB; const stepX = chartW / (days.length - 1); function pts(vals) { return vals.map((v, i)=>[ padL + i * stepX, chartH - v / maxVal * chartH ]); } function smoothPath(points) { if (points.length < 2) return ''; let d = `M ${points[0][0].toFixed(1)} ${points[0][1].toFixed(1)}`; for(let i = 1; i < points.length; i++){ const cpx = ((points[i - 1][0] + points[i][0]) / 2).toFixed(1); d += ` C ${cpx} ${points[i - 1][1].toFixed(1)} ${cpx} ${points[i][1].toFixed(1)} ${points[i][0].toFixed(1)} ${points[i][1].toFixed(1)}`; } return d; } function areaPath(vals) { const points = pts(vals); const line = smoothPath(points); if (!line) return ''; const lastX = points[points.length - 1][0].toFixed(1); return `${line} L ${lastX} ${chartH.toFixed(1)} L ${padL.toFixed(1)} ${chartH.toFixed(1)} Z`; } function fmtY(v) { return v >= 1000 ? `${Math.round(v / 1000)}K` : String(v); } const yTicks = [ 0, Math.round(maxVal / 3), Math.round(maxVal * 2 / 3), maxVal ]; const xTicks = days.map((d, i)=>({ i, label: d.slice(8) })).filter((_, i)=>i % 7 === 0 || i === days.length - 1); return /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-3 gap-3 mb-5", children: [ { label: t('profile.site.stats.total_views', 'Просмотры'), value: totalViews, color: 'text-blue-600', bg: 'bg-blue-50' }, { label: t('profile.site.stats.total_unique', 'Уник. посетители'), value: totalUnique, color: 'text-violet-600', bg: 'bg-violet-50' }, { label: t('profile.site.stats.total_messages', 'Сообщения'), value: totalMessages, color: 'text-emerald-600', bg: 'bg-emerald-50' } ].map((card)=>/*#__PURE__*/ _jsxs("div", { className: `${card.bg} rounded-xl p-3 text-center`, children: [ /*#__PURE__*/ _jsx("div", { className: `text-2xl font-bold ${card.color}`, children: card.value }), /*#__PURE__*/ _jsx("div", { className: "text-xs text-gray-500 mt-0.5", children: card.label }) ] }, card.label)) }), /*#__PURE__*/ _jsx("div", { className: "flex items-center gap-4 mb-2", children: seriesDef.map((s)=>/*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5 text-xs text-gray-500", children: [ /*#__PURE__*/ _jsx("span", { className: "w-3 h-0.5 inline-block rounded", style: { background: s.color } }), s.label ] }, s.label)) }), /*#__PURE__*/ _jsx("div", { className: "overflow-x-auto", children: /*#__PURE__*/ _jsxs("svg", { viewBox: `0 0 ${W} ${H + 12}`, className: "w-full", style: { minWidth: 320 }, children: [ yTicks.map((v)=>{ const y = chartH - v / maxVal * chartH; return /*#__PURE__*/ _jsxs("g", { children: [ /*#__PURE__*/ _jsx("line", { x1: padL, y1: y, x2: W - 4, y2: y, stroke: "#f3f4f6", strokeWidth: 1 }), /*#__PURE__*/ _jsx("text", { x: padL - 5, y: y + 3.5, textAnchor: "end", fontSize: 9, fill: "#9ca3af", children: fmtY(v) }) ] }, v); }), xTicks.map(({ i })=>/*#__PURE__*/ _jsx("line", { x1: padL + i * stepX, y1: 0, x2: padL + i * stepX, y2: chartH, stroke: "#f9fafb", strokeWidth: 1 }, `vg-${i}`)), xTicks.map(({ i, label })=>/*#__PURE__*/ _jsx("text", { x: padL + i * stepX, y: H + 10, textAnchor: "middle", fontSize: 9, fill: "#9ca3af", children: label }, i)), seriesDef.map((s, si)=>/*#__PURE__*/ _jsx("path", { d: areaPath(s.vals), fill: s.fill }, `fill-${si}`)), seriesDef.map((s, si)=>/*#__PURE__*/ _jsx("path", { d: smoothPath(pts(s.vals)), fill: "none", stroke: s.color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }, `line-${si}`)), seriesDef.map((s, si)=>{ const points = pts(s.vals); const last = points[points.length - 1]; return /*#__PURE__*/ _jsx("circle", { cx: last[0], cy: last[1], r: 4, fill: "white", stroke: s.color, strokeWidth: 2 }, `dot-${si}`); }), /*#__PURE__*/ _jsx("line", { x1: padL, y1: chartH, x2: W - 4, y2: chartH, stroke: "#e5e7eb", strokeWidth: 1 }) ] }) }) ] }); })() ] }) ] }), activeTab === 'reviews' && /*#__PURE__*/ _jsx("div", { className: "space-y-4", children: myReviews === null ? /*#__PURE__*/ _jsx("div", { className: "text-center py-10 text-white/70", children: t('common.loading') }) : myReviews.length === 0 ? /*#__PURE__*/ _jsxs("div", { className: "text-center py-20 text-white/60", children: [ /*#__PURE__*/ _jsx("p", { className: "text-4xl mb-3", children: "⭐" }), /*#__PURE__*/ _jsx("p", { children: t('profile.no_reviews') }) ] }) : myReviews.map(({ review, author })=>/*#__PURE__*/ _jsx("div", { className: "bg-white rounded-xl border border-gray-200 p-4", children: /*#__PURE__*/ _jsxs("div", { className: "flex items-start gap-3", children: [ /*#__PURE__*/ _jsx("div", { className: "w-9 h-9 rounded-full bg-gray-100 flex-shrink-0 flex items-center justify-center text-gray-600 text-sm font-bold overflow-hidden", children: author?.image ? /*#__PURE__*/ _jsx("img", { src: author.image, alt: author.name, className: "w-full h-full object-cover" }) : author?.name?.[0]?.toUpperCase() ?? '?' }), /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-1", children: [ /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-800", children: author?.name ?? '—' }), /*#__PURE__*/ _jsxs("span", { className: "text-yellow-400", children: [ '★'.repeat(review.rating), '☆'.repeat(5 - review.rating) ] }) ] }), review.comment && /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-600", children: review.comment }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-1", children: new Date(review.createdAt).toLocaleDateString() }) ] }) ] }) }, review.id)) }), activeTab === 'finance' && /*#__PURE__*/ _jsxs("div", { className: "space-y-5", children: [ /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-3", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('profile.balance') }), /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setTopUpAmount(10); setTopUpError(''); setShowTopUpModal(true); }, className: "flex items-center gap-1.5 text-sm font-medium text-blue-600 hover:text-blue-700 hover:bg-blue-50 px-3 py-1.5 rounded-lg transition-colors", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('profile.balance.topup') ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 p-4 bg-green-50 rounded-xl border border-green-100", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-6 h-6 text-green-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), /*#__PURE__*/ _jsxs("span", { className: "text-xl font-bold text-green-700", children: [ parseFloat(user?.balance ?? '0').toFixed(2), " EUR" ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-2", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-sm font-semibold text-gray-800", children: t('profile.balance.history', 'Архив операций') }), /*#__PURE__*/ _jsx("span", { className: "text-xs text-gray-400", children: t('profile.balance.history.last', 'Последние операции') }) ] }), balanceHistory.length === 0 ? /*#__PURE__*/ _jsx("div", { className: "rounded-xl border border-dashed border-gray-200 px-4 py-6 text-sm text-gray-400 text-center", children: t('profile.balance.history.empty', 'Операций пока нет') }) : /*#__PURE__*/ _jsx("div", { className: "space-y-2", children: balanceHistory.map((entry)=>{ const isCredit = entry.direction === 'credit'; const amount = Number(entry.amount).toFixed(2); const badgeClass = isCredit ? 'bg-emerald-50 text-emerald-700 border-emerald-100' : 'bg-rose-50 text-rose-700 border-rose-100'; const title = entry.kind === 'topup' ? t('profile.balance.history.kind.topup', 'Пополнение баланса') : entry.kind === 'plan_purchase' ? t('profile.balance.history.kind.plan_purchase', 'Списание за тариф') : entry.kind === 'admin_topup' ? t('profile.balance.history.kind.admin_topup', 'Пополнение администратором') : t('profile.balance.history.kind.admin_adjustment', 'Корректировка администратором'); return /*#__PURE__*/ _jsxs("div", { className: "rounded-xl border border-gray-200 px-4 py-3", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-start justify-between gap-3", children: [ /*#__PURE__*/ _jsxs("div", { className: "min-w-0", children: [ /*#__PURE__*/ _jsx("div", { className: "text-sm font-medium text-gray-900", children: entry.description || title }), /*#__PURE__*/ _jsx("div", { className: "text-xs text-gray-500 mt-1", children: new Date(entry.createdAt).toLocaleString(dateLocale) }) ] }), /*#__PURE__*/ _jsxs("div", { className: `shrink-0 rounded-full border px-2.5 py-1 text-xs font-semibold ${badgeClass}`, children: [ isCredit ? '+' : '-', amount, " ", entry.currency ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-2 text-xs text-gray-500", children: [ t('profile.balance.history.balance_after', 'Баланс после'), ": ", Number(entry.balanceAfter).toFixed(2), " ", entry.currency ] }) ] }, entry.id); }) }) ] }) ] }), showTopUpModal && /*#__PURE__*/ _jsx("div", { className: "fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-black/40 backdrop-blur-sm", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl shadow-2xl w-full max-w-sm p-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mb-5", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-gray-900", children: t('profile.balance.topup.title') }), /*#__PURE__*/ _jsx("button", { onClick: ()=>setShowTopUpModal(false), className: "text-gray-400 hover:text-gray-600", children: /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }) ] }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500 mb-3", children: t('profile.balance.topup.hint') }), /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-4 gap-2 mb-4", children: [ 5, 10, 20, 50 ].map((v)=>/*#__PURE__*/ _jsxs("button", { onClick: ()=>setTopUpAmount(v), className: `py-2 rounded-xl text-sm font-semibold border transition-colors ${Number(topUpAmount) === v ? 'bg-blue-600 text-white border-blue-600' : 'border-gray-200 text-gray-700 hover:border-blue-400'}`, children: [ "€", v ] }, v)) }), /*#__PURE__*/ _jsxs("div", { className: "mb-5", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.balance.topup.amount') }), /*#__PURE__*/ _jsxs("div", { className: "relative", children: [ /*#__PURE__*/ _jsx("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm", children: "€" }), /*#__PURE__*/ _jsx("input", { type: "number", min: "1", max: "9999", step: "1", value: topUpAmount, onChange: (e)=>setTopUpAmount(e.target.value), className: "w-full pl-7 pr-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), topUpError && /*#__PURE__*/ _jsx("p", { className: "text-sm text-red-600 mb-3", children: topUpError }), /*#__PURE__*/ _jsx("button", { onClick: handleTopUp, disabled: topUpLoading || !Number(topUpAmount) || Number(topUpAmount) < 1, className: "w-full py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed text-white font-semibold rounded-xl transition-colors flex items-center justify-center gap-2", children: topUpLoading ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 animate-spin", fill: "none", viewBox: "0 0 24 24", children: [ /*#__PURE__*/ _jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /*#__PURE__*/ _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v8z" }) ] }), t('profile.balance.topup.loading') ] }) : t('profile.balance.topup.submit') }) ] }) }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-3", children: t('profile.plan.title') }), user?.plan ? /*#__PURE__*/ _jsxs("div", { className: "flex items-start gap-3 p-4 bg-blue-50 rounded-xl border border-blue-100", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-6 h-6 text-blue-500 shrink-0 mt-0.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" }) }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-900", children: user.plan.name }), user.plan.description && /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: user.plan.description }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-3 mt-2 text-xs text-gray-500", children: [ /*#__PURE__*/ _jsxs("span", { className: "font-medium text-blue-700", children: [ user.plan.price, " ", user.plan.currency ] }), user.plan.maxCards != null ? /*#__PURE__*/ _jsxs("span", { children: [ t('profile.plan.cards_up_to'), " ", user.plan.maxCards ] }) : /*#__PURE__*/ _jsx("span", { children: t('profile.plan.cards_unlimited') }), user.plan.maxTasks != null && /*#__PURE__*/ _jsxs("span", { children: [ t('profile.plan.tasks_up_to'), " ", user.plan.maxTasks ] }), user.plan.maxOffers != null && /*#__PURE__*/ _jsxs("span", { children: [ t('profile.plan.offers_up_to'), " ", user.plan.maxOffers ] }), /*#__PURE__*/ _jsx("span", { className: user.planExpiresAt && new Date(user.planExpiresAt) < new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) ? 'text-red-500 font-medium' : '', children: user.planExpiresAt ? `${t('profile.plan.valid_until')} ${new Date(user.planExpiresAt).toLocaleDateString()}` : t('profile.plan.no_expiry') }) ] }), (user.plan.features ?? []).length > 0 && /*#__PURE__*/ _jsx("ul", { className: "mt-2 space-y-0.5", children: user.plan.features.map((f, i)=>/*#__PURE__*/ _jsxs("li", { className: "text-xs text-gray-600 flex items-center gap-1.5", children: [ /*#__PURE__*/ _jsx("span", { className: "text-green-500", children: "✓" }), " ", f ] }, i)) }) ] }) ] }) : /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 p-4 bg-gray-50 rounded-xl border border-gray-100", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-700", children: t('profile.plan.basic') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.plan.contact_upgrade') }) ] }) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "text-center", children: /*#__PURE__*/ _jsxs("a", { href: "/pricing", className: "inline-flex items-center gap-1.5 text-sm font-medium text-white/70 hover:text-white transition", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 7l5 5m0 0l-5 5m5-5H6" }) }), t('pricing.title', 'Тарифы') ] }) }) ] }), activeTab !== 'cards' && activeTab !== 'reviews' && activeTab !== 'finance' && activeTab !== 'site' && /*#__PURE__*/ _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [ error && /*#__PURE__*/ _jsx("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), saved && /*#__PURE__*/ _jsxs("div", { className: "bg-green-50 text-green-700 p-3 rounded-lg text-sm", children: [ "✓ ", t('profile.saved') ] }), activeTab === 'notifications' && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('notifications.title') }), notifySaved && /*#__PURE__*/ _jsxs("div", { className: "bg-green-50 text-green-700 p-3 rounded-lg text-sm", children: [ "✓ ", t('notifications.saved') ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-start justify-between gap-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsx("p", { className: "font-medium text-gray-800 text-sm", children: t('chat.notif_messages') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: t('notifications.messages.desc') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: notifySaving, onClick: async ()=>{ const next = !notifMessages; setNotifMessages(next); setNotifySaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ notifMessages: next }) }); setNotifySaved(true); setTimeout(()=>setNotifySaved(false), 2500); } catch { setNotifMessages(!next); } finally{ setNotifySaving(false); } }, className: `relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 ${notifMessages ? 'bg-blue-600' : 'bg-gray-200'}`, role: "switch", "aria-checked": notifMessages, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notifMessages ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }), showSpecialistTabs && /*#__PURE__*/ _jsxs("div", { className: `flex items-start justify-between gap-4 ${!user?.plan?.notifyNewTasks ? 'opacity-60' : ''}`, children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1", children: [ /*#__PURE__*/ _jsx("p", { className: "font-medium text-gray-800 text-sm", children: t('notifications.email.new_tasks') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: t('notifications.email.new_tasks.desc') }), !user?.plan?.notifyNewTasks && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-amber-600 mt-1", children: [ "\uD83D\uDD12 ", t('notifications.plan_required') ] }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: notifySaving || !user?.plan?.notifyNewTasks, onClick: async ()=>{ const next = !notifyNewTasks; setNotifyNewTasks(next); setNotifySaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ notifyNewTasks: next }) }); setNotifySaved(true); setTimeout(()=>setNotifySaved(false), 2500); } catch { setNotifyNewTasks(!next); } finally{ setNotifySaving(false); } }, className: `relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 ${notifyNewTasks ? 'bg-blue-600' : 'bg-gray-200'}`, role: "switch", "aria-checked": notifyNewTasks, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notifyNewTasks ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }), activeTab === 'referral' && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-5", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('profile.referral.title') }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500", children: t('profile.referral.desc') }), !referralLoaded ? /*#__PURE__*/ _jsx("div", { className: "text-sm text-gray-400", children: t('common.loading') }) : referralCode ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs font-medium text-gray-500 mb-1.5", children: t('profile.referral.link_label') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ _jsx("input", { readOnly: true, value: `${"undefined" !== 'undefined' ? window.location.origin : ''}/register?ref=${referralCode}`, className: "flex-1 text-sm border border-gray-200 rounded-lg px-3 py-2 bg-gray-50 text-gray-700 focus:outline-none" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>{ navigator.clipboard.writeText(`${window.location.origin}/register?ref=${referralCode}`); setReferralCopied(true); setTimeout(()=>setReferralCopied(false), 2000); }, className: "px-3 py-2 rounded-lg border border-gray-200 text-sm font-medium hover:bg-gray-50 transition whitespace-nowrap", children: referralCopied ? t('profile.referral.copied') : t('profile.referral.copy') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 p-4 bg-blue-50 rounded-xl", children: [ /*#__PURE__*/ _jsx("div", { className: "text-2xl font-bold text-blue-700", children: referralCount }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-blue-700", children: t('profile.referral.invited_count') }) ] }) ] }) : /*#__PURE__*/ _jsx("div", { className: "text-sm text-gray-400", children: t('profile.referral.no_code') }) ] }), activeTab === 'auto_response' && /*#__PURE__*/ _jsx(AutoResponseTab, { categories: categories, locationTree: locationTree, loaded: arLoaded, onLoad: ()=>{ if (arLoaded) return; api.getAutoResponseSettings().then((s)=>{ setAutoResponse(s); setArLoaded(true); }).catch(()=>setArLoaded(true)); }, settings: autoResponse, saving: arSaving, saved: arSaved, onSave: async (data)=>{ setArSaving(true); setArSaved(false); try { const updated = await api.updateAutoResponseSettings(data); setAutoResponse(updated); setArSaved(true); setTimeout(()=>setArSaved(false), 2500); } catch {} finally{ setArSaving(false); } }, t: t, catLocale: catLocale }), activeTab === 'info' && /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-4", children: t('profile.photo') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-5", children: [ /*#__PURE__*/ _jsxs("div", { className: "relative", children: [ user?.image ? /*#__PURE__*/ _jsx("img", { src: user.image, alt: user.name, className: "w-20 h-20 rounded-full object-cover border-2 border-gray-200" }) : /*#__PURE__*/ _jsx("div", { className: "w-20 h-20 rounded-full bg-blue-100 flex items-center justify-center text-blue-700 text-2xl font-bold border-2 border-gray-200", children: initials }), avatarUploading && /*#__PURE__*/ _jsx("div", { className: "absolute inset-0 rounded-full bg-black/40 flex items-center justify-center", children: /*#__PURE__*/ _jsx("div", { className: "w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" }) }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>fileRef.current?.click(), disabled: avatarUploading, className: "bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg text-sm font-medium disabled:opacity-50", children: t('profile.photo.change') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('profile.photo.hint') }), /*#__PURE__*/ _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handleAvatarChange }) ] }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-4", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800", children: t('profile.basic_info') }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('register.first_name') }), /*#__PURE__*/ _jsx("input", { value: formData.firstName, onChange: (e)=>setFormData({ ...formData, firstName: e.target.value }), required: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('register.last_name') }), /*#__PURE__*/ _jsx("input", { value: formData.lastName, onChange: (e)=>setFormData({ ...formData, lastName: e.target.value }), required: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: "Email" }), /*#__PURE__*/ _jsx("input", { value: user?.email, disabled: true, className: "w-full border border-gray-200 rounded-lg px-3 py-2 text-sm text-gray-400 bg-gray-50 cursor-not-allowed" }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between mt-1.5", children: [ user?.emailVerified ? /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1 text-xs text-green-600", children: [ /*#__PURE__*/ _jsx("span", { className: "inline-block w-1.5 h-1.5 rounded-full bg-green-500" }), t('profile.email.verified') ] }) : /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1 text-xs text-amber-600", children: [ /*#__PURE__*/ _jsx("span", { className: "inline-block w-1.5 h-1.5 rounded-full bg-amber-500" }), t('profile.email.not_verified') ] }), !user?.emailVerified && /*#__PURE__*/ _jsx("button", { type: "button", disabled: resendState !== 'idle', onClick: handleResendVerification, className: "text-xs text-blue-600 hover:underline disabled:opacity-60 disabled:no-underline", children: resendState === 'sending' ? t('login.unverified.sending') : resendState === 'sent' ? t('login.unverified.sent') : t('login.unverified.resend') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.phone') }), /*#__PURE__*/ _jsx("input", { type: "tel", value: formData.phone, onChange: (e)=>setFormData({ ...formData, phone: e.target.value }), placeholder: t('profile.phone.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.bio') }), /*#__PURE__*/ _jsx("textarea", { value: formData.bio, onChange: (e)=>setFormData({ ...formData, bio: e.target.value }), rows: 3, maxLength: 1000, placeholder: t('profile.bio.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm resize-none" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.language') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mb-2", children: t('profile.language.hint') }), /*#__PURE__*/ _jsxs("select", { value: formData.locale, onChange: (e)=>setFormData({ ...formData, locale: e.target.value }), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400", children: [ /*#__PURE__*/ _jsx("option", { value: "el", children: "Ελληνικά" }), /*#__PURE__*/ _jsx("option", { value: "en", children: "English" }), /*#__PURE__*/ _jsx("option", { value: "ru", children: "Русский" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.languages') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mb-2", children: t('profile.languages.hint') }), /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2", children: [ { code: 'el', flag: '🇬🇷', label: 'Ελληνικά' }, { code: 'en', flag: '🇬🇧', label: 'English' }, { code: 'ru', flag: '🇷🇺', label: 'Русский' }, { code: 'uk', flag: '🇺🇦', label: 'Українська' }, { code: 'de', flag: '🇩🇪', label: 'Deutsch' }, { code: 'fr', flag: '🇫🇷', label: 'Français' }, { code: 'it', flag: '🇮🇹', label: 'Italiano' }, { code: 'es', flag: '🇪🇸', label: 'Español' }, { code: 'ar', flag: '🇸🇦', label: 'العربية' }, { code: 'zh', flag: '🇨🇳', label: '中文' } ].map(({ code, flag, label })=>{ const selected = selectedLanguages.includes(code); return /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setSelectedLanguages(selected ? selectedLanguages.filter((l)=>l !== code) : [ ...selectedLanguages, code ]), className: `flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm border transition ${selected ? 'bg-blue-600 border-blue-600 text-white' : 'bg-white border-gray-300 text-gray-700 hover:border-blue-400'}`, children: [ /*#__PURE__*/ _jsx("span", { children: flag }), /*#__PURE__*/ _jsx("span", { children: label }) ] }, code); }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-3", children: t('profile.role') }), /*#__PURE__*/ _jsx("div", { className: `inline-flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium ${isSpecialist ? 'bg-purple-100 text-purple-700' : isAdmin ? 'bg-red-100 text-red-700' : 'bg-gray-100 text-gray-600'}`, children: isSpecialist ? t('profile.role.specialist') : isAdmin ? t('profile.role.admin') : t('profile.role.customer') }), !isSpecialist && !isAdmin && /*#__PURE__*/ _jsxs("div", { className: "mt-4 p-4 bg-purple-50 rounded-xl", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-600 mb-3", children: t('profile.become_specialist.desc') }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: handleBecomeSpecialist, disabled: becomingSpecialist, className: "bg-purple-600 hover:bg-purple-700 text-white px-5 py-2 rounded-lg text-sm font-semibold disabled:opacity-50", children: becomingSpecialist ? t('common.loading') : t('profile.become_specialist') }) ] }) ] }), (isSpecialist ? dashData?.features?.hasCanHelpNowStatus : dashData?.features?.hasNeedHelpStatus) && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-4", children: t('status.title', 'Статус') }), isSpecialist && /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('status.can_help_now', 'Готов помочь сейчас') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('status.can_help_now_hint', 'Ваша карточка показывается вверху') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: statusToggling === 'canhelp_now', onClick: async ()=>{ setStatusToggling('canhelp_now'); const nextActive = !myStatuses.includes('canhelp_now'); try { const res = await api.toggleStatus('canhelp_now', nextActive); setMyStatuses((prev)=>res.isActive ? [ ...prev.filter((s)=>s !== 'canhelp_now'), 'canhelp_now' ] : prev.filter((s)=>s !== 'canhelp_now')); } catch {} finally{ setStatusToggling(null); } }, className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${myStatuses.includes('canhelp_now') ? 'bg-green-500' : 'bg-gray-300'} disabled:opacity-50`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${myStatuses.includes('canhelp_now') ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }), !isSpecialist && !isAdmin && /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('status.need_help', 'Нужна помощь') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('status.need_help_hint', 'Специалисты смогут вам предложить помощь') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", disabled: statusToggling === 'need_help', onClick: async ()=>{ setStatusToggling('need_help'); const nextActive = !myStatuses.includes('need_help'); try { const res = await api.toggleStatus('need_help', nextActive); setMyStatuses((prev)=>res.isActive ? [ ...prev.filter((s)=>s !== 'need_help'), 'need_help' ] : prev.filter((s)=>s !== 'need_help')); } catch {} finally{ setStatusToggling(null); } }, className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${myStatuses.includes('need_help') ? 'bg-blue-500' : 'bg-gray-300'} disabled:opacity-50`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${myStatuses.includes('need_help') ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }), isSpecialist && (dashData?.plan?.tier === 'pro' || dashData?.plan?.tier === 'ultimate') && /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-800 mb-4", children: t('profile.show_contact', 'Показывать контакты') }), /*#__PURE__*/ _jsxs("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-800", children: t('profile.show_contact_hint', 'Клиенты видят ваш телефон') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.show_contact_desc', 'Позволяет клиентам связаться напрямую') }) ] }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setShowContactInfo((v)=>!v), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${showContactInfo ? 'bg-blue-500' : 'bg-gray-300'}`, children: /*#__PURE__*/ _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${showContactInfo ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }) ] }), /*#__PURE__*/ _jsx("button", { type: "submit", disabled: saving, className: `w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed ${activeTab === 'notifications' || activeTab === 'referral' || activeTab === 'auto_response' ? 'hidden' : ''}`, children: saving ? t('profile.saving') : t('common.save') }) ] }), showUpgradeModal && /*#__PURE__*/ _jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl shadow-xl p-6 w-full max-w-md", children: [ /*#__PURE__*/ _jsx("div", { className: "text-center mb-5", children: /*#__PURE__*/ _jsx("span", { className: "text-5xl", children: "\uD83D\uDE80" }) }), /*#__PURE__*/ _jsx("h2", { className: "text-lg font-bold text-gray-900 text-center mb-2", children: t('profile.upgrade.cards_limit') }), /*#__PURE__*/ _jsxs("p", { className: "text-sm text-gray-600 text-center mb-4", children: [ user?.plan?.name ?? t('profile.plan.basic'), " — ", t('profile.plan.cards_up_to'), " ", maxCards ] }), user?.plan && /*#__PURE__*/ _jsxs("div", { className: "bg-gray-50 rounded-xl p-4 mb-5 text-sm text-gray-600 text-center", children: [ /*#__PURE__*/ _jsx("span", { className: "font-medium text-gray-800", children: t('profile.upgrade.plan') }), ' ', user.plan.name, " — ", user.plan.price, " ", user.plan.currency ] }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 text-center mb-5", children: t('profile.upgrade.contact') }), /*#__PURE__*/ _jsx("button", { onClick: ()=>setShowUpgradeModal(false), className: "w-full bg-blue-600 hover:bg-blue-700 text-white py-2.5 rounded-xl text-sm font-semibold", children: t('profile.upgrade.ok') }) ] }) }) ] }) ] }) ] }); } @@`=_DFrt%-T[.5zPW_kr9>~:Q  _AECF8;;> ! j m !"!&#*###h$k$&&L)P) *_***,,..P/S/3385;5s6w699V;Z;;;<<>>@ @dBgBCCD_D4G7GIIKKELIL;M>MkOnOQQRRSSUUXXWY[YYY[[[[\_\9^=^?^G^__MbPbqctc1d5dHeKeffhhjjoorpuprrssuuw_wmxqxyyyyzz{{{|+}.}Y]:=_@D $ʐΐ/2.1ϔҔ8<Ù:>_ÝƝfjàƠΡѡ̣У),69rv W[ج۬KN$'_ SVX_&T]|29biǸ_PWź̺ BIֻݻov׼ܼ5<t{_GNؾ߾V](/ah%,cj_MTGN~3:ho@Ick_GN+n}DLJTp&+;Z_qQ[5? */ESqv ?Vor,/_ x{36psKNrv _         8_<T!X!%%&&''s+w+I,L,..2233445588z<_~<=#= >>>>??yA}AB BcCgChDkDEEIIwJzJM M&O*O,O4OOOvS_ySUU3Y7Y\\N^Q^aaGcKc)d-dee|ff!h$hhslszt}t*x-xUzXz||_HL69hlwz26Ǒʑ36@C59;Cέѭ_EHѷԷ.1nq*.:>z}_TWAECFz~`c_#/3sw}  v _y  FJy|FI/!2!""# #$ $j%m%&&((1+4+j,_m,Q.U.11b2e23344O6R6::;;===>>>L@O@C CFFGGH_HJJKKNNNNdPgPQQRRUUWW-Y1Y[[^^aaaa;c>cf_fggiikkllmm_pbpppIrLr t twwxxyyzz{{||~_~dn܏Ɛɐ9<˓ϓ}&qtáǡ_֣٣   36x(+    _+"?imcf[^EHTWfj_Z^^aHKBEdg:=2_6ux DHQTloEIcf  Z _^   mp`!d!?%B%W&Z&<)@)6*9*x+{+--..C0F0a4e4[5^5667_788 :#:G<J<>>iClCEEFFGGIIAKDKMMRRUR5U9U/V2VWWX^XYY\Y[[1]4]_"_aaddFeJe f#fffggi"ikklloopp(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSkillSuggestions */ .rl_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zc"https://api.canhelp.gr"0_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .deletePortfolioItem */ .zB_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updatePortfolioItem */ .hl(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment: react__WEBPACK_IMPORTED_MODULE_1__.useEffect: react__WEBPACK_IMPORTED_MODULE_1__.useStatereact__WEBPACK_IMPORTED_MODULE_1__.Suspense(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)(0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .initiateTopUp */ .oh_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .authClient */ .yK_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyReferralInfo */ .st_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyReviews */ .q7_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSiteStats */ .RN_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getCategories */ .bW_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getLocations */ .Vs_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyDashboard */ .H_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyStatuses */ .z6_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getBalanceHistory */ .fm_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getUserRating */ .Bm_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMySpecialistCards */ .Bb00_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .createSpecialistCard */ .eR_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .deleteSpecialistCard */ .f5 false0_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getAutoResponseSettings */ .Gp_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateAutoResponseSettings */ .RQ_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .toggleStatus */ .bc  __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ProfilePage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); /* __next_internal_client_entry_do_not_use__ default auto */ function SpecialistCardEditor({ card, isOpen, onToggle, onUpdate, onDelete, categories, locationTree, catLocale, locale }) { const { t } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)(); const [cardTab, setCardTab] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)('main'); const [saving, setSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [savedOk, setSavedOk] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [localTitle, setLocalTitle] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card.title); const [localDesc, setLocalDesc] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card.description ?? ''); const [localSkills, setLocalSkills] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card.skills ?? []); const [skillInput, setSkillInput] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [localCategories, setLocalCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card.categories ?? []); const [localLocations, setLocalLocations] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card.locations ?? []); const [localActive, setLocalActive] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card.isActive); const [apiSkillSugs, setApiSkillSugs] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [portfolio, setPortfolio] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card.portfolio ?? []); const [portfolioUploading, setPortfolioUploading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [editingItem, setEditingItem] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [editTitle, setEditTitle] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [editDesc, setEditDesc] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const portfolioFileRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (cardTab !== 'skills') return; _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSkillSuggestions */ .rl(localCategories.length > 0 ? localCategories : undefined).then(setApiSkillSugs).catch(()=>setApiSkillSugs([])); }, [ localCategories, cardTab ]); const lbl = (ru, en, el)=>locale === 'ru' ? ru : locale === 'en' ? en : el; async function saveAll() { setSaving(true); try { const updated = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zc(card.id, { title: localTitle, description: localDesc || null, skills: localSkills, categories: localCategories, locations: localLocations }); onUpdate({ ...updated, portfolio }); setSavedOk(true); setTimeout(()=>setSavedOk(false), 2000); } catch {} finally{ setSaving(false); } } async function toggleActive() { const next = !localActive; setLocalActive(next); try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zc(card.id, { isActive: next }); } catch {} } function addSkill(s) { const trimmed = s.trim(); if (trimmed && !localSkills.includes(trimmed)) setLocalSkills([ ...localSkills, trimmed ]); setSkillInput(''); } function toggleCategory(slug, childSlugs = []) { if (localCategories.includes(slug)) { setLocalCategories(localCategories.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocalCategories([ ...new Set([ ...localCategories, slug, ...childSlugs ]) ]); } } function toggleLocation(slug, childSlugs = []) { if (localLocations.includes(slug)) { setLocalLocations(localLocations.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocalLocations([ ...new Set([ ...localLocations, slug, ...childSlugs ]) ]); } } async function handlePortfolioUpload(e) { const file = e.target.files?.[0]; if (!file) return; setPortfolioUploading(true); try { const form = new FormData(); form.append('file', file); form.append('cardId', card.id); const res = await fetch(`${"https://api.canhelp.gr" || 0}/api/portfolio`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const item = await res.json(); const next = [ ...portfolio, item ]; setPortfolio(next); onUpdate({ ...card, portfolio: next }); } catch {} finally{ setPortfolioUploading(false); if (portfolioFileRef.current) portfolioFileRef.current.value = ''; } } async function handlePortfolioDelete(id) { try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .deletePortfolioItem */ .zB(id); const next = portfolio.filter((p)=>p.id !== id); setPortfolio(next); onUpdate({ ...card, portfolio: next }); } catch {} } async function handlePortfolioSave(id) { try { const item = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updatePortfolioItem */ .hl(id, { title: editTitle, description: editDesc }); setPortfolio((prev)=>prev.map((p)=>p.id === id ? item : p)); setEditingItem(null); } catch {} } const cardTabs = [ { id: 'main', label: t('profile.card.tab.main') }, { id: 'skills', label: t('profile.card.tab.skills') }, { id: 'categories', label: t('profile.card.tab.categories') }, { id: 'geography', label: t('profile.card.tab.geography') }, { id: 'portfolio', label: t('profile.card.tab.portfolio') } ]; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 overflow-hidden", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-gray-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: onToggle, className: "flex-1 flex items-center gap-3 text-left", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm font-semibold text-gray-800 flex-1", children: localTitle || card.title }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-gray-400 text-xs", children: isOpen ? '▲' : '▼' }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", title: t('profile.card.active'), onClick: toggleActive, className: `w-8 h-5 rounded-full transition-colors flex-shrink-0 ${localActive ? 'bg-green-400' : 'bg-gray-300'}`, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `block w-4 h-4 rounded-full bg-white shadow transition-transform mx-0.5 ${localActive ? 'translate-x-3' : ''}` }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: onDelete, className: "text-red-400 hover:text-red-600 text-sm px-1 flex-shrink-0", title: t('profile.card.delete'), children: "\uD83D\uDDD1" }) ] }), isOpen && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex overflow-x-auto border-b border-gray-100 bg-gray-50 gap-0", children: cardTabs.map((t)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setCardTab(t.id), className: `px-4 py-2.5 text-xs font-medium whitespace-nowrap border-b-2 transition -mb-px ${cardTab === t.id ? 'border-blue-500 text-blue-600 bg-white' : 'border-transparent text-gray-500 hover:text-gray-700'}`, children: t.label }, t.id)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "p-4", children: [ cardTab === 'main' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: localTitle, onChange: (e)=>setLocalTitle(e.target.value), maxLength: 200, placeholder: t('profile.cards.new_title'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { value: localDesc, onChange: (e)=>setLocalDesc(e.target.value), rows: 4, maxLength: 1000, placeholder: t('profile.bio.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), cardTab === 'skills' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-3", children: [ localSkills.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex flex-wrap gap-2", children: localSkills.map((s)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "flex items-center gap-1.5 bg-blue-50 text-blue-700 text-sm px-3 py-1 rounded-full", children: [ s, /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setLocalSkills(localSkills.filter((x)=>x !== s)), className: "text-blue-400 hover:text-blue-700 leading-none", children: "\xd7" }) ] }, s)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: skillInput, onChange: (e)=>setSkillInput(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') { e.preventDefault(); addSkill(skillInput); } }, placeholder: t('profile.card.skill.add'), className: "flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>addSkill(skillInput), className: "px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium", children: "+" }) ] }), apiSkillSugs.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex flex-wrap gap-1.5", children: apiSkillSugs.map((s)=>s.names[catLocale] ?? s.names.el).filter((name, i, arr)=>arr.indexOf(name) === i && !localSkills.includes(name)).slice(0, 16).map((name)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>addSkill(name), className: "text-xs px-2.5 py-1 border border-gray-200 rounded-full text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: [ "+ ", name ] }, name)) }) ] }), cardTab === 'categories' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-3", children: categories.map((cat)=>{ const catName = cat.names?.[catLocale] ?? cat.names?.el ?? cat.slug; const children = cat.children ?? []; const childSlugs = children.map((c)=>c.slug); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: localCategories.includes(cat.slug), onChange: ()=>toggleCategory(cat.slug, childSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-sm font-medium text-gray-800", children: [ cat.icon && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "mr-1", children: cat.icon }), catName ] }) ] }), children.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "ml-6 mt-2 space-y-2", children: children.map((sub)=>{ const subName = sub.names?.[catLocale] ?? sub.names?.el ?? sub.slug; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: localCategories.includes(sub.slug), onChange: ()=>toggleCategory(sub.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm text-gray-600", children: subName }) ] }, sub.id); }) }) ] }, cat.id); }) }), cardTab === 'geography' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-3", children: locationTree.map((city)=>{ const cityName = city.names?.[catLocale] ?? city.names?.el ?? city.slug; const districts = city.children ?? []; const districtSlugs = districts.map((d)=>d.slug); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: localLocations.includes(city.slug), onChange: ()=>toggleLocation(city.slug, districtSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm font-medium text-gray-800", children: cityName }) ] }), districts.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "ml-6 mt-2 space-y-2", children: districts.map((d)=>{ const dName = d.names?.[catLocale] ?? d.names?.el ?? d.slug; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: localLocations.includes(d.slug), onChange: ()=>toggleLocation(d.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm text-gray-600", children: dName }) ] }, d.id); }) }) ] }, city.id); }) }), cardTab === 'portfolio' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-3", children: [ portfolio.length < 20 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>portfolioFileRef.current?.click(), disabled: portfolioUploading, className: "flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium disabled:opacity-50", children: portfolioUploading ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" }), t('profile.card.photo.uploading') ] }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ "\uD83D\uDCF7 ", t('profile.card.photo.add') ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { ref: portfolioFileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handlePortfolioUpload }) ] }), portfolio.length === 0 ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-8 text-gray-400 text-sm border-2 border-dashed border-gray-200 rounded-xl", children: t('profile.card.photo.empty') }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-3", children: portfolio.map((item)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "group relative rounded-xl overflow-hidden border border-gray-200 bg-gray-50", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: item.imageUrl, alt: item.title ?? '', className: "w-full aspect-square object-cover" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "absolute inset-0 bg-black/0 group-hover:bg-black/50 transition-all flex flex-col justify-between p-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>handlePortfolioDelete(item.id), className: "self-end opacity-0 group-hover:opacity-100 transition w-7 h-7 rounded-full bg-red-500 text-white text-sm flex items-center justify-center hover:bg-red-600", children: "\xd7" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>{ setEditingItem(item); setEditTitle(item.title ?? ''); setEditDesc(item.description ?? ''); }, className: "opacity-0 group-hover:opacity-100 transition text-xs text-white bg-black/50 hover:bg-black/70 rounded-lg px-2 py-1", children: [ "✏️ ", t('profile.card.item.edit') ] }) ] }), item.title && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "px-2 py-1.5", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs font-medium text-gray-700 truncate", children: item.title }) }) ] }, item.id)) }) ] }), cardTab !== 'portfolio' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-3 mt-4 pt-4 border-t border-gray-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", disabled: saving, onClick: saveAll, className: "px-5 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-semibold disabled:opacity-50", children: saving ? '...' : t('profile.card.save') }), savedOk && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-sm text-green-600", children: [ "✓ ", t('profile.card.saved') ] }) ] }) ] }) ] }), editingItem && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-2xl shadow-xl p-6 w-full max-w-md", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-semibold text-gray-800 mb-4", children: t('profile.card.item.edit') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: editingItem.imageUrl, alt: "", className: "w-full h-40 object-cover rounded-xl mb-4" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.card.item.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: editTitle, onChange: (e)=>setEditTitle(e.target.value), maxLength: 200, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.card.item.desc') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { value: editDesc, onChange: (e)=>setEditDesc(e.target.value), rows: 3, maxLength: 1000, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex gap-3 mt-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>handlePortfolioSave(editingItem.id), className: "flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 rounded-lg text-sm font-medium", children: t('profile.card.item.save') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setEditingItem(null), className: "flex-1 bg-gray-100 hover:bg-gray-200 text-gray-700 py-2 rounded-lg text-sm font-medium", children: t('profile.card.item.cancel') }) ] }) ] }) }) ] }); } // ─── AutoResponseTab ─────────────────────────────────────────────────────── function AutoResponseTab({ categories, locationTree, loaded, onLoad, settings, saving, saved, onSave, t, catLocale }) { const { useEffect: _ue, useState: _us } = { useEffect: react__WEBPACK_IMPORTED_MODULE_1__.useEffect, useState: react__WEBPACK_IMPORTED_MODULE_1__.useState }; const [enabled, setEnabled] = _us(false); const [minBudget, setMinBudget] = _us(''); const [maxBudget, setMaxBudget] = _us(''); const [defaultPrice, setDefaultPrice] = _us(''); const [defaultMessage, setDefaultMessage] = _us(''); const [maxPerDay, setMaxPerDay] = _us(''); const [selCategories, setSelCategories] = _us([]); const [selLocations, setSelLocations] = _us([]); _ue(()=>{ onLoad(); }, []); _ue(()=>{ if (!settings) return; setEnabled(settings.enabled); setMinBudget(settings.minBudget != null ? String(settings.minBudget) : ''); setMaxBudget(settings.maxBudget != null ? String(settings.maxBudget) : ''); setDefaultPrice(settings.defaultPrice != null ? String(settings.defaultPrice) : ''); setDefaultMessage(settings.defaultMessage ?? ''); setMaxPerDay(settings.maxAutoOffersPerDay != null ? String(settings.maxAutoOffersPerDay) : ''); setSelCategories(settings.categories ?? []); setSelLocations(settings.locations ?? []); }, [ settings ]); if (!loaded) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-10 text-white/60", children: t('common.loading') }); const flatLocations = []; function flatten(nodes) { for (const n of nodes){ flatLocations.push({ id: n.id, name: n.name }); if (n.children?.length) flatten(n.children); } } flatten(locationTree); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center justify-between cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "font-medium text-gray-800", children: t('auto_response.title', 'Авто-ответ') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: t('auto_response.desc', 'Автоматически отвечать на подходящие задачи') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setEnabled((v)=>!v), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${enabled ? 'bg-blue-500' : 'bg-gray-300'}`, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${enabled ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-5 space-y-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-medium text-gray-800 text-sm", children: t('auto_response.budget_range', 'Бюджет задачи') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.min_budget', 'Мин. €') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "number", min: "0", value: minBudget, onChange: (e)=>setMinBudget(e.target.value), placeholder: "0", className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.max_budget', 'Макс. €') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "number", min: "0", value: maxBudget, onChange: (e)=>setMaxBudget(e.target.value), placeholder: "∞", className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.default_price', 'Цена по умолчанию €') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "number", min: "0", value: defaultPrice, onChange: (e)=>setDefaultPrice(e.target.value), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.max_per_day', 'Макс. авто-офертов/день') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "number", min: "1", max: "50", value: maxPerDay, onChange: (e)=>setMaxPerDay(e.target.value), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-xs text-gray-500 mb-1", children: t('auto_response.default_message', 'Текст авто-ответа') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { value: defaultMessage, onChange: (e)=>setDefaultMessage(e.target.value), rows: 4, maxLength: 2000, placeholder: t('auto_response.message_placeholder', 'Здравствуйте! Я могу помочь с этой задачей...'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), categories.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-medium text-gray-800 text-sm mb-3", children: t('auto_response.categories', 'Категории задач') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex flex-wrap gap-2 max-h-40 overflow-y-auto", children: categories.map((cat)=>{ const name = cat[`name_${catLocale}`] || cat.name_el || cat.name; const sel = selCategories.includes(cat.id); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setSelCategories(sel ? selCategories.filter((c)=>c !== cat.id) : [ ...selCategories, cat.id ]), className: `px-3 py-1.5 rounded-lg text-xs border transition ${sel ? 'bg-blue-600 border-blue-600 text-white' : 'bg-white border-gray-300 text-gray-700 hover:border-blue-400'}`, children: name }, cat.id); }) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", disabled: saving, onClick: ()=>onSave({ enabled, minBudget: minBudget ? Number(minBudget) : null, maxBudget: maxBudget ? Number(maxBudget) : null, defaultPrice: defaultPrice ? Number(defaultPrice) : null, defaultMessage: defaultMessage || null, maxAutoOffersPerDay: maxPerDay ? Number(maxPerDay) : null, categories: selCategories.length > 0 ? selCategories : null, locations: selLocations.length > 0 ? selLocations : null }), className: "w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50", children: saving ? t('common.loading') : saved ? t('auto_response.saved', 'Сохранено ✓') : t('common.save') }) ] }); } function ProfilePage() { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react__WEBPACK_IMPORTED_MODULE_1__.Suspense, { fallback: null, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ProfilePageInner, {}) }); } function ProfilePageInner() { const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const searchParams = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)(); const { data: session, isPending } = (0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)(); const { t, locale } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)(); const validTabs = [ 'info', 'finance', 'cards', 'notifications', 'reviews', 'referral', 'auto_response', 'site' ]; const initialTab = searchParams.get('tab') ?? 'info'; const [activeTab, setActiveTab] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(validTabs.includes(initialTab) ? initialTab : 'info'); const [user, setUser] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true); const [saving, setSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [saved, setSaved] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [error, setError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [formData, setFormData] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({ firstName: '', lastName: '', phone: '', bio: '', locale: 'el' }); const [selectedLanguages, setSelectedLanguages] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); // Specialist cards const [cards, setCards] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [maxCards, setMaxCards] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(1); const [cardsLoading, setCardsLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [openCardId, setOpenCardId] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [creatingCard, setCreatingCard] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [newCardTitle, setNewCardTitle] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [showNewCardForm, setShowNewCardForm] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [showUpgradeModal, setShowUpgradeModal] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); // Reference data const [categories, setCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [locationTree, setLocationTree] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); // Become specialist const [becomingSpecialist, setBecomingSpecialist] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [avatarUploading, setAvatarUploading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const fileRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); // Notification preferences const [notifyNewTasks, setNotifyNewTasks] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [notifMessages, setNotifMessages] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true); const [notifySaving, setNotifySaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [notifySaved, setNotifySaved] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); // Email verification resend const [resendState, setResendState] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)('idle'); // Referral info const [referralCode, setReferralCode] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [referralCount, setReferralCount] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0); const [referralCopied, setReferralCopied] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [referralLoaded, setReferralLoaded] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); // Balance top-up modal const [showTopUpModal, setShowTopUpModal] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [topUpAmount, setTopUpAmount] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(10); const [topUpLoading, setTopUpLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [topUpError, setTopUpError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [balanceHistory, setBalanceHistory] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); // Plan data + statuses const [dashData, setDashData] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [myStatuses, setMyStatuses] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [statusToggling, setStatusToggling] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [personalSiteSlug, setPersonalSiteSlug] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [slugSaving, setSlugSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [slugSaved, setSlugSaved] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [slugCopied, setSlugCopied] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [slugError, setSlugError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [showContactInfo, setShowContactInfo] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [siteSettings, setSiteSettings] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({}); const [siteSettingsSaving, setSiteSettingsSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [siteStats, setSiteStats] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [siteStatsLoading, setSiteStatsLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [autoResponse, setAutoResponse] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [arLoaded, setArLoaded] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [arSaving, setArSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [arSaved, setArSaved] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); async function handleTopUp() { const amount = Number(topUpAmount); if (!amount || amount < 1) return; setTopUpLoading(true); setTopUpError(''); try { const { url, params } = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .initiateTopUp */ .oh(amount); // Build and auto-submit form to ePay const form = document.createElement('form'); form.method = 'POST'; form.action = url; Object.entries(params).forEach(([k, v])=>{ const input = document.createElement('input'); input.type = 'hidden'; input.name = k; input.value = v; form.appendChild(input); }); document.body.appendChild(form); form.submit(); } catch (e) { setTopUpError(e?.message || t('profile.balance.topup.error')); setTopUpLoading(false); } } async function handleResendVerification() { if (!user?.email || resendState !== 'idle') return; setResendState('sending'); const callbackURL = `${window.location.origin}/profile`; const result = await _lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .authClient */ .yK.sendVerificationEmail({ email: user.email, callbackURL }); if (result?.error) { setResendState('idle'); } else { setResendState('sent'); } } process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (activeTab !== 'referral' || referralLoaded) return; _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyReferralInfo */ .st().then((r)=>{ setReferralCode(r.referralCode); setReferralCount(r.referralCount); }).catch(()=>{}).finally(()=>setReferralLoaded(true)); }, [ activeTab ]); // Reviews const [myReviews, setMyReviews] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [reviewsLoading, setReviewsLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [myRating, setMyRating] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (activeTab !== 'reviews' || myReviews !== null || reviewsLoading) return; setReviewsLoading(true); _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyReviews */ .q7().then(setMyReviews).catch(()=>setMyReviews([])).finally(()=>setReviewsLoading(false)); }, [ activeTab ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (activeTab !== 'site' || siteStats !== null || siteStatsLoading) return; setSiteStatsLoading(true); _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSiteStats */ .RN().then((res)=>setSiteStats(res.days)).catch(()=>setSiteStats([])).finally(()=>setSiteStatsLoading(false)); }, [ activeTab ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!isPending && !session) router.push('/login'); }, [ session, isPending ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!session) return; Promise.all([ _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me'), _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getCategories */ .bW(), _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getLocations */ .Vs(), _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyDashboard */ .H().catch(()=>null), _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyStatuses */ .z6().catch(()=>[]), _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getBalanceHistory */ .fm(8).catch(()=>[]) ]).then(([u, cats, locs, dash, statusRes, history])=>{ setUser(u); setFormData({ firstName: u.firstName ?? '', lastName: u.lastName ?? '', phone: u.phone ?? '', bio: u.bio ?? '', locale: u.locale ?? 'el' }); setSelectedLanguages(u.languages ?? []); setNotifyNewTasks(u.notifyNewTasks ?? false); setNotifMessages(u.notifMessages ?? true); setCategories(cats); setLocationTree(locs); setDashData(dash); setMyStatuses((statusRes ?? []).filter((s)=>s.isActive).map((s)=>s.statusType)); setBalanceHistory(history); setPersonalSiteSlug(u.personalSiteSlug ?? ''); setShowContactInfo(u.showContactInfo ?? false); setSiteSettings(u.siteSettings ?? {}); if (u.role === 'specialist' || u.role === 'admin') { loadCards(); _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getUserRating */ .Bm(u.id).then((r)=>setMyRating(r.avg)).catch(()=>{}); } }).catch(()=>{}).finally(()=>setLoading(false)); }, [ session ]); async function loadCards() { setCardsLoading(true); try { const { cards: c, maxCards: m } = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMySpecialistCards */ .Bb(); setCards(c); setMaxCards(m); } catch {} finally{ setCardsLoading(false); } } async function handleSubmit(e) { e.preventDefault(); setError(''); setSaving(true); try { const updated = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ firstName: formData.firstName, lastName: formData.lastName, phone: formData.phone || undefined, bio: formData.bio || undefined, locale: formData.locale, languages: selectedLanguages, personalSiteSlug: personalSiteSlug || undefined, showContactInfo }) }); setUser(updated); setSaved(true); setTimeout(()=>setSaved(false), 2500); } catch (err) { setError(err.message || t('common.error')); } finally{ setSaving(false); } } async function handleBecomeSpecialist() { setBecomingSpecialist(true); setError(''); try { const updated = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me/become-specialist', { method: 'POST' }); setUser(updated); setActiveTab('cards'); loadCards(); } catch (err) { setError(err.message || t('common.error')); } finally{ setBecomingSpecialist(false); } } async function handleSaveSiteSlug() { setSlugSaving(true); setSlugError(''); try { const updated = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ personalSiteSlug: personalSiteSlug || null }) }); setUser(updated); setPersonalSiteSlug(updated.personalSiteSlug ?? ''); setSlugSaved(true); setTimeout(()=>setSlugSaved(false), 2500); } catch (err) { const code = err?.code ?? ''; if (code === 'SLUG_TAKEN' || err.message === 'This URL is already taken') { setSlugError(t('profile.site.slug_taken', 'Этот адрес уже занят')); } else { setSlugError(err.message || t('common.error')); } } finally{ setSlugSaving(false); } } async function handleSaveSiteSettings(newSettings) { setSiteSettings(newSettings); setSiteSettingsSaving(true); try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ siteSettings: newSettings }) }); } catch {} finally{ setSiteSettingsSaving(false); } } async function handleAvatarChange(e) { const file = e.target.files?.[0]; if (!file) return; setAvatarUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${"https://api.canhelp.gr" || 0}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); const fullUrl = `${"https://api.canhelp.gr" || 0}${url}`; await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ image: fullUrl }) }); setUser((prev)=>({ ...prev, image: fullUrl })); } catch { setError(t('profile.upload.error')); } finally{ setAvatarUploading(false); } } async function handleCreateCard() { if (!newCardTitle.trim()) return; setCreatingCard(true); try { const card = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .createSpecialistCard */ .eR({ title: newCardTitle.trim() }); setCards((prev)=>[ ...prev, card ]); setOpenCardId(card.id); setNewCardTitle(''); setShowNewCardForm(false); } catch (err) { setError(err.message || t('common.error')); } finally{ setCreatingCard(false); } } async function handleDeleteCard(id) { if (!confirm(t('profile.cards.delete_confirm'))) return; try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .deleteSpecialistCard */ .f5(id); setCards((prev)=>prev.filter((c)=>c.id !== id)); if (openCardId === id) setOpenCardId(null); } catch (err) { setError(err.message || t('common.error')); } } if (isPending || loading) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const dateLocale = locale === 'en' ? 'en-US' : locale === 'ru' ? 'ru-RU' : 'el-GR'; const isSpecialist = user?.role === 'specialist'; const isAdmin = user?.role === 'admin'; const showSpecialistTabs = isSpecialist || isAdmin; const initials = user ? `${user.firstName?.[0] ?? ''}${user.lastName?.[0] ?? ''}`.toUpperCase() : '?'; const hasAutoResponse = !!dashData?.features?.hasAutoResponse; const tabIcons = { info: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" }) }), finance: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 6v12m-3-2.818l.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.879 4.006 0l.415.33M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), cards: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M20.25 14.15v4.073a2.25 2.25 0 01-2.25 2.25h-12a2.25 2.25 0 01-2.25-2.25V6a2.25 2.25 0 012.25-2.25h4.073M15.75 3h5.25v5.25M15.75 3l-9 9" }) }), notifications: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), reviews: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.562.562 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.562.562 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" }) }), referral: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244" }) }), auto_response: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" }) }), site: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" }) }) }; const tabs = showSpecialistTabs ? [ { id: 'info', label: t('profile.tab.info') }, { id: 'finance', label: t('profile.tab.finance') }, { id: 'cards', label: t('profile.tab.cards') }, { id: 'notifications', label: t('profile.tab.notifications') }, { id: 'reviews', label: t('profile.tab.reviews') }, { id: 'referral', label: t('profile.tab.referral') }, ...hasAutoResponse ? [ { id: 'auto_response', label: t('profile.tab.auto_response', 'Авто-ответ') } ] : [], ...dashData?.features?.hasPersonalSite ? [ { id: 'site', label: t('profile.tab.site') } ] : [] ] : [ { id: 'info', label: t('profile.tab.info') }, { id: 'finance', label: t('profile.tab.finance') }, { id: 'notifications', label: t('profile.tab.notifications') }, { id: 'reviews', label: t('profile.tab.reviews') }, { id: 'referral', label: t('profile.tab.referral') }, ...dashData?.features?.hasPersonalSite ? [ { id: 'site', label: t('profile.tab.site') } ] : [] ]; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "max-w-4xl mx-auto px-4 py-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-4 mb-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-14 h-14 rounded-full flex-shrink-0 overflow-hidden border-2 border-white/40 flex items-center justify-center text-blue-700 text-xl font-bold bg-blue-100 cursor-pointer", onClick: ()=>{ setActiveTab('info'); fileRef.current?.click(); }, title: t('profile.photo.change'), children: user?.image ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: user.image, alt: user.name, className: "w-full h-full object-cover" }) : initials }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-xl font-bold text-white leading-tight", children: user?.firstName ? `${user.firstName} ${user.lastName ?? ''}`.trim() : user?.name ?? t('nav.profile') }), myRating && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-1 mt-0.5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-yellow-300", children: "★" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "font-semibold text-white text-sm", children: Number(myRating).toFixed(1) }), myReviews !== null && myReviews.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-white/60 text-xs", children: [ "(", myReviews.length, ")" ] }) ] }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex gap-6 items-start", children: [ tabs.length > 1 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("aside", { className: "w-52 shrink-0 hidden sm:block", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("nav", { className: "rounded-2xl overflow-hidden bg-white/10 backdrop-blur-sm", children: tabs.map((tab)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>setActiveTab(tab.id), className: `w-full text-left px-4 py-3 text-sm font-medium transition border-b border-white/10 last:border-0 flex items-center gap-3 ${activeTab === tab.id ? 'bg-white text-blue-700' : 'text-white/80 hover:bg-white/10 hover:text-white'}`, children: [ tabIcons[tab.id], /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: tab.label }) ] }, tab.id)) }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1 min-w-0", children: [ tabs.length > 1 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex sm:hidden bg-white/15 backdrop-blur rounded-xl p-1 mb-4 gap-1 overflow-x-auto", children: tabs.map((tab)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>setActiveTab(tab.id), className: `flex-1 min-w-fit px-3 py-2 text-xs font-medium rounded-lg transition whitespace-nowrap flex flex-col items-center gap-0.5 ${activeTab === tab.id ? 'bg-white text-blue-700 shadow-sm' : 'text-white/80 hover:text-white hover:bg-white/10'}`, children: [ tabIcons[tab.id], /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: tab.label }) ] }, tab.id)) }), activeTab === 'cards' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-4", children: [ error && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-between", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-sm text-white/70", children: [ t('profile.cards.count'), ": ", cards.length, " / ", maxCards === null ? '∞' : maxCards ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>{ if (maxCards !== null && cards.length >= maxCards) { setShowUpgradeModal(true); } else { setShowNewCardForm(true); } }, className: "flex items-center gap-1.5 text-sm font-medium text-white hover:text-white/80", children: [ "+ ", t('profile.cards.add') ] }) ] }), showNewCardForm && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-blue-200 p-4 space-y-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-800", children: t('profile.cards.new_title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: newCardTitle, onChange: (e)=>setNewCardTitle(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') handleCreateCard(); }, maxLength: 200, placeholder: t('profile.cards.placeholder'), autoFocus: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: handleCreateCard, disabled: creatingCard || !newCardTitle.trim(), className: "px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium disabled:opacity-50", children: creatingCard ? '...' : t('profile.cards.create') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>{ setShowNewCardForm(false); setNewCardTitle(''); }, className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg text-sm font-medium", children: t('profile.cards.cancel') }) ] }) ] }), cardsLoading && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-10 text-white/70", children: t('common.loading') }), !cardsLoading && cards.length === 0 && !showNewCardForm && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-center py-14 border-2 border-dashed border-white/30 rounded-xl", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-white/70 text-sm mb-3", children: t('profile.cards.empty') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>setShowNewCardForm(true), className: "text-sm text-white font-medium hover:underline", children: [ "+ ", t('profile.cards.create_first') ] }) ] }), cards.map((card)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(SpecialistCardEditor, { card: card, isOpen: openCardId === card.id, onToggle: ()=>setOpenCardId(openCardId === card.id ? null : card.id), onUpdate: (updated)=>setCards((prev)=>prev.map((c)=>c.id === updated.id ? updated : c)), onDelete: ()=>handleDeleteCard(card.id), categories: categories, locationTree: locationTree, catLocale: catLocale, locale: locale }, card.id)) ] }), activeTab === 'site' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800 mb-1", children: t('profile.site.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400", children: t('profile.site_slug_hint') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-xs font-medium text-gray-500 mb-1.5", children: t('profile.site.url_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 flex-wrap", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm text-gray-400 shrink-0", children: "canhelp.gr/site/" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: personalSiteSlug, onChange: (e)=>setPersonalSiteSlug(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, '')), placeholder: "my-slug", maxLength: 50, className: "flex-1 min-w-32 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-3 flex-wrap", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: handleSaveSiteSlug, disabled: slugSaving, className: "px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50", children: slugSaving ? t('profile.saving') : t('common.save') }), slugSaved && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-sm text-green-600", children: [ "✓ ", t('profile.saved') ] }), personalSiteSlug && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>{ navigator.clipboard.writeText(`${window.location.origin}/site/${personalSiteSlug}`); setSlugCopied(true); setTimeout(()=>setSlugCopied(false), 2000); }, className: "px-3 py-2 border border-gray-300 rounded-lg text-sm text-gray-600 hover:bg-gray-50 flex items-center gap-1.5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }), slugCopied ? t('profile.site.copied') : t('profile.site.copy') ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("a", { href: `/site/${personalSiteSlug}`, target: "_blank", rel: "noopener noreferrer", className: "px-3 py-2 border border-blue-200 bg-blue-50 rounded-lg text-sm text-blue-600 hover:bg-blue-100 flex items-center gap-1.5", children: [ t('profile.site_open'), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-3.5 h-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) }) ] }) ] }) ] }), slugError && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-red-500", children: slugError }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-semibold text-gray-800", children: t('profile.site.visible_title') }), siteSettingsSaving && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-gray-400", children: t('profile.saving', 'Сохранение...') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-3", children: [ { key: 'showBio', label: t('profile.site.visible.bio', 'Биография') }, { key: 'showRating', label: t('profile.site.visible.rating', 'Рейтинг и отзывы') }, { key: 'showReviews', label: t('profile.site.visible.reviews', 'Раздел с отзывами') }, { key: 'showServices', label: t('profile.site.visible.services', 'Карточки услуг') }, { key: 'showPortfolio', label: t('profile.site.visible.portfolio', 'Портфолио') }, { key: 'showPhone', label: t('profile.site.visible.contacts', 'Контактный телефон') }, { key: 'showFullLastName', label: t('profile.site.visible.full_last_name', 'Фамилия полностью') }, { key: 'showStatus', label: t('profile.site.visible.status', 'Статус «Готов помочь»') } ].map(({ key, label })=>{ const checked = siteSettings[key] !== false // undefined = true by default ; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-3 cursor-pointer group", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: `w-5 h-5 rounded border-2 flex items-center justify-center transition shrink-0 ${checked ? 'bg-blue-600 border-blue-600' : 'bg-white border-gray-300 group-hover:border-blue-400'}`, onClick: ()=>{ const next = { ...siteSettings, [key]: !checked }; handleSaveSiteSettings(next); }, children: checked && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-3 h-3 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 12.75l6 6 9-13.5" }) }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm text-gray-700 select-none", onClick: ()=>{ const next = { ...siteSettings, [key]: !checked }; handleSaveSiteSettings(next); }, children: label }) ] }, key); }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-4", children: t('profile.site.edit_bio_hint', 'Имя и фото всегда отображаются') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mt-6 pt-4 border-t border-gray-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('profile.site.theme', 'Тема оформления') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex gap-3", children: [ { value: 'dark', label: t('profile.site.theme.dark', 'Тёмная'), icon: '🌙' }, { value: 'light', label: t('profile.site.theme.light', 'Светлая'), icon: '☀️' } ].map((opt)=>{ const selected = (siteSettings.siteTheme ?? 'dark') === opt.value; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { onClick: ()=>handleSaveSiteSettings({ ...siteSettings, siteTheme: opt.value }), className: `flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border-2 text-sm font-medium transition ${selected ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-200 bg-white text-gray-500 hover:border-gray-300'}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: opt.icon }), opt.label ] }, opt.value); }) }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex items-center justify-between mb-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-semibold text-gray-800", children: t('profile.site.stats.title', 'Аналитика сайта') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.site.stats.days', 'последние 30 дней') }) ] }) }), !personalSiteSlug ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-400 py-4 text-center", children: t('profile.site.stats.no_slug', 'Укажите адрес сайта, чтобы видеть статистику') }) : siteStatsLoading || siteStats === null ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-400 py-4 text-center", children: t('profile.site.stats.loading', 'Загрузка аналитики...') }) : (()=>{ const totalViews = siteStats.reduce((s, d)=>s + d.views, 0); const totalUnique = siteStats.reduce((s, d)=>s + d.unique, 0); const totalMessages = siteStats.reduce((s, d)=>s + d.messages, 0); // Area chart helpers const days = siteStats.map((d)=>d.date); const seriesDef = [ { vals: siteStats.map((d)=>d.views), color: '#3b82f6', fill: '#3b82f615', label: t('profile.site.stats.views', 'Просмотры') }, { vals: siteStats.map((d)=>d.unique), color: '#8b5cf6', fill: '#8b5cf610', label: t('profile.site.stats.unique', 'Уникальные') }, { vals: siteStats.map((d)=>d.messages), color: '#10b981', fill: '#10b98110', label: t('profile.site.stats.messages', 'Сообщения') } ]; const maxVal = Math.max(...seriesDef.flatMap((s)=>s.vals), 1); const W = 580; const H = 160; const padL = 36; const padB = 22; const chartW = W - padL - 4; const chartH = H - padB; const stepX = chartW / (days.length - 1); function pts(vals) { return vals.map((v, i)=>[ padL + i * stepX, chartH - v / maxVal * chartH ]); } function smoothPath(points) { if (points.length < 2) return ''; let d = `M ${points[0][0].toFixed(1)} ${points[0][1].toFixed(1)}`; for(let i = 1; i < points.length; i++){ const cpx = ((points[i - 1][0] + points[i][0]) / 2).toFixed(1); d += ` C ${cpx} ${points[i - 1][1].toFixed(1)} ${cpx} ${points[i][1].toFixed(1)} ${points[i][0].toFixed(1)} ${points[i][1].toFixed(1)}`; } return d; } function areaPath(vals) { const points = pts(vals); const line = smoothPath(points); if (!line) return ''; const lastX = points[points.length - 1][0].toFixed(1); return `${line} L ${lastX} ${chartH.toFixed(1)} L ${padL.toFixed(1)} ${chartH.toFixed(1)} Z`; } function fmtY(v) { return v >= 1000 ? `${Math.round(v / 1000)}K` : String(v); } const yTicks = [ 0, Math.round(maxVal / 3), Math.round(maxVal * 2 / 3), maxVal ]; const xTicks = days.map((d, i)=>({ i, label: d.slice(8) })).filter((_, i)=>i % 7 === 0 || i === days.length - 1); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "grid grid-cols-3 gap-3 mb-5", children: [ { label: t('profile.site.stats.total_views', 'Просмотры'), value: totalViews, color: 'text-blue-600', bg: 'bg-blue-50' }, { label: t('profile.site.stats.total_unique', 'Уник. посетители'), value: totalUnique, color: 'text-violet-600', bg: 'bg-violet-50' }, { label: t('profile.site.stats.total_messages', 'Сообщения'), value: totalMessages, color: 'text-emerald-600', bg: 'bg-emerald-50' } ].map((card)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: `${card.bg} rounded-xl p-3 text-center`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: `text-2xl font-bold ${card.color}`, children: card.value }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-xs text-gray-500 mt-0.5", children: card.label }) ] }, card.label)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex items-center gap-4 mb-2", children: seriesDef.map((s)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "flex items-center gap-1.5 text-xs text-gray-500", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-3 h-0.5 inline-block rounded", style: { background: s.color } }), s.label ] }, s.label)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "overflow-x-auto", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { viewBox: `0 0 ${W} ${H + 12}`, className: "w-full", style: { minWidth: 320 }, children: [ yTicks.map((v)=>{ const y = chartH - v / maxVal * chartH; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("g", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("line", { x1: padL, y1: y, x2: W - 4, y2: y, stroke: "#f3f4f6", strokeWidth: 1 }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("text", { x: padL - 5, y: y + 3.5, textAnchor: "end", fontSize: 9, fill: "#9ca3af", children: fmtY(v) }) ] }, v); }), xTicks.map(({ i })=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("line", { x1: padL + i * stepX, y1: 0, x2: padL + i * stepX, y2: chartH, stroke: "#f9fafb", strokeWidth: 1 }, `vg-${i}`)), xTicks.map(({ i, label })=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("text", { x: padL + i * stepX, y: H + 10, textAnchor: "middle", fontSize: 9, fill: "#9ca3af", children: label }, i)), seriesDef.map((s, si)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: areaPath(s.vals), fill: s.fill }, `fill-${si}`)), seriesDef.map((s, si)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: smoothPath(pts(s.vals)), fill: "none", stroke: s.color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }, `line-${si}`)), seriesDef.map((s, si)=>{ const points = pts(s.vals); const last = points[points.length - 1]; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("circle", { cx: last[0], cy: last[1], r: 4, fill: "white", stroke: s.color, strokeWidth: 2 }, `dot-${si}`); }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("line", { x1: padL, y1: chartH, x2: W - 4, y2: chartH, stroke: "#e5e7eb", strokeWidth: 1 }) ] }) }) ] }); })() ] }) ] }), activeTab === 'reviews' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-4", children: myReviews === null ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-10 text-white/70", children: t('common.loading') }) : myReviews.length === 0 ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-center py-20 text-white/60", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-4xl mb-3", children: "⭐" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { children: t('profile.no_reviews') }) ] }) : myReviews.map(({ review, author })=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "bg-white rounded-xl border border-gray-200 p-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-start gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-9 h-9 rounded-full bg-gray-100 flex-shrink-0 flex items-center justify-center text-gray-600 text-sm font-bold overflow-hidden", children: author?.image ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: author.image, alt: author.name, className: "w-full h-full object-cover" }) : author?.name?.[0]?.toUpperCase() ?? '?' }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 mb-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm font-medium text-gray-800", children: author?.name ?? '—' }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-yellow-400", children: [ '★'.repeat(review.rating), '☆'.repeat(5 - review.rating) ] }) ] }), review.comment && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-600", children: review.comment }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-1", children: new Date(review.createdAt).toLocaleDateString() }) ] }) ] }) }, review.id)) }), activeTab === 'finance' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800", children: t('profile.balance') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { onClick: ()=>{ setTopUpAmount(10); setTopUpError(''); setShowTopUpModal(true); }, className: "flex items-center gap-1.5 text-sm font-medium text-blue-600 hover:text-blue-700 hover:bg-blue-50 px-3 py-1.5 rounded-lg transition-colors", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('profile.balance.topup') ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-3 p-4 bg-green-50 rounded-xl border border-green-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-6 h-6 text-green-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-xl font-bold text-green-700", children: [ parseFloat(user?.balance ?? '0').toFixed(2), " EUR" ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mt-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "text-sm font-semibold text-gray-800", children: t('profile.balance.history', 'Архив операций') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-gray-400", children: t('profile.balance.history.last', 'Последние операции') }) ] }), balanceHistory.length === 0 ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "rounded-xl border border-dashed border-gray-200 px-4 py-6 text-sm text-gray-400 text-center", children: t('profile.balance.history.empty', 'Операций пока нет') }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-2", children: balanceHistory.map((entry)=>{ const isCredit = entry.direction === 'credit'; const amount = Number(entry.amount).toFixed(2); const badgeClass = isCredit ? 'bg-emerald-50 text-emerald-700 border-emerald-100' : 'bg-rose-50 text-rose-700 border-rose-100'; const title = entry.kind === 'topup' ? t('profile.balance.history.kind.topup', 'Пополнение баланса') : entry.kind === 'plan_purchase' ? t('profile.balance.history.kind.plan_purchase', 'Списание за тариф') : entry.kind === 'admin_topup' ? t('profile.balance.history.kind.admin_topup', 'Пополнение администратором') : t('profile.balance.history.kind.admin_adjustment', 'Корректировка администратором'); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "rounded-xl border border-gray-200 px-4 py-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-sm font-medium text-gray-900", children: entry.description || title }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-xs text-gray-500 mt-1", children: new Date(entry.createdAt).toLocaleString(dateLocale) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: `shrink-0 rounded-full border px-2.5 py-1 text-xs font-semibold ${badgeClass}`, children: [ isCredit ? '+' : '-', amount, " ", entry.currency ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mt-2 text-xs text-gray-500", children: [ t('profile.balance.history.balance_after', 'Баланс после'), ": ", Number(entry.balanceAfter).toFixed(2), " ", entry.currency ] }) ] }, entry.id); }) }) ] }) ] }), showTopUpModal && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-black/40 backdrop-blur-sm", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-2xl shadow-2xl w-full max-w-sm p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-between mb-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "text-lg font-semibold text-gray-900", children: t('profile.balance.topup.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: ()=>setShowTopUpModal(false), className: "text-gray-400 hover:text-gray-600", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-500 mb-3", children: t('profile.balance.topup.hint') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "grid grid-cols-4 gap-2 mb-4", children: [ 5, 10, 20, 50 ].map((v)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { onClick: ()=>setTopUpAmount(v), className: `py-2 rounded-xl text-sm font-semibold border transition-colors ${Number(topUpAmount) === v ? 'bg-blue-600 text-white border-blue-600' : 'border-gray-200 text-gray-700 hover:border-blue-400'}`, children: [ "€", v ] }, v)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.balance.topup.amount') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "relative", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm", children: "€" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "number", min: "1", max: "9999", step: "1", value: topUpAmount, onChange: (e)=>setTopUpAmount(e.target.value), className: "w-full pl-7 pr-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), topUpError && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-red-600 mb-3", children: topUpError }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: handleTopUp, disabled: topUpLoading || !Number(topUpAmount) || Number(topUpAmount) < 1, className: "w-full py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed text-white font-semibold rounded-xl transition-colors flex items-center justify-center gap-2", children: topUpLoading ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { className: "w-4 h-4 animate-spin", fill: "none", viewBox: "0 0 24 24", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v8z" }) ] }), t('profile.balance.topup.loading') ] }) : t('profile.balance.topup.submit') }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800 mb-3", children: t('profile.plan.title') }), user?.plan ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-start gap-3 p-4 bg-blue-50 rounded-xl border border-blue-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-6 h-6 text-blue-500 shrink-0 mt-0.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "font-semibold text-gray-900", children: user.plan.name }), user.plan.description && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-500 mt-0.5", children: user.plan.description }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-wrap gap-3 mt-2 text-xs text-gray-500", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "font-medium text-blue-700", children: [ user.plan.price, " ", user.plan.currency ] }), user.plan.maxCards != null ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { children: [ t('profile.plan.cards_up_to'), " ", user.plan.maxCards ] }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: t('profile.plan.cards_unlimited') }), user.plan.maxTasks != null && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { children: [ t('profile.plan.tasks_up_to'), " ", user.plan.maxTasks ] }), user.plan.maxOffers != null && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { children: [ t('profile.plan.offers_up_to'), " ", user.plan.maxOffers ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: user.planExpiresAt && new Date(user.planExpiresAt) < new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) ? 'text-red-500 font-medium' : '', children: user.planExpiresAt ? `${t('profile.plan.valid_until')} ${new Date(user.planExpiresAt).toLocaleDateString()}` : t('profile.plan.no_expiry') }) ] }), (user.plan.features ?? []).length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("ul", { className: "mt-2 space-y-0.5", children: user.plan.features.map((f, i)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("li", { className: "text-xs text-gray-600 flex items-center gap-1.5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-green-500", children: "✓" }), " ", f ] }, i)) }) ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-3 p-4 bg-gray-50 rounded-xl border border-gray-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-5 h-5 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-700", children: t('profile.plan.basic') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.plan.contact_upgrade') }) ] }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("a", { href: "/pricing", className: "inline-flex items-center gap-1.5 text-sm font-medium text-white/70 hover:text-white transition", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 7l5 5m0 0l-5 5m5-5H6" }) }), t('pricing.title', 'Тарифы') ] }) }) ] }), activeTab !== 'cards' && activeTab !== 'reviews' && activeTab !== 'finance' && activeTab !== 'site' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("form", { onSubmit: handleSubmit, className: "space-y-6", children: [ error && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), saved && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-green-50 text-green-700 p-3 rounded-lg text-sm", children: [ "✓ ", t('profile.saved') ] }), activeTab === 'notifications' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800", children: t('notifications.title') }), notifySaved && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-green-50 text-green-700 p-3 rounded-lg text-sm", children: [ "✓ ", t('notifications.saved') ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "font-medium text-gray-800 text-sm", children: t('chat.notif_messages') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-500 mt-0.5", children: t('notifications.messages.desc') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", disabled: notifySaving, onClick: async ()=>{ const next = !notifMessages; setNotifMessages(next); setNotifySaving(true); try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ notifMessages: next }) }); setNotifySaved(true); setTimeout(()=>setNotifySaved(false), 2500); } catch { setNotifMessages(!next); } finally{ setNotifySaving(false); } }, className: `relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 ${notifMessages ? 'bg-blue-600' : 'bg-gray-200'}`, role: "switch", "aria-checked": notifMessages, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notifMessages ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }), showSpecialistTabs && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: `flex items-start justify-between gap-4 ${!user?.plan?.notifyNewTasks ? 'opacity-60' : ''}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "font-medium text-gray-800 text-sm", children: t('notifications.email.new_tasks') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-500 mt-0.5", children: t('notifications.email.new_tasks.desc') }), !user?.plan?.notifyNewTasks && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-xs text-amber-600 mt-1", children: [ "\uD83D\uDD12 ", t('notifications.plan_required') ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", disabled: notifySaving || !user?.plan?.notifyNewTasks, onClick: async ()=>{ const next = !notifyNewTasks; setNotifyNewTasks(next); setNotifySaving(true); try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ notifyNewTasks: next }) }); setNotifySaved(true); setTimeout(()=>setNotifySaved(false), 2500); } catch { setNotifyNewTasks(!next); } finally{ setNotifySaving(false); } }, className: `relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 ${notifyNewTasks ? 'bg-blue-600' : 'bg-gray-200'}`, role: "switch", "aria-checked": notifyNewTasks, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${notifyNewTasks ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }), activeTab === 'referral' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800", children: t('profile.referral.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-500", children: t('profile.referral.desc') }), !referralLoaded ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-sm text-gray-400", children: t('common.loading') }) : referralCode ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs font-medium text-gray-500 mb-1.5", children: t('profile.referral.link_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { readOnly: true, value: `${ false ? 0 : ''}/register?ref=${referralCode}`, className: "flex-1 text-sm border border-gray-200 rounded-lg px-3 py-2 bg-gray-50 text-gray-700 focus:outline-none" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>{ navigator.clipboard.writeText(`${window.location.origin}/register?ref=${referralCode}`); setReferralCopied(true); setTimeout(()=>setReferralCopied(false), 2000); }, className: "px-3 py-2 rounded-lg border border-gray-200 text-sm font-medium hover:bg-gray-50 transition whitespace-nowrap", children: referralCopied ? t('profile.referral.copied') : t('profile.referral.copy') }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-3 p-4 bg-blue-50 rounded-xl", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-2xl font-bold text-blue-700", children: referralCount }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-blue-700", children: t('profile.referral.invited_count') }) ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-sm text-gray-400", children: t('profile.referral.no_code') }) ] }), activeTab === 'auto_response' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AutoResponseTab, { categories: categories, locationTree: locationTree, loaded: arLoaded, onLoad: ()=>{ if (arLoaded) return; _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getAutoResponseSettings */ .Gp().then((s)=>{ setAutoResponse(s); setArLoaded(true); }).catch(()=>setArLoaded(true)); }, settings: autoResponse, saving: arSaving, saved: arSaved, onSave: async (data)=>{ setArSaving(true); setArSaved(false); try { const updated = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateAutoResponseSettings */ .RQ(data); setAutoResponse(updated); setArSaved(true); setTimeout(()=>setArSaved(false), 2500); } catch {} finally{ setArSaving(false); } }, t: t, catLocale: catLocale }), activeTab === 'info' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800 mb-4", children: t('profile.photo') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "relative", children: [ user?.image ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: user.image, alt: user.name, className: "w-20 h-20 rounded-full object-cover border-2 border-gray-200" }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-20 h-20 rounded-full bg-blue-100 flex items-center justify-center text-blue-700 text-2xl font-bold border-2 border-gray-200", children: initials }), avatarUploading && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "absolute inset-0 rounded-full bg-black/40 flex items-center justify-center", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" }) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>fileRef.current?.click(), disabled: avatarUploading, className: "bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg text-sm font-medium disabled:opacity-50", children: t('profile.photo.change') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-1", children: t('profile.photo.hint') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handleAvatarChange }) ] }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6 space-y-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800", children: t('profile.basic_info') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "grid grid-cols-2 gap-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('register.first_name') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: formData.firstName, onChange: (e)=>setFormData({ ...formData, firstName: e.target.value }), required: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('register.last_name') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: formData.lastName, onChange: (e)=>setFormData({ ...formData, lastName: e.target.value }), required: true, className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: "Email" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: user?.email, disabled: true, className: "w-full border border-gray-200 rounded-lg px-3 py-2 text-sm text-gray-400 bg-gray-50 cursor-not-allowed" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-between mt-1.5", children: [ user?.emailVerified ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "flex items-center gap-1 text-xs text-green-600", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "inline-block w-1.5 h-1.5 rounded-full bg-green-500" }), t('profile.email.verified') ] }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "flex items-center gap-1 text-xs text-amber-600", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "inline-block w-1.5 h-1.5 rounded-full bg-amber-500" }), t('profile.email.not_verified') ] }), !user?.emailVerified && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", disabled: resendState !== 'idle', onClick: handleResendVerification, className: "text-xs text-blue-600 hover:underline disabled:opacity-60 disabled:no-underline", children: resendState === 'sending' ? t('login.unverified.sending') : resendState === 'sent' ? t('login.unverified.sent') : t('login.unverified.resend') }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.phone') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "tel", value: formData.phone, onChange: (e)=>setFormData({ ...formData, phone: e.target.value }), placeholder: t('profile.phone.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.bio') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { value: formData.bio, onChange: (e)=>setFormData({ ...formData, bio: e.target.value }), rows: 3, maxLength: 1000, placeholder: t('profile.bio.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 text-sm resize-none" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.language') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mb-2", children: t('profile.language.hint') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("select", { value: formData.locale, onChange: (e)=>setFormData({ ...formData, locale: e.target.value }), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "el", children: "Ελληνικά" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "en", children: "English" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "ru", children: "Русский" }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('profile.languages') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mb-2", children: t('profile.languages.hint') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex flex-wrap gap-2", children: [ { code: 'el', flag: '🇬🇷', label: 'Ελληνικά' }, { code: 'en', flag: '🇬🇧', label: 'English' }, { code: 'ru', flag: '🇷🇺', label: 'Русский' }, { code: 'uk', flag: '🇺🇦', label: 'Українська' }, { code: 'de', flag: '🇩🇪', label: 'Deutsch' }, { code: 'fr', flag: '🇫🇷', label: 'Français' }, { code: 'it', flag: '🇮🇹', label: 'Italiano' }, { code: 'es', flag: '🇪🇸', label: 'Español' }, { code: 'ar', flag: '🇸🇦', label: 'العربية' }, { code: 'zh', flag: '🇨🇳', label: '中文' } ].map(({ code, flag, label })=>{ const selected = selectedLanguages.includes(code); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>setSelectedLanguages(selected ? selectedLanguages.filter((l)=>l !== code) : [ ...selectedLanguages, code ]), className: `flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm border transition ${selected ? 'bg-blue-600 border-blue-600 text-white' : 'bg-white border-gray-300 text-gray-700 hover:border-blue-400'}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: flag }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: label }) ] }, code); }) }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800 mb-3", children: t('profile.role') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: `inline-flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium ${isSpecialist ? 'bg-purple-100 text-purple-700' : isAdmin ? 'bg-red-100 text-red-700' : 'bg-gray-100 text-gray-600'}`, children: isSpecialist ? t('profile.role.specialist') : isAdmin ? t('profile.role.admin') : t('profile.role.customer') }), !isSpecialist && !isAdmin && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mt-4 p-4 bg-purple-50 rounded-xl", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-600 mb-3", children: t('profile.become_specialist.desc') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: handleBecomeSpecialist, disabled: becomingSpecialist, className: "bg-purple-600 hover:bg-purple-700 text-white px-5 py-2 rounded-lg text-sm font-semibold disabled:opacity-50", children: becomingSpecialist ? t('common.loading') : t('profile.become_specialist') }) ] }) ] }), (isSpecialist ? dashData?.features?.hasCanHelpNowStatus : dashData?.features?.hasNeedHelpStatus) && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800 mb-4", children: t('status.title', 'Статус') }), isSpecialist && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-800", children: t('status.can_help_now', 'Готов помочь сейчас') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: t('status.can_help_now_hint', 'Ваша карточка показывается вверху') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", disabled: statusToggling === 'canhelp_now', onClick: async ()=>{ setStatusToggling('canhelp_now'); const nextActive = !myStatuses.includes('canhelp_now'); try { const res = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .toggleStatus */ .bc('canhelp_now', nextActive); setMyStatuses((prev)=>res.isActive ? [ ...prev.filter((s)=>s !== 'canhelp_now'), 'canhelp_now' ] : prev.filter((s)=>s !== 'canhelp_now')); } catch {} finally{ setStatusToggling(null); } }, className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${myStatuses.includes('canhelp_now') ? 'bg-green-500' : 'bg-gray-300'} disabled:opacity-50`, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${myStatuses.includes('canhelp_now') ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }), !isSpecialist && !isAdmin && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-800", children: t('status.need_help', 'Нужна помощь') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: t('status.need_help_hint', 'Специалисты смогут вам предложить помощь') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", disabled: statusToggling === 'need_help', onClick: async ()=>{ setStatusToggling('need_help'); const nextActive = !myStatuses.includes('need_help'); try { const res = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .toggleStatus */ .bc('need_help', nextActive); setMyStatuses((prev)=>res.isActive ? [ ...prev.filter((s)=>s !== 'need_help'), 'need_help' ] : prev.filter((s)=>s !== 'need_help')); } catch {} finally{ setStatusToggling(null); } }, className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${myStatuses.includes('need_help') ? 'bg-blue-500' : 'bg-gray-300'} disabled:opacity-50`, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${myStatuses.includes('need_help') ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }), isSpecialist && (dashData?.plan?.tier === 'pro' || dashData?.plan?.tier === 'ultimate') && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-800 mb-4", children: t('profile.show_contact', 'Показывать контакты') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center justify-between cursor-pointer gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-800", children: t('profile.show_contact_hint', 'Клиенты видят ваш телефон') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: t('profile.show_contact_desc', 'Позволяет клиентам связаться напрямую') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setShowContactInfo((v)=>!v), className: `relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${showContactInfo ? 'bg-blue-500' : 'bg-gray-300'}`, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${showContactInfo ? 'translate-x-6' : 'translate-x-1'}` }) }) ] }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "submit", disabled: saving, className: `w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed ${activeTab === 'notifications' || activeTab === 'referral' || activeTab === 'auto_response' ? 'hidden' : ''}`, children: saving ? t('profile.saving') : t('common.save') }) ] }), showUpgradeModal && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-2xl shadow-xl p-6 w-full max-w-md", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center mb-5", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-5xl", children: "\uD83D\uDE80" }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "text-lg font-bold text-gray-900 text-center mb-2", children: t('profile.upgrade.cards_limit') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-sm text-gray-600 text-center mb-4", children: [ user?.plan?.name ?? t('profile.plan.basic'), " — ", t('profile.plan.cards_up_to'), " ", maxCards ] }), user?.plan && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-gray-50 rounded-xl p-4 mb-5 text-sm text-gray-600 text-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "font-medium text-gray-800", children: t('profile.upgrade.plan') }), ' ', user.plan.name, " — ", user.plan.price, " ", user.plan.currency ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 text-center mb-5", children: t('profile.upgrade.contact') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: ()=>setShowUpgradeModal(false), className: "w-full bg-blue-600 hover:bg-blue-700 text-white py-2.5 rounded-xl text-sm font-semibold", children: t('profile.upgrade.ok') }) ] }) }) ] }) ] }) ] }); }    B__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ProfilePage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); 3{61146undefined148209undefined211271undefined273324undefined326370undefined372404undefined549557(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)undefined596603(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined646653(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined697704(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined754761(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined814821(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined890897(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined959966(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10231030(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined11041111(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined11781185(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined12471254(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined12991306(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined13871394(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined14461453(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined15001507(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined15501557(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined15931598(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined16621670(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined17281750_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSkillSuggestions */ .rlundefined21062129_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zcundefined27492772_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zcundefined42664296"https://api.canhelp.gr"undefined430143230undefined50275049_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .deletePortfolioItem */ .zBundefined53615383_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updatePortfolioItem */ .hlundefined61576161(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined62996303(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined64656469(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined67236726(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined69686971(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined72277230(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined75757578(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined78257828(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined82218225(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined82988301(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined84798482(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined89989002(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined91559159(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined93209323(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined98749877(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1057210576(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1076310766(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1093710941(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1127811281(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1192211926(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1211212115(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1305913062(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1362413627(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1393913943(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1473714740(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1519015194(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1531515319(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1556115564(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1611716121(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1639116394(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1699616999(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1736617370(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1763617639(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1822818231(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1893418937(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1940019404(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1952519529(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1977119774(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2033120334(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2076020763(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2112121125(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2139121394(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2197821981(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2268122685(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2287122875(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2299622999(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2353223536(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2353823546react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined2368523688(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2412124125(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2412724135react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined2457224575(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2516525168(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2545725460(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2564925653(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2592825931(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2632226326(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2665026653(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2730827312(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2861028613(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2878628789(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2939129395(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2960529608(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3014330147(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3067630679(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3082930833(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3099931002(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3121931222(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3147331477(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3162631630(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3174331746(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3204332046(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3260132605(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3271832721(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3301733020(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3369133695(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3385033853(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3429534298(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3508035079: react__WEBPACK_IMPORTED_MODULE_1__.useEffectundefined3509835097: react__WEBPACK_IMPORTED_MODULE_1__.useStateundefined3623736240(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3667236676(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3676536768(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3689636900(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3706637070(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3716737170(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3742237425(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3776137764(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3809538098(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3842438428(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3858838591(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3881438818(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3896838972(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3907739080(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3936039363(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3999439998(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4010340106(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4038740390(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4106241066(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4115541158(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4142241425(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4193241936(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4202542028(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4229442297(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4286642870(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4302043023(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4325543258(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4386343867(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4401744020(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4424844251(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4461944622(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4534845351(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4635446368undefined4641946422(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4642446431react__WEBPACK_IMPORTED_MODULE_1__.Suspenseundefined4649246495(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4657846586(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined4661646630(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)undefined4667646685(0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)undefined4671646724(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)undefined4701247019(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4710447111(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4715447161(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4720247209(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4724947256(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4729647303(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4734647353(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4752147528(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4758947596(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4763947646(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4769647703(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4775347760(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4781347820(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4787447881(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4793847945(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4800748014(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4808648093(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4814448151(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4823948246(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4830648313(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4834348348(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined4843748444(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4850048507(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4856048567(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4861948626(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4871148718(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4879448801(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4885648863(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4891748924(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4898248989(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4907549082(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4913449141(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4919249199(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4924949256(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4931149318(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4938949396(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4944549452(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4950749514(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4957549582(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4962949636(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4968449691(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4974149748(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4979649803(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4986049867(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4992149928(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined4999149998(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5004650053(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5011450121(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5017550182(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5022750234(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5028050287(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5033150338(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5058450600_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .initiateTopUp */ .ohundefined5152051529_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .authClient */ .yKundefined5181151819(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined5189951919_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyReferralInfo */ .stundefined5217852185(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5224252249(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5229552302(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined5236652374(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined5250852523_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyReviews */ .q7undefined5270352711(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined5284652861_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSiteStats */ .RNundefined5306053068(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined5324253250(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined5332253332_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined5336053376_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getCategories */ .bWundefined5339353408_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getLocations */ .Vsundefined5342553442_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyDashboard */ .Hundefined5347553491_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyStatuses */ .z6undefined5352253542_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getBalanceHistory */ .fmundefined5457154587_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getUserRating */ .Bmundefined5487454897_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMySpecialistCards */ .Bbundefined5519655206_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined5614556155_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined5662956639_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined5757857588_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined5812458154"https://api.canhelp.gr"undefined58159581810undefined5845158481"https://api.canhelp.gr"undefined58486585080undefined5853758547_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined5912259145_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .createSpecialistCard */ .eRundefined5971159734_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .deleteSpecialistCard */ .f5undefined6001560018(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6068960692(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6090860911(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6122861231(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6144761450(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6185361856(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6207262075(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6238962392(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6260862611(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6299362996(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6321263215(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6374363746(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6396263965(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6430764310(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6452664529(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6488064883(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6509965102(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6733167335(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined6744267446(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined6757867581(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6809068093(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6835768361(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined6850368506(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6883468838(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined6902069023(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6924969252(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined6956569569(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7012370127(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7027270275(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7040470407(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7058570589(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7116171164(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7145071454(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7161571618(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7183071834(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7244172444(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7276072764(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7293472937(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7319473198(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7340773411(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7406874072(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7522975233(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7546575468(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7576675769(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7665976663(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7687376876(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7755877561(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7849278495(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7881178815(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined7905879061(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined7934879352(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8007580078(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8101881022(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8118381187(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8141981423(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8156081563(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8188881891(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8229782301(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8243882441(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8278782791(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8304883051(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8340383406(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8436284366(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8459984602(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8527685280(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8579885802(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8580485812react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined8595985963(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8690286905(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8747487477(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8837188375(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined8910689109(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined8967889681(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9060990612(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9095190955(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined9117791181(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined9141991422(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9177291775(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9219392196(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9508095084(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined9535495357(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9629896301(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9685396856(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9743697439(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9855798560(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9888898892(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined9912699129(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined9948899491(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined100712100716(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined101553101556(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined102293102297(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined102519102522(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined102706102710(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined102855102858(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined103219103222(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined103744103747(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined104099104102(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined109877109881(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined109883109891react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined110030110033(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined111896111900(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined112197112200(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined112593112596(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined113178113181(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined113398113402(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined113710113713(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined114542114545(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined114730114734(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined115514115518(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined115709115712(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined116475116478(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined117500117503(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined118265118268(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined119021119024(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined119418119421(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined120501120504(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined121296121299(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined122452122455(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined122599122602(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined122837122841(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined123036123039(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined123276123279(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined123534123537(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined123713123717(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined123927123930(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined124227124230(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined124697124701(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined124919124923(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined125187125190(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined125562125566(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined126304126307(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined126627126630(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined127263127267(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined127428127432(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined127654127658(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined127896127899(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined128216128220(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined128958128961(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined129478129481(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined130253130257(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined130531130534(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined131029131032(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined131631131635(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined132259132263(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined132467132471(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined132733132736(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined133119133122(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined133637133640(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined134006134009(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined135141135145(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined135436135440(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined135750135754(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined136057136060(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined136518136521(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined137151137155(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined138204138208(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined139567139570(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined139797139801(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined140040140044(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined140294140297(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined140650140653(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined140958140961(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined141478141481(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined142129142132(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined142442142445(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined142929142933(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined143750143754(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined143970143973(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined144339144343(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined144587144590(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined144975144978(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined146085146088(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined146376146379(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined146935146939(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined146941146949react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined147096147100(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined147532147535(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined148230148233(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined149209149213(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined149435149438(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined149744149748(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined150019150022(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined150523150526(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined151040151044(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined151282151285(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined151652151655(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined152005152009(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined152304152308(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined153042153046(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined153586153589(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined153901153905(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined154543154547(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined155156155159(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined155926155929(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined156153156157(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined156475156478(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined157370157374(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined157646157649(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined158143158146(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined158690158694(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined158847158850(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined159207159210(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined159839159842(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined159983159987(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined160329160332(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined160777160780(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined161562161566(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined161793161796(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined162062162066(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined162511162515(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined162747162750(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined163054163058(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined163532163536(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined163774163778(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined164008164011(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined164369164372(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined164838164841(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined165476165486_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined167093167096(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined167607167611(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined167900167904(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined168134168137(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined168505168508(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined168907168911(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined169597169600(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined170268170278_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined171889171892(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined172483172487(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined172719172722(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined173014173017(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined173319173322(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined173573173577(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined173579173587react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined173718173722(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined173875173878(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined174251174255(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined174526174529(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined174712174738 falseundefined1747421747630undefined175144175147(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined176534176538(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined176811176814(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined177162177165(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined177673177676(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined178071178074(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined178449178475_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getAutoResponseSettings */ .Gpundefined179234179263_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateAutoResponseSettings */ .RQundefined179944179948(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined179950179958react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined180073180077(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined180323180326(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined180646180650(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined180897180901(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined181171181174(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined181595181598(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined182085182088(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined182356182359(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined182886182890(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined183059183062(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined183827183830(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined184212184215(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined185178185182(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined185438185441(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined185761185765(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined186011186015(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined186184186187(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined186592186595(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined187646187650(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined187819187822(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined188226188229(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined189383189387(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined189540189543(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined189899189902(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined190397190401(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined190711190715(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined191034191037(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined191538191542(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined191861191864(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined192460192463(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined193549193553(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined193706193709(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined194076194079(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined195140195144(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined195297195300(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined195665195668(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined196815196819(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined196972196975(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined197345197348(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined197701197705(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined198499198502(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined198848198851(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined199196199199(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined199770199774(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined199927199930(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined200301200304(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined200658200661(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined205152205156(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined206143206146(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined206423206426(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined207164207168(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined207414207417(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined207736207739(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined208338208342(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined208598208601(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined208963208966(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined210017210021(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined210267210270(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined210615210619(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined210899210903(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined211072211075(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined211488211491(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined212039212042(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined212719212734_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .toggleStatus */ .bcundefined213865213868(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined214455214459(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined214739214743(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined214912214915(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined215318215321(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined215873215876(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined216547216562_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .toggleStatus */ .bcundefined217682217685(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined218421218425(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined218671218674(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined219024219028(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined219308219312(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined219481219484(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined219909219912(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined220465220468(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined220959220962(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined221663221666(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined222349222352(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined222534222538(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined222752222755(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined222909222912(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined223213223216(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined223518223522(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined224179224183(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined224435224438(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined225183225186(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined225473225476(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined 0  ŋwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceC__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SchedulePage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource~/* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect, useCallback } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { getMyAvailability, setAvailability, setAvailabilityRange, request } from '@/lib/api'; const STATUS_CYCLE = { available: 'busy', busy: null }; const WEEK_DAYS_BY_LOCALE = { ru: [ 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс' ], en: [ 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su' ], el: [ 'Δε', 'Τρ', 'Τε', 'Πε', 'Πα', 'Σά', 'Κυ' ] }; const MONTHS_BY_LOCALE = { ru: [ 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' ], en: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], el: [ 'Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος' ] }; function toMonthKey(year, month) { return `${year}-${String(month + 1).padStart(2, '0')}`; } function toDateKey(year, month, day) { return `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; } export default function SchedulePage() { const { data: session, isPending } = useSession(); const router = useRouter(); const searchParams = useSearchParams(); const { locale, t } = useLocale(); const now = new Date(); const [viewYear, setViewYear] = useState(now.getFullYear()); const [viewMonth, setViewMonth] = useState(now.getMonth()); // availability map: 'YYYY-MM-DD' → 'available'|'busy' const [avail, setAvail] = useState({}); const [saving, setSaving] = useState(null) // date being saved ; // Range selection state const [rangeStart, setRangeStart] = useState(null); const [rangeMode, setRangeMode] = useState(false); const [rangeStatus, setRangeStatus] = useState('available'); // Google Calendar state const [gcalStatus, setGcalStatus] = useState(null); const [gcalLoading, setGcalLoading] = useState(false); const [gcalToast, setGcalToast] = useState(null); const today = new Date().toISOString().slice(0, 10); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); if (!isPending && session && session.user?.role !== 'specialist' && session.user?.role !== 'admin') router.push('/profile'); }, [ session, isPending ]); // Load Google Calendar status const loadGcalStatus = useCallback(()=>{ request('/google/calendar/status').then(setGcalStatus).catch(()=>setGcalStatus({ connected: false })); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; loadGcalStatus(); // Handle callback redirect params const gcalParam = searchParams.get('gcal'); if (gcalParam === 'connected') { setGcalToast(t('schedule.gcalConnected')); setTimeout(()=>setGcalToast(null), 5000); router.replace('/schedule'); } else if (gcalParam === 'error') { setGcalToast(t('schedule.gcalError')); setTimeout(()=>setGcalToast(null), 5000); router.replace('/schedule'); } }, [ session ]); const loadMonth = useCallback((year, month)=>{ const key = toMonthKey(year, month); getMyAvailability(key).then((rows)=>{ setAvail((prev)=>{ const next = { ...prev }; rows.forEach((r)=>{ next[r.date] = r.status; }); return next; }); }).catch(()=>{}); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; loadMonth(viewYear, viewMonth); // preload next month too const next = new Date(viewYear, viewMonth + 1, 1); loadMonth(next.getFullYear(), next.getMonth()); }, [ session, viewYear, viewMonth, loadMonth ]); function prevMonth() { if (viewMonth === 0) { setViewYear((y)=>y - 1); setViewMonth(11); } else setViewMonth((m)=>m - 1); } function nextMonth() { if (viewMonth === 11) { setViewYear((y)=>y + 1); setViewMonth(0); } else setViewMonth((m)=>m + 1); } async function toggleDay(dateKey) { if (dateKey < today) return; // past — ignore if (rangeMode) { if (!rangeStart) { setRangeStart(dateKey); return; } // Second click — apply range const from = rangeStart < dateKey ? rangeStart : dateKey; const to = rangeStart < dateKey ? dateKey : rangeStart; setRangeStart(null); setSaving('range'); try { await setAvailabilityRange(from, to, rangeStatus); // Update local state setAvail((prev)=>{ const next = { ...prev }; const cur = new Date(from); const end = new Date(to); while(cur <= end){ const d = cur.toISOString().slice(0, 10); if (d >= today) next[d] = rangeStatus; cur.setDate(cur.getDate() + 1); } return next; }); } catch {} setSaving(null); return; } const current = avail[dateKey] ?? null; const next = current === null ? 'available' : STATUS_CYCLE[current]; setSaving(dateKey); // Optimistic setAvail((prev)=>({ ...prev, [dateKey]: next })); try { await setAvailability(dateKey, next); } catch { // Revert on error setAvail((prev)=>({ ...prev, [dateKey]: current })); } setSaving(null); } if (isPending) return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-gray-500", children: t('common.loading') }); const role = session?.user?.role; if (!session || role !== 'specialist' && role !== 'admin') return null; const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; async function connectGcal() { window.location.href = `${apiBase}/api/google/calendar/connect`; } async function disconnectGcal() { if (!confirm(t('schedule.gcalDisconnectConfirm'))) return; setGcalLoading(true); try { await request('/google/calendar/disconnect', { method: 'DELETE' }); setGcalStatus({ connected: false }); } catch {} setGcalLoading(false); } async function importFromGcal() { setGcalLoading(true); try { const res = await request('/google/calendar/import', { method: 'POST' }); setGcalToast(t('schedule.gcalImportDone').replace('{n}', String(res.imported ?? 0))); setTimeout(()=>setGcalToast(null), 5000); // Refresh calendar display loadMonth(viewYear, viewMonth); } catch {} setGcalLoading(false); } return /*#__PURE__*/ _jsxs("div", { className: "max-w-3xl mx-auto px-4 py-10", children: [ gcalToast && /*#__PURE__*/ _jsx("div", { className: "fixed top-4 right-4 z-50 bg-white border border-gray-200 shadow-lg rounded-xl px-4 py-3 text-sm text-gray-800 max-w-xs", children: gcalToast }), /*#__PURE__*/ _jsxs("div", { className: "mb-8", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-2xl font-bold text-white", children: t('schedule.title') }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-white/70 mt-1", children: t('schedule.subtitle') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-4 mb-6", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ _jsx("span", { className: "w-6 h-6 rounded-lg bg-emerald-100 border-2 border-emerald-400 flex items-center justify-center text-xs", children: "✓" }), t('schedule.available') ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ _jsx("span", { className: "w-6 h-6 rounded-lg bg-red-100 border-2 border-red-400 flex items-center justify-center text-xs", children: "✗" }), t('schedule.busy') ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ _jsx("span", { className: "w-6 h-6 rounded-lg bg-white/20 border border-white/30" }), t('schedule.unset') ] }), /*#__PURE__*/ _jsx("div", { className: "text-xs text-white/50 self-center", children: t('schedule.click_hint') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-3 mb-6 p-3 bg-white rounded-xl border border-gray-200", children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [ /*#__PURE__*/ _jsx("div", { onClick: ()=>{ setRangeMode((v)=>!v); setRangeStart(null); }, className: `w-10 h-6 rounded-full transition-colors relative cursor-pointer ${rangeMode ? 'bg-blue-500' : 'bg-gray-200'}`, children: /*#__PURE__*/ _jsx("span", { className: `absolute top-1 w-4 h-4 bg-white rounded-full shadow transition-transform ${rangeMode ? 'translate-x-5' : 'translate-x-1'}` }) }), /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-700", children: t('schedule.range_mode') }) ] }), rangeMode && /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 ml-4", children: [ /*#__PURE__*/ _jsx("button", { onClick: ()=>setRangeStatus('available'), className: `px-3 py-1 rounded-lg text-sm font-medium border transition ${rangeStatus === 'available' ? 'bg-emerald-100 border-emerald-400 text-emerald-700' : 'bg-white border-gray-200 text-gray-500'}`, children: t('schedule.available') }), /*#__PURE__*/ _jsx("button", { onClick: ()=>setRangeStatus('busy'), className: `px-3 py-1 rounded-lg text-sm font-medium border transition ${rangeStatus === 'busy' ? 'bg-red-100 border-red-400 text-red-700' : 'bg-white border-gray-200 text-gray-500'}`, children: t('schedule.busy') }), rangeStart && /*#__PURE__*/ _jsx("span", { className: "text-xs text-blue-600", children: t('schedule.range_from').replace('{date}', rangeStart) }) ] }) ] }), /*#__PURE__*/ _jsx(AvailCalendar, { year: viewYear, month: viewMonth, avail: avail, saving: saving, rangeStart: rangeStart, today: today, onToggle: toggleDay, onPrev: prevMonth, onNext: nextMonth }), /*#__PURE__*/ _jsxs("div", { className: "mt-6 bg-white rounded-2xl border border-gray-200 p-5 shadow-sm", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-4", children: [ /*#__PURE__*/ _jsxs("svg", { width: "22", height: "22", viewBox: "0 0 48 48", fill: "none", children: [ /*#__PURE__*/ _jsx("rect", { width: "48", height: "48", rx: "8", fill: "#fff" }), /*#__PURE__*/ _jsx("path", { d: "M34 14H14a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2V16a2 2 0 0 0-2-2z", fill: "#4285F4" }), /*#__PURE__*/ _jsx("path", { d: "M28 20h-8v2h8v-2zm0 4h-8v2h8v-2zm-2 4h-6v2h6v-2z", fill: "#fff" }), /*#__PURE__*/ _jsx("circle", { cx: "18", cy: "18", r: "2", fill: "#DB4437" }), /*#__PURE__*/ _jsx("circle", { cx: "30", cy: "18", r: "2", fill: "#DB4437" }), /*#__PURE__*/ _jsx("rect", { x: "17", y: "12", width: "2", height: "6", rx: "1", fill: "#DB4437" }), /*#__PURE__*/ _jsx("rect", { x: "29", y: "12", width: "2", height: "6", rx: "1", fill: "#DB4437" }) ] }), /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-900 text-sm", children: t('schedule.googleCalendar') }) ] }), gcalStatus === null ? /*#__PURE__*/ _jsx("div", { className: "text-xs text-gray-400", children: t('common.loading') }) : gcalStatus.connected ? /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [ /*#__PURE__*/ _jsx("circle", { cx: "8", cy: "8", r: "8", fill: "#22c55e" }), /*#__PURE__*/ _jsx("path", { d: "M5 8l2 2 4-4", stroke: "#fff", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) ] }), /*#__PURE__*/ _jsxs("span", { className: "text-sm text-gray-700", children: [ t('schedule.connectedAs'), " ", /*#__PURE__*/ _jsx("span", { className: "font-medium", children: gcalStatus.email }) ] }) ] }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400", children: t('schedule.gcalAutoSyncNote') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-2", children: [ /*#__PURE__*/ _jsx("button", { onClick: importFromGcal, disabled: gcalLoading, className: "px-3 py-1.5 rounded-lg border border-blue-200 bg-blue-50 text-blue-700 text-xs font-medium hover:bg-blue-100 disabled:opacity-50 transition", children: gcalLoading ? t('common.loading') : t('schedule.importFromGoogle') }), /*#__PURE__*/ _jsx("button", { onClick: disconnectGcal, disabled: gcalLoading, className: "px-3 py-1.5 rounded-lg border border-gray-200 bg-white text-gray-500 text-xs font-medium hover:bg-gray-50 disabled:opacity-50 transition", children: t('schedule.disconnectGoogle') }) ] }) ] }) : /*#__PURE__*/ _jsxs("div", { className: "space-y-3", children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500", children: t('schedule.gcalConnectDesc') }), /*#__PURE__*/ _jsxs("button", { onClick: connectGcal, className: "flex items-center gap-2 px-4 py-2 rounded-xl border border-gray-200 bg-white hover:bg-gray-50 transition text-sm font-medium text-gray-700", children: [ /*#__PURE__*/ _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 48 48", fill: "none", children: [ /*#__PURE__*/ _jsx("path", { d: "M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z", fill: "#FFC107" }), /*#__PURE__*/ _jsx("path", { d: "M6.3 14.7l7 5.1C15 16.1 19.1 13 24 13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 16.3 2 9.7 7.4 6.3 14.7z", fill: "#FF3D00" }), /*#__PURE__*/ _jsx("path", { d: "M24 46c5.5 0 10.5-1.9 14.4-5.1l-6.7-5.5C29.5 37 26.9 38 24 38c-6.1 0-11.2-4-13-9.5l-7 5.4C7.6 41.9 15.2 46 24 46z", fill: "#4CAF50" }), /*#__PURE__*/ _jsx("path", { d: "M44.5 20H24v8.5h11.8c-.9 2.8-2.8 5.1-5.3 6.6l6.7 5.5C41.5 37.3 45 31.1 45 24c0-1.3-.2-2.7-.5-4z", fill: "#1976D2" }) ] }), t('schedule.connectGoogle') ] }) ] }) ] }) ] }); } function AvailCalendar({ year, month, avail, saving, rangeStart, today, onToggle, onPrev, onNext }) { const { locale, t } = useLocale(); const weekDays = WEEK_DAYS_BY_LOCALE[locale] ?? WEEK_DAYS_BY_LOCALE.ru; const months = MONTHS_BY_LOCALE[locale] ?? MONTHS_BY_LOCALE.ru; const firstDay = new Date(year, month, 1); // Monday-based: 0=Mon, 6=Sun const startDow = (firstDay.getDay() + 6) % 7; const daysInMonth = new Date(year, month + 1, 0).getDate(); const prevMonthDays = new Date(year, month, 0).getDate(); const cells = []; // Leading days from prev month for(let i = startDow - 1; i >= 0; i--){ cells.push({ day: prevMonthDays - i, cur: false, dateKey: '' }); } // Current month days for(let d = 1; d <= daysInMonth; d++){ cells.push({ day: d, cur: true, dateKey: toDateKey(year, month, d) }); } // Trailing days const remainder = cells.length % 7; if (remainder !== 0) { for(let d = 1; d <= 7 - remainder; d++){ cells.push({ day: d, cur: false, dateKey: '' }); } } // Count summary — only future dates (>= today) const monthPrefix = toDateKey(year, month, 1).slice(0, 7); const availCount = Object.entries(avail).filter(([k, v])=>k.startsWith(monthPrefix) && k >= today && v === 'available').length; const busyCount = Object.entries(avail).filter(([k, v])=>k.startsWith(monthPrefix) && k >= today && v === 'busy').length; return /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl border border-gray-200 overflow-hidden shadow-sm", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-100", children: [ /*#__PURE__*/ _jsx("button", { onClick: onPrev, className: "w-8 h-8 rounded-lg hover:bg-gray-100 flex items-center justify-center text-gray-500 transition", children: "‹" }), /*#__PURE__*/ _jsxs("div", { className: "text-center", children: [ /*#__PURE__*/ _jsxs("h2", { className: "font-semibold text-gray-900", children: [ months[month], " ", year ] }), /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-400 mt-0.5", children: [ /*#__PURE__*/ _jsxs("span", { className: "text-emerald-600 font-medium", children: [ availCount, " ", t('schedule.free') ] }), ' · ', /*#__PURE__*/ _jsxs("span", { className: "text-red-500 font-medium", children: [ busyCount, " ", t('schedule.busy_count') ] }) ] }) ] }), /*#__PURE__*/ _jsx("button", { onClick: onNext, className: "w-8 h-8 rounded-lg hover:bg-gray-100 flex items-center justify-center text-gray-500 transition", children: "›" }) ] }), /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-7 border-b border-gray-100", children: weekDays.map((d)=>/*#__PURE__*/ _jsx("div", { className: "py-2 text-center text-xs font-medium text-gray-400", children: d }, d)) }), /*#__PURE__*/ _jsx("div", { className: "grid grid-cols-7", children: cells.map((cell, idx)=>{ if (!cell.cur) { return /*#__PURE__*/ _jsx("div", { className: "p-1 h-12 flex items-center justify-center text-sm text-gray-200", children: cell.day }, `empty-${idx}`); } const status = avail[cell.dateKey] ?? null; const isPast = cell.dateKey < today; const isToday = cell.dateKey === today; const isSaving = saving === cell.dateKey; const isRangeStart = rangeStart === cell.dateKey; let cellCls = 'h-12 flex flex-col items-center justify-center rounded-xl m-0.5 text-sm font-medium transition-all select-none '; if (isPast) { cellCls += 'text-gray-200 cursor-default '; } else if (status === 'available') { cellCls += 'bg-emerald-100 border-2 border-emerald-400 text-emerald-700 cursor-pointer hover:bg-emerald-200 '; } else if (status === 'busy') { cellCls += 'bg-red-100 border-2 border-red-400 text-red-700 cursor-pointer hover:bg-red-200 '; } else { cellCls += 'bg-gray-50 border border-gray-200 text-gray-700 cursor-pointer hover:bg-blue-50 hover:border-blue-300 '; } if (isToday) cellCls += 'ring-2 ring-blue-400 ring-offset-1 '; if (isRangeStart) cellCls += '!ring-2 !ring-blue-500 !ring-offset-1 scale-105 '; if (isSaving) cellCls += 'opacity-60 pointer-events-none '; return /*#__PURE__*/ _jsxs("button", { className: cellCls, onClick: ()=>onToggle(cell.dateKey), disabled: isPast || isSaving, title: status === 'available' ? t('schedule.available') : status === 'busy' ? t('schedule.busy') : t('schedule.click_to_set'), children: [ /*#__PURE__*/ _jsx("span", { children: cell.day }), !isPast && status === 'available' && /*#__PURE__*/ _jsx("span", { className: "text-[9px] leading-none text-emerald-600", children: t('schedule.available').toLowerCase() }), !isPast && status === 'busy' && /*#__PURE__*/ _jsx("span", { className: "text-[9px] leading-none text-red-500", children: t('schedule.busy').toLowerCase() }), isSaving && /*#__PURE__*/ _jsx("span", { className: "text-[8px] text-gray-400", children: "..." }) ] }, cell.dateKey); }) }) ] }); } cl={}_JL9GLS 0 7  _ k r \ d ~ 5ETg5CQTIgl_ !!!^"a"#"###}$$.%1%&&Y'\'((w)z)**q+u+(,_,,,,{.~.//00d1g153834496<677S8W888:":Y;\;t<w<q=t=>_>??|AARCUCDD?ECEEEFFGG@ICIYK]KLL+N.NOOOOQQ*T_.TTTUUVVTXWXZ Zh[k[\\__{eeffffggrhvhiijjlTlnnooyp|pIqLq rrxxzzzz{{||(0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em)(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyAvailability */ .iN)(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .setAvailabilityRange */ .D1)(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .setAvailability */ .OM)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)"https://api.canhelp.gr"0(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs) ^__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SchedulePage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); /* __next_internal_client_entry_do_not_use__ default auto */ const STATUS_CYCLE = { available: 'busy', busy: null }; const WEEK_DAYS_BY_LOCALE = { ru: [ 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс' ], en: [ 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su' ], el: [ 'Δε', 'Τρ', 'Τε', 'Πε', 'Πα', 'Σά', 'Κυ' ] }; const MONTHS_BY_LOCALE = { ru: [ 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' ], en: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], el: [ 'Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος' ] }; function toMonthKey(year, month) { return `${year}-${String(month + 1).padStart(2, '0')}`; } function toDateKey(year, month, day) { return `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; } function SchedulePage() { const { data: session, isPending } = (0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)(); const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const searchParams = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)(); const { locale, t } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)(); const now = new Date(); const [viewYear, setViewYear] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(now.getFullYear()); const [viewMonth, setViewMonth] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(now.getMonth()); // availability map: 'YYYY-MM-DD' → 'available'|'busy' const [avail, setAvail] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({}); const [saving, setSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null) // date being saved ; // Range selection state const [rangeStart, setRangeStart] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [rangeMode, setRangeMode] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [rangeStatus, setRangeStatus] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)('available'); // Google Calendar state const [gcalStatus, setGcalStatus] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [gcalLoading, setGcalLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [gcalToast, setGcalToast] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const today = new Date().toISOString().slice(0, 10); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!isPending && !session) router.push('/login'); if (!isPending && session && session.user?.role !== 'specialist' && session.user?.role !== 'admin') router.push('/profile'); }, [ session, isPending ]); // Load Google Calendar status const loadGcalStatus = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)(()=>{ (0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em)('/google/calendar/status').then(setGcalStatus).catch(()=>setGcalStatus({ connected: false })); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!session) return; loadGcalStatus(); // Handle callback redirect params const gcalParam = searchParams.get('gcal'); if (gcalParam === 'connected') { setGcalToast(t('schedule.gcalConnected')); setTimeout(()=>setGcalToast(null), 5000); router.replace('/schedule'); } else if (gcalParam === 'error') { setGcalToast(t('schedule.gcalError')); setTimeout(()=>setGcalToast(null), 5000); router.replace('/schedule'); } }, [ session ]); const loadMonth = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((year, month)=>{ const key = toMonthKey(year, month); (0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyAvailability */ .iN)(key).then((rows)=>{ setAvail((prev)=>{ const next = { ...prev }; rows.forEach((r)=>{ next[r.date] = r.status; }); return next; }); }).catch(()=>{}); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!session) return; loadMonth(viewYear, viewMonth); // preload next month too const next = new Date(viewYear, viewMonth + 1, 1); loadMonth(next.getFullYear(), next.getMonth()); }, [ session, viewYear, viewMonth, loadMonth ]); function prevMonth() { if (viewMonth === 0) { setViewYear((y)=>y - 1); setViewMonth(11); } else setViewMonth((m)=>m - 1); } function nextMonth() { if (viewMonth === 11) { setViewYear((y)=>y + 1); setViewMonth(0); } else setViewMonth((m)=>m + 1); } async function toggleDay(dateKey) { if (dateKey < today) return; // past — ignore if (rangeMode) { if (!rangeStart) { setRangeStart(dateKey); return; } // Second click — apply range const from = rangeStart < dateKey ? rangeStart : dateKey; const to = rangeStart < dateKey ? dateKey : rangeStart; setRangeStart(null); setSaving('range'); try { await (0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .setAvailabilityRange */ .D1)(from, to, rangeStatus); // Update local state setAvail((prev)=>{ const next = { ...prev }; const cur = new Date(from); const end = new Date(to); while(cur <= end){ const d = cur.toISOString().slice(0, 10); if (d >= today) next[d] = rangeStatus; cur.setDate(cur.getDate() + 1); } return next; }); } catch {} setSaving(null); return; } const current = avail[dateKey] ?? null; const next = current === null ? 'available' : STATUS_CYCLE[current]; setSaving(dateKey); // Optimistic setAvail((prev)=>({ ...prev, [dateKey]: next })); try { await (0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .setAvailability */ .OM)(dateKey, next); } catch { // Revert on error setAvail((prev)=>({ ...prev, [dateKey]: current })); } setSaving(null); } if (isPending) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-20 text-gray-500", children: t('common.loading') }); const role = session?.user?.role; if (!session || role !== 'specialist' && role !== 'admin') return null; const apiBase = "https://api.canhelp.gr" || 0; async function connectGcal() { window.location.href = `${apiBase}/api/google/calendar/connect`; } async function disconnectGcal() { if (!confirm(t('schedule.gcalDisconnectConfirm'))) return; setGcalLoading(true); try { await (0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em)('/google/calendar/disconnect', { method: 'DELETE' }); setGcalStatus({ connected: false }); } catch {} setGcalLoading(false); } async function importFromGcal() { setGcalLoading(true); try { const res = await (0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em)('/google/calendar/import', { method: 'POST' }); setGcalToast(t('schedule.gcalImportDone').replace('{n}', String(res.imported ?? 0))); setTimeout(()=>setGcalToast(null), 5000); // Refresh calendar display loadMonth(viewYear, viewMonth); } catch {} setGcalLoading(false); } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "max-w-3xl mx-auto px-4 py-10", children: [ gcalToast && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "fixed top-4 right-4 z-50 bg-white border border-gray-200 shadow-lg rounded-xl px-4 py-3 text-sm text-gray-800 max-w-xs", children: gcalToast }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-2xl font-bold text-white", children: t('schedule.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-white/70 mt-1", children: t('schedule.subtitle') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-wrap gap-4 mb-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-6 h-6 rounded-lg bg-emerald-100 border-2 border-emerald-400 flex items-center justify-center text-xs", children: "✓" }), t('schedule.available') ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-6 h-6 rounded-lg bg-red-100 border-2 border-red-400 flex items-center justify-center text-xs", children: "✗" }), t('schedule.busy') ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 text-sm text-white/80", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-6 h-6 rounded-lg bg-white/20 border border-white/30" }), t('schedule.unset') ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-xs text-white/50 self-center", children: t('schedule.click_hint') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-3 mb-6 p-3 bg-white rounded-xl border border-gray-200", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { onClick: ()=>{ setRangeMode((v)=>!v); setRangeStart(null); }, className: `w-10 h-6 rounded-full transition-colors relative cursor-pointer ${rangeMode ? 'bg-blue-500' : 'bg-gray-200'}`, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: `absolute top-1 w-4 h-4 bg-white rounded-full shadow transition-transform ${rangeMode ? 'translate-x-5' : 'translate-x-1'}` }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm font-medium text-gray-700", children: t('schedule.range_mode') }) ] }), rangeMode && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 ml-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: ()=>setRangeStatus('available'), className: `px-3 py-1 rounded-lg text-sm font-medium border transition ${rangeStatus === 'available' ? 'bg-emerald-100 border-emerald-400 text-emerald-700' : 'bg-white border-gray-200 text-gray-500'}`, children: t('schedule.available') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: ()=>setRangeStatus('busy'), className: `px-3 py-1 rounded-lg text-sm font-medium border transition ${rangeStatus === 'busy' ? 'bg-red-100 border-red-400 text-red-700' : 'bg-white border-gray-200 text-gray-500'}`, children: t('schedule.busy') }), rangeStart && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs text-blue-600", children: t('schedule.range_from').replace('{date}', rangeStart) }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AvailCalendar, { year: viewYear, month: viewMonth, avail: avail, saving: saving, rangeStart: rangeStart, today: today, onToggle: toggleDay, onPrev: prevMonth, onNext: nextMonth }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mt-6 bg-white rounded-2xl border border-gray-200 p-5 shadow-sm", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 mb-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { width: "22", height: "22", viewBox: "0 0 48 48", fill: "none", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("rect", { width: "48", height: "48", rx: "8", fill: "#fff" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M34 14H14a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2V16a2 2 0 0 0-2-2z", fill: "#4285F4" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M28 20h-8v2h8v-2zm0 4h-8v2h8v-2zm-2 4h-6v2h6v-2z", fill: "#fff" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("circle", { cx: "18", cy: "18", r: "2", fill: "#DB4437" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("circle", { cx: "30", cy: "18", r: "2", fill: "#DB4437" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("rect", { x: "17", y: "12", width: "2", height: "6", rx: "1", fill: "#DB4437" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("rect", { x: "29", y: "12", width: "2", height: "6", rx: "1", fill: "#DB4437" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-semibold text-gray-900 text-sm", children: t('schedule.googleCalendar') }) ] }), gcalStatus === null ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-xs text-gray-400", children: t('common.loading') }) : gcalStatus.connected ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("circle", { cx: "8", cy: "8", r: "8", fill: "#22c55e" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M5 8l2 2 4-4", stroke: "#fff", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-sm text-gray-700", children: [ t('schedule.connectedAs'), " ", /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "font-medium", children: gcalStatus.email }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400", children: t('schedule.gcalAutoSyncNote') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-wrap gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: importFromGcal, disabled: gcalLoading, className: "px-3 py-1.5 rounded-lg border border-blue-200 bg-blue-50 text-blue-700 text-xs font-medium hover:bg-blue-100 disabled:opacity-50 transition", children: gcalLoading ? t('common.loading') : t('schedule.importFromGoogle') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: disconnectGcal, disabled: gcalLoading, className: "px-3 py-1.5 rounded-lg border border-gray-200 bg-white text-gray-500 text-xs font-medium hover:bg-gray-50 disabled:opacity-50 transition", children: t('schedule.disconnectGoogle') }) ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "space-y-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-500", children: t('schedule.gcalConnectDesc') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { onClick: connectGcal, className: "flex items-center gap-2 px-4 py-2 rounded-xl border border-gray-200 bg-white hover:bg-gray-50 transition text-sm font-medium text-gray-700", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 48 48", fill: "none", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z", fill: "#FFC107" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M6.3 14.7l7 5.1C15 16.1 19.1 13 24 13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 16.3 2 9.7 7.4 6.3 14.7z", fill: "#FF3D00" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M24 46c5.5 0 10.5-1.9 14.4-5.1l-6.7-5.5C29.5 37 26.9 38 24 38c-6.1 0-11.2-4-13-9.5l-7 5.4C7.6 41.9 15.2 46 24 46z", fill: "#4CAF50" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M44.5 20H24v8.5h11.8c-.9 2.8-2.8 5.1-5.3 6.6l6.7 5.5C41.5 37.3 45 31.1 45 24c0-1.3-.2-2.7-.5-4z", fill: "#1976D2" }) ] }), t('schedule.connectGoogle') ] }) ] }) ] }) ] }); } function AvailCalendar({ year, month, avail, saving, rangeStart, today, onToggle, onPrev, onNext }) { const { locale, t } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)(); const weekDays = WEEK_DAYS_BY_LOCALE[locale] ?? WEEK_DAYS_BY_LOCALE.ru; const months = MONTHS_BY_LOCALE[locale] ?? MONTHS_BY_LOCALE.ru; const firstDay = new Date(year, month, 1); // Monday-based: 0=Mon, 6=Sun const startDow = (firstDay.getDay() + 6) % 7; const daysInMonth = new Date(year, month + 1, 0).getDate(); const prevMonthDays = new Date(year, month, 0).getDate(); const cells = []; // Leading days from prev month for(let i = startDow - 1; i >= 0; i--){ cells.push({ day: prevMonthDays - i, cur: false, dateKey: '' }); } // Current month days for(let d = 1; d <= daysInMonth; d++){ cells.push({ day: d, cur: true, dateKey: toDateKey(year, month, d) }); } // Trailing days const remainder = cells.length % 7; if (remainder !== 0) { for(let d = 1; d <= 7 - remainder; d++){ cells.push({ day: d, cur: false, dateKey: '' }); } } // Count summary — only future dates (>= today) const monthPrefix = toDateKey(year, month, 1).slice(0, 7); const availCount = Object.entries(avail).filter(([k, v])=>k.startsWith(monthPrefix) && k >= today && v === 'available').length; const busyCount = Object.entries(avail).filter(([k, v])=>k.startsWith(monthPrefix) && k >= today && v === 'busy').length; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-2xl border border-gray-200 overflow-hidden shadow-sm", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-100", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: onPrev, className: "w-8 h-8 rounded-lg hover:bg-gray-100 flex items-center justify-center text-gray-500 transition", children: "‹" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("h2", { className: "font-semibold text-gray-900", children: [ months[month], " ", year ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-xs text-gray-400 mt-0.5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-emerald-600 font-medium", children: [ availCount, " ", t('schedule.free') ] }), ' · ', /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-red-500 font-medium", children: [ busyCount, " ", t('schedule.busy_count') ] }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: onNext, className: "w-8 h-8 rounded-lg hover:bg-gray-100 flex items-center justify-center text-gray-500 transition", children: "›" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "grid grid-cols-7 border-b border-gray-100", children: weekDays.map((d)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "py-2 text-center text-xs font-medium text-gray-400", children: d }, d)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "grid grid-cols-7", children: cells.map((cell, idx)=>{ if (!cell.cur) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "p-1 h-12 flex items-center justify-center text-sm text-gray-200", children: cell.day }, `empty-${idx}`); } const status = avail[cell.dateKey] ?? null; const isPast = cell.dateKey < today; const isToday = cell.dateKey === today; const isSaving = saving === cell.dateKey; const isRangeStart = rangeStart === cell.dateKey; let cellCls = 'h-12 flex flex-col items-center justify-center rounded-xl m-0.5 text-sm font-medium transition-all select-none '; if (isPast) { cellCls += 'text-gray-200 cursor-default '; } else if (status === 'available') { cellCls += 'bg-emerald-100 border-2 border-emerald-400 text-emerald-700 cursor-pointer hover:bg-emerald-200 '; } else if (status === 'busy') { cellCls += 'bg-red-100 border-2 border-red-400 text-red-700 cursor-pointer hover:bg-red-200 '; } else { cellCls += 'bg-gray-50 border border-gray-200 text-gray-700 cursor-pointer hover:bg-blue-50 hover:border-blue-300 '; } if (isToday) cellCls += 'ring-2 ring-blue-400 ring-offset-1 '; if (isRangeStart) cellCls += '!ring-2 !ring-blue-500 !ring-offset-1 scale-105 '; if (isSaving) cellCls += 'opacity-60 pointer-events-none '; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { className: cellCls, onClick: ()=>onToggle(cell.dateKey), disabled: isPast || isSaving, title: status === 'available' ? t('schedule.available') : status === 'busy' ? t('schedule.busy') : t('schedule.click_to_set'), children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: cell.day }), !isPast && status === 'available' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-[9px] leading-none text-emerald-600", children: t('schedule.available').toLowerCase() }), !isPast && status === 'busy' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-[9px] leading-none text-red-500", children: t('schedule.busy').toLowerCase() }), isSaving && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-[8px] text-gray-400", children: "..." }) ] }, cell.dateKey); }) }) ] }); }    C__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SchedulePage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); L61123undefined125181undefined183243undefined245284undefined286330undefined332425undefined18491863undefined19311940(0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)undefined19641972(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined20022016(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)undefined20472055(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)undefined21242131(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21912198(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23062313(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined23522359(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined24622469(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined25162523(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined25752582(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined26672674(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined27252732(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined27802787(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined29082916(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined32303240(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined32563262(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em)undefined34543462(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined40674077(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined41494165(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getMyAvailability */ .iN)undefined45354543(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined57165735(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .setAvailabilityRange */ .D1)undefined67096723(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .setAvailability */ .OM)undefined69936996(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined72417271"https://api.canhelp.gr"undefined727672980undefined75827588(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em)undefined79187924(0,_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em)undefined83208324(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined84458448(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined86868690(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined87988801(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined89918994(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined92089212(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined93419345(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined95189521(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined98969900(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1007310076(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1043810442(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1061510618(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1089310896(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1112111125(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1130411308(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1147611479(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1189911902(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1219412197(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1248412488(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1264412647(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1310913112(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1356113564(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1388113884(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1424914253(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1441914423(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1457914583(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1487914882(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1519315196(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1547615479(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1572915732(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1604016043(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1635116354(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1676416767(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1723417237(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1753717540(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1772717731(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1786817872(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1804718051(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1839518398(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1875218755(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1928919293(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1961119614(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2001120014(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2023820242(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2041420417(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2096020963(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2154621550(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2168721690(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2191321917(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2226422268(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2261222615(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2304723050(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2340023403(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2375323756(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2447024478(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)undefined2597925983(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2613226136(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2630826311(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2659526599(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2673826742(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2711127115(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2729327297(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2778727791(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2833728340(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2864928652(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2879328796(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2900129004(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2919529198(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3085230856(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3125831261(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3143531438(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3172331726(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3198231985(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined I  ɮwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceJ__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SpecialistSetupPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource/* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/navigation'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import * as api from '@/lib/api'; const TOTAL_STEPS = 5; // ─── Step indicator ──────────────────────────────────────────────────────── function StepIndicator({ current, total }) { return /*#__PURE__*/ _jsx("div", { className: "flex items-center justify-center gap-2 mb-8", children: Array.from({ length: total }, (_, i)=>i + 1).map((n)=>/*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ _jsx("div", { className: `w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold transition-colors ${n < current ? 'bg-green-500 text-white' : n === current ? 'bg-blue-600 text-white ring-4 ring-blue-200' : 'bg-gray-200 text-gray-400'}`, children: n < current ? /*#__PURE__*/ _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: /*#__PURE__*/ _jsx("path", { d: "M2 7l4 4 6-6", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) : n }), n < total && /*#__PURE__*/ _jsx("div", { className: `w-8 h-0.5 ${n < current ? 'bg-green-500' : 'bg-gray-200'}` }) ] }, n)) }); } // ─── Step 1: Welcome ─────────────────────────────────────────────────────── function Step1Welcome({ t, onNext }) { return /*#__PURE__*/ _jsxs("div", { className: "text-center", children: [ /*#__PURE__*/ _jsx("div", { className: "w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6", children: /*#__PURE__*/ _jsxs("svg", { width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "#2563eb", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [ /*#__PURE__*/ _jsx("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }), /*#__PURE__*/ _jsx("circle", { cx: "12", cy: "7", r: "4" }) ] }) }), /*#__PURE__*/ _jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-2", children: t('specialist_setup.step1.title') }), /*#__PURE__*/ _jsx("p", { className: "text-blue-600 font-medium mb-4", children: t('specialist_setup.step1.subtitle') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm leading-relaxed mb-8 max-w-sm mx-auto", children: t('specialist_setup.step1.desc') }), /*#__PURE__*/ _jsxs("div", { className: "bg-gray-50 rounded-xl p-5 text-left mb-8 max-w-sm mx-auto", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-semibold text-gray-700 mb-3", children: t('specialist_setup.step1.what_next') }), /*#__PURE__*/ _jsx("ul", { className: "space-y-2", children: [ t('specialist_setup.step1.item1'), t('specialist_setup.step1.item2'), t('specialist_setup.step1.item3'), t('specialist_setup.step1.item4'), t('specialist_setup.step1.item5') ].map((item, i)=>/*#__PURE__*/ _jsxs("li", { className: "flex items-center gap-2 text-sm text-gray-600", children: [ /*#__PURE__*/ _jsx("span", { className: "w-5 h-5 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center text-xs font-bold shrink-0", children: i + 1 }), item ] }, i)) }) ] }), /*#__PURE__*/ _jsxs("button", { onClick: onNext, className: "w-full max-w-xs bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 transition", children: [ t('specialist_setup.next'), " →" ] }) ] }); } // ─── Step 2: Basic profile ───────────────────────────────────────────────── function Step2Profile({ t, onNext, onBack }) { const [bio, setBio] = useState(''); const [phone, setPhone] = useState(''); const [saving, setSaving] = useState(false); const [avatarUrl, setAvatarUrl] = useState(null); const [uploading, setUploading] = useState(false); const fileRef = useRef(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.request('/users/me', {}).then((u)=>{ setBio(u.bio ?? ''); setPhone(u.phone ?? ''); setAvatarUrl(u.image ?? null); }).catch(()=>{}); }, []); async function handleAvatarChange(e) { const file = e.target.files?.[0]; if (!file) return; setUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); const fullUrl = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}${url}`; await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ image: fullUrl }) }); setAvatarUrl(fullUrl); } catch {} finally{ setUploading(false); if (fileRef.current) fileRef.current.value = ''; } } async function handleSave() { setSaving(true); try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ bio: bio || undefined, phone: phone || undefined }) }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step2.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step2.subtitle') }), /*#__PURE__*/ _jsxs("div", { className: "mb-5", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step2.photo_label') }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-4", children: [ /*#__PURE__*/ _jsx("div", { className: "w-16 h-16 rounded-full bg-gray-100 border-2 border-gray-200 overflow-hidden shrink-0 flex items-center justify-center", children: avatarUrl ? /*#__PURE__*/ _jsx("img", { src: avatarUrl, alt: "", className: "w-full h-full object-cover" }) : /*#__PURE__*/ _jsxs("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "#9ca3af", strokeWidth: "2", children: [ /*#__PURE__*/ _jsx("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }), /*#__PURE__*/ _jsx("circle", { cx: "12", cy: "7", r: "4" }) ] }) }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>fileRef.current?.click(), disabled: uploading, className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium text-gray-700 disabled:opacity-50 transition", children: uploading ? t('specialist_setup.step2.photo_uploading') : t('specialist_setup.step2.photo_btn') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mt-1", children: t('specialist_setup.step2.photo_hint') }) ] }), /*#__PURE__*/ _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handleAvatarChange }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-4", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step2.bio_label') }), /*#__PURE__*/ _jsx("textarea", { value: bio, onChange: (e)=>setBio(e.target.value), rows: 4, maxLength: 1000, placeholder: t('specialist_setup.step2.bio_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step2.phone_label') }), /*#__PURE__*/ _jsx("input", { type: "tel", value: phone, onChange: (e)=>setPhone(e.target.value), placeholder: t('specialist_setup.step2.phone_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 3: Service card ────────────────────────────────────────────────── function Step3Card({ t, onNext, onBack, onCardCreated }) { const [title, setTitle] = useState(''); const [desc, setDesc] = useState(''); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); async function handleSave() { if (!title.trim()) { setError(t('specialist_setup.step3.title_required')); return; } setError(''); setSaving(true); try { const card = await api.createSpecialistCard({ title: title.trim(), description: desc || undefined }); onCardCreated(card); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step3.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step3.subtitle') }), /*#__PURE__*/ _jsxs("div", { className: "mb-4", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step3.title_label') }), /*#__PURE__*/ _jsx("input", { value: title, onChange: (e)=>{ setTitle(e.target.value); if (error) setError(''); }, maxLength: 200, placeholder: t('specialist_setup.step3.title_placeholder'), className: `w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 ${error ? 'border-red-400' : 'border-gray-300'}` }), error && /*#__PURE__*/ _jsx("p", { className: "text-red-500 text-xs mt-1", children: error }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step3.desc_label') }), /*#__PURE__*/ _jsx("textarea", { value: desc, onChange: (e)=>setDesc(e.target.value), rows: 5, maxLength: 1000, placeholder: t('specialist_setup.step3.desc_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 4: Skills & Categories ────────────────────────────────────────── function Step4Skills({ t, onNext, onBack, card, catLocale }) { const [skills, setSkills] = useState(card?.skills ?? []); const [skillInput, setSkillInput] = useState(''); const [categories, setCategories] = useState(card?.categories ?? []); const [allCategories, setAllCategories] = useState([]); const [suggestions, setSuggestions] = useState([]); const [saving, setSaving] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.getCategories().then(setAllCategories).catch(()=>{}); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.getSkillSuggestions(categories.length > 0 ? categories : undefined).then(setSuggestions).catch(()=>{}); }, [ categories ]); function addSkill(s) { const trimmed = s.trim(); if (trimmed && !skills.includes(trimmed)) setSkills([ ...skills, trimmed ]); setSkillInput(''); } function toggleCategory(slug, childSlugs = []) { if (categories.includes(slug)) { setCategories(categories.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setCategories([ ...new Set([ ...categories, slug, ...childSlugs ]) ]); } } async function handleSave() { if (!card) { onNext(); return; } setSaving(true); try { await api.updateSpecialistCard(card.id, { skills, categories }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step4.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step4.subtitle') }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step4.skills_label') }), skills.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-2 mb-2", children: skills.map((s)=>/*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5 bg-blue-50 text-blue-700 text-sm px-3 py-1 rounded-full", children: [ s, /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setSkills(skills.filter((x)=>x !== s)), className: "text-blue-400 hover:text-blue-700 leading-none text-base", children: "\xd7" }) ] }, s)) }), /*#__PURE__*/ _jsxs("div", { className: "flex gap-2", children: [ /*#__PURE__*/ _jsx("input", { value: skillInput, onChange: (e)=>setSkillInput(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') { e.preventDefault(); addSkill(skillInput); } }, placeholder: t('specialist_setup.step4.skills_placeholder'), className: "flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>addSkill(skillInput), className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium", children: t('specialist_setup.step4.skills_add') }) ] }), suggestions.length > 0 && /*#__PURE__*/ _jsx("div", { className: "flex flex-wrap gap-1.5 mt-2", children: suggestions.map((s)=>s.names[catLocale] ?? s.names.el).filter((name, i, arr)=>arr.indexOf(name) === i && !skills.includes(name)).slice(0, 12).map((name)=>/*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>addSkill(name), className: "text-xs px-2.5 py-1 border border-gray-200 rounded-full text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: [ "+ ", name ] }, name)) }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mb-6", children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step4.categories_label') }), /*#__PURE__*/ _jsx("div", { className: "space-y-2 max-h-64 overflow-y-auto border border-gray-200 rounded-xl p-3", children: allCategories.map((cat)=>{ const catName = cat.names?.[catLocale] ?? cat.names?.el ?? cat.slug; const children = cat.children ?? []; const childSlugs = children.map((c)=>c.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: categories.includes(cat.slug), onChange: ()=>toggleCategory(cat.slug, childSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("span", { className: "text-sm font-medium text-gray-800", children: [ cat.icon && /*#__PURE__*/ _jsx("span", { className: "mr-1", children: cat.icon }), catName ] }) ] }), children.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-1.5 space-y-1.5", children: children.map((sub)=>{ const subName = sub.names?.[catLocale] ?? sub.names?.el ?? sub.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: categories.includes(sub.slug), onChange: ()=>toggleCategory(sub.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: subName }) ] }, sub.id); }) }) ] }, cat.id); }) }) ] }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 5: Geography ───────────────────────────────────────────────────── function Step5Geography({ t, onNext, onBack, card, catLocale }) { const [locations, setLocations] = useState(card?.locations ?? []); const [locationTree, setLocationTree] = useState([]); const [saving, setSaving] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ api.getLocations().then(setLocationTree).catch(()=>{}); }, []); function toggleLocation(slug, childSlugs = []) { if (locations.includes(slug)) { setLocations(locations.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocations([ ...new Set([ ...locations, slug, ...childSlugs ]) ]); } } async function handleSave() { if (!card) { onNext(); return; } setSaving(true); try { await api.updateSpecialistCard(card.id, { locations }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step5.title') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: t('specialist_setup.step5.subtitle') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 mb-5", children: t('specialist_setup.step5.hint') }), /*#__PURE__*/ _jsx("div", { className: "space-y-3 max-h-72 overflow-y-auto border border-gray-200 rounded-xl p-3 mb-6", children: locationTree.map((city)=>{ const cityName = city.names?.[catLocale] ?? city.names?.el ?? city.slug; const districts = city.children ?? []; const districtSlugs = districts.map((d)=>d.slug); return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: locations.includes(city.slug), onChange: ()=>toggleLocation(city.slug, districtSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm font-medium text-gray-800", children: cityName }) ] }), districts.length > 0 && /*#__PURE__*/ _jsx("div", { className: "ml-6 mt-1.5 space-y-1.5", children: districts.map((d)=>{ const dName = d.names?.[catLocale] ?? d.names?.el ?? d.slug; return /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", checked: locations.includes(d.slug), onChange: ()=>toggleLocation(d.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-600", children: dName }) ] }, d.id); }) }) ] }, city.id); }) }), /*#__PURE__*/ _jsx(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving, isLast: true }) ] }); } // ─── Done screen ─────────────────────────────────────────────────────────── function StepDone({ t }) { return /*#__PURE__*/ _jsxs("div", { className: "text-center py-4", children: [ /*#__PURE__*/ _jsx("div", { className: "w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-6", children: /*#__PURE__*/ _jsx("svg", { width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "#16a34a", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /*#__PURE__*/ _jsx("path", { d: "M20 6L9 17l-5-5" }) }) }), /*#__PURE__*/ _jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-2", children: t('specialist_setup.done.title') }), /*#__PURE__*/ _jsx("p", { className: "text-green-600 font-medium mb-4", children: t('specialist_setup.done.subtitle') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm leading-relaxed mb-8 max-w-sm mx-auto", children: t('specialist_setup.done.desc') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col sm:flex-row gap-3 justify-center", children: [ /*#__PURE__*/ _jsx("a", { href: "/profile", className: "px-6 py-3 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 transition text-center", children: t('specialist_setup.go_to_profile') }), /*#__PURE__*/ _jsx("a", { href: "/tasks", className: "px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition text-center", children: t('specialist_setup.browse_tasks') }) ] }) ] }); } // ─── Navigation buttons ──────────────────────────────────────────────────── function NavButtons({ t, onBack, onNext, loading, isLast }) { return /*#__PURE__*/ _jsxs("div", { className: "flex gap-3 pt-2", children: [ /*#__PURE__*/ _jsxs("button", { type: "button", onClick: onBack, className: "flex-1 px-4 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition", children: [ "← ", t('specialist_setup.back') ] }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: onNext, disabled: loading, className: "flex-[2] px-4 py-3 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 transition", children: loading ? '...' : isLast ? t('specialist_setup.finish') : `${t('specialist_setup.next')} →` }) ] }); } // ─── Main page ───────────────────────────────────────────────────────────── export default function SpecialistSetupPage() { const { data: session, isPending } = useSession(); const router = useRouter(); const { t, locale } = useLocale(); const [step, setStep] = useState(1); const [card, setCard] = useState(null); const catLocale = locale === 'ru' ? 'ru' : locale === 'en' ? 'en' : 'el'; process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); if (!isPending && session && session.user?.role !== 'specialist') router.push('/become-specialist'); }, [ session, isPending ]); if (isPending || !session) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const isDone = step > TOTAL_STEPS; return /*#__PURE__*/ _jsx("div", { className: "min-h-screen py-10 px-4", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-lg mx-auto", children: [ /*#__PURE__*/ _jsxs("div", { className: "text-center mb-6", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-lg font-semibold text-white/90", children: t('specialist_setup.page_title') }), !isDone && /*#__PURE__*/ _jsx("p", { className: "text-sm text-white/50 mt-0.5", children: t('specialist_setup.step_of').replace('{current}', String(step)).replace('{total}', String(TOTAL_STEPS)) }) ] }), !isDone && /*#__PURE__*/ _jsx(StepIndicator, { current: step, total: TOTAL_STEPS }), /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-2xl border border-gray-200 p-6 shadow-sm", children: [ isDone && /*#__PURE__*/ _jsx(StepDone, { t: t }), step === 1 && /*#__PURE__*/ _jsx(Step1Welcome, { t: t, onNext: ()=>setStep(2) }), step === 2 && /*#__PURE__*/ _jsx(Step2Profile, { t: t, onNext: ()=>setStep(3), onBack: ()=>setStep(1) }), step === 3 && /*#__PURE__*/ _jsx(Step3Card, { t: t, onNext: ()=>setStep(4), onBack: ()=>setStep(2), onCardCreated: setCard }), step === 4 && /*#__PURE__*/ _jsx(Step4Skills, { t: t, onNext: ()=>setStep(5), onBack: ()=>setStep(3), card: card, catLocale: catLocale }), step === 5 && /*#__PURE__*/ _jsx(Step5Geography, { t: t, onNext: ()=>setStep(6), onBack: ()=>setStep(4), card: card, catLocale: catLocale }) ] }), step >= 2 && step <= TOTAL_STEPS && /*#__PURE__*/ _jsx("div", { className: "text-center mt-4", children: /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setStep(step + 1), className: "text-sm text-white/50 hover:text-white/80 transition", children: t('specialist_setup.skip') }) }) ] }) }); } @b={}_46VAD!$cgg k z _} 1 4 SV03GNlq_7ABF58S V 0!4!!!""##`%_c%,&/&''( (q*t*++o-s---..0091<1 2#233O5V5y55555_5667768988899 : :::I=L=>>>>f?i?nAqABBCCGCNCC_CCCCDEDMD]DmDDDDEHHnIrIIIaJdJKKKK|LL MMN"NP_PPPSS~UUVVXXJYMY6Z9Z \\z\~\X][]O_S_I`L`^babccddf_f%i(ijjjjkkOkWkgkvkmmnnnnooGpJppprrssssu_uvvxxxxzz||~ ~l~o~Ɂ́{~EI߃!_x|ڊ3<T\{͋ԋbjMPRrv-0ilWZvy>A(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em"https://api.canhelp.gr"00_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .createSpecialistCard */ .eR_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getCategories */ .bW_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSkillSuggestions */ .rl_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zc_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getLocations */ .Vs(0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y) ٿ__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SpecialistSetupPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); /* __next_internal_client_entry_do_not_use__ default auto */ const TOTAL_STEPS = 5; // ─── Step indicator ──────────────────────────────────────────────────────── function StepIndicator({ current, total }) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex items-center justify-center gap-2 mb-8", children: Array.from({ length: total }, (_, i)=>i + 1).map((n)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: `w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold transition-colors ${n < current ? 'bg-green-500 text-white' : n === current ? 'bg-blue-600 text-white ring-4 ring-blue-200' : 'bg-gray-200 text-gray-400'}`, children: n < current ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M2 7l4 4 6-6", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) : n }), n < total && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: `w-8 h-0.5 ${n < current ? 'bg-green-500' : 'bg-gray-200'}` }) ] }, n)) }); } // ─── Step 1: Welcome ─────────────────────────────────────────────────────── function Step1Welcome({ t, onNext }) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "#2563eb", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("circle", { cx: "12", cy: "7", r: "4" }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "text-2xl font-bold text-gray-900 mb-2", children: t('specialist_setup.step1.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-blue-600 font-medium mb-4", children: t('specialist_setup.step1.subtitle') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-gray-500 text-sm leading-relaxed mb-8 max-w-sm mx-auto", children: t('specialist_setup.step1.desc') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-gray-50 rounded-xl p-5 text-left mb-8 max-w-sm mx-auto", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-semibold text-gray-700 mb-3", children: t('specialist_setup.step1.what_next') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("ul", { className: "space-y-2", children: [ t('specialist_setup.step1.item1'), t('specialist_setup.step1.item2'), t('specialist_setup.step1.item3'), t('specialist_setup.step1.item4'), t('specialist_setup.step1.item5') ].map((item, i)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("li", { className: "flex items-center gap-2 text-sm text-gray-600", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-5 h-5 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center text-xs font-bold shrink-0", children: i + 1 }), item ] }, i)) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { onClick: onNext, className: "w-full max-w-xs bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 transition", children: [ t('specialist_setup.next'), " →" ] }) ] }); } // ─── Step 2: Basic profile ───────────────────────────────────────────────── function Step2Profile({ t, onNext, onBack }) { const [bio, setBio] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [phone, setPhone] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [saving, setSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [avatarUrl, setAvatarUrl] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const [uploading, setUploading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const fileRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', {}).then((u)=>{ setBio(u.bio ?? ''); setPhone(u.phone ?? ''); setAvatarUrl(u.image ?? null); }).catch(()=>{}); }, []); async function handleAvatarChange(e) { const file = e.target.files?.[0]; if (!file) return; setUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${"https://api.canhelp.gr" || 0}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); const fullUrl = `${"https://api.canhelp.gr" || 0}${url}`; await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ image: fullUrl }) }); setAvatarUrl(fullUrl); } catch {} finally{ setUploading(false); if (fileRef.current) fileRef.current.value = ''; } } async function handleSave() { setSaving(true); try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Em('/users/me', { method: 'PATCH', body: JSON.stringify({ bio: bio || undefined, phone: phone || undefined }) }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step2.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step2.subtitle') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-5", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step2.photo_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-16 h-16 rounded-full bg-gray-100 border-2 border-gray-200 overflow-hidden shrink-0 flex items-center justify-center", children: avatarUrl ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: avatarUrl, alt: "", className: "w-full h-full object-cover" }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "#9ca3af", strokeWidth: "2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("circle", { cx: "12", cy: "7", r: "4" }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>fileRef.current?.click(), disabled: uploading, className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium text-gray-700 disabled:opacity-50 transition", children: uploading ? t('specialist_setup.step2.photo_uploading') : t('specialist_setup.step2.photo_btn') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mt-1", children: t('specialist_setup.step2.photo_hint') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp", className: "hidden", onChange: handleAvatarChange }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step2.bio_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { value: bio, onChange: (e)=>setBio(e.target.value), rows: 4, maxLength: 1000, placeholder: t('specialist_setup.step2.bio_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step2.phone_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "tel", value: phone, onChange: (e)=>setPhone(e.target.value), placeholder: t('specialist_setup.step2.phone_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 3: Service card ────────────────────────────────────────────────── function Step3Card({ t, onNext, onBack, onCardCreated }) { const [title, setTitle] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [desc, setDesc] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [saving, setSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [error, setError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); async function handleSave() { if (!title.trim()) { setError(t('specialist_setup.step3.title_required')); return; } setError(''); setSaving(true); try { const card = await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .createSpecialistCard */ .eR({ title: title.trim(), description: desc || undefined }); onCardCreated(card); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step3.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step3.subtitle') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step3.title_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: title, onChange: (e)=>{ setTitle(e.target.value); if (error) setError(''); }, maxLength: 200, placeholder: t('specialist_setup.step3.title_placeholder'), className: `w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 ${error ? 'border-red-400' : 'border-gray-300'}` }), error && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-red-500 text-xs mt-1", children: error }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('specialist_setup.step3.desc_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { value: desc, onChange: (e)=>setDesc(e.target.value), rows: 5, maxLength: 1000, placeholder: t('specialist_setup.step3.desc_placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 4: Skills & Categories ────────────────────────────────────────── function Step4Skills({ t, onNext, onBack, card, catLocale }) { const [skills, setSkills] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card?.skills ?? []); const [skillInput, setSkillInput] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [categories, setCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card?.categories ?? []); const [allCategories, setAllCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [suggestions, setSuggestions] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [saving, setSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getCategories */ .bW().then(setAllCategories).catch(()=>{}); }, []); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSkillSuggestions */ .rl(categories.length > 0 ? categories : undefined).then(setSuggestions).catch(()=>{}); }, [ categories ]); function addSkill(s) { const trimmed = s.trim(); if (trimmed && !skills.includes(trimmed)) setSkills([ ...skills, trimmed ]); setSkillInput(''); } function toggleCategory(slug, childSlugs = []) { if (categories.includes(slug)) { setCategories(categories.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setCategories([ ...new Set([ ...categories, slug, ...childSlugs ]) ]); } } async function handleSave() { if (!card) { onNext(); return; } setSaving(true); try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zc(card.id, { skills, categories }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step4.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-gray-500 text-sm mb-6", children: t('specialist_setup.step4.subtitle') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step4.skills_label') }), skills.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex flex-wrap gap-2 mb-2", children: skills.map((s)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "flex items-center gap-1.5 bg-blue-50 text-blue-700 text-sm px-3 py-1 rounded-full", children: [ s, /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setSkills(skills.filter((x)=>x !== s)), className: "text-blue-400 hover:text-blue-700 leading-none text-base", children: "\xd7" }) ] }, s)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { value: skillInput, onChange: (e)=>setSkillInput(e.target.value), onKeyDown: (e)=>{ if (e.key === 'Enter') { e.preventDefault(); addSkill(skillInput); } }, placeholder: t('specialist_setup.step4.skills_placeholder'), className: "flex-1 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>addSkill(skillInput), className: "px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium", children: t('specialist_setup.step4.skills_add') }) ] }), suggestions.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex flex-wrap gap-1.5 mt-2", children: suggestions.map((s)=>s.names[catLocale] ?? s.names.el).filter((name, i, arr)=>arr.indexOf(name) === i && !skills.includes(name)).slice(0, 12).map((name)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>addSkill(name), className: "text-xs px-2.5 py-1 border border-gray-200 rounded-full text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: [ "+ ", name ] }, name)) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "mb-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('specialist_setup.step4.categories_label') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-2 max-h-64 overflow-y-auto border border-gray-200 rounded-xl p-3", children: allCategories.map((cat)=>{ const catName = cat.names?.[catLocale] ?? cat.names?.el ?? cat.slug; const children = cat.children ?? []; const childSlugs = children.map((c)=>c.slug); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: categories.includes(cat.slug), onChange: ()=>toggleCategory(cat.slug, childSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-sm font-medium text-gray-800", children: [ cat.icon && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "mr-1", children: cat.icon }), catName ] }) ] }), children.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "ml-6 mt-1.5 space-y-1.5", children: children.map((sub)=>{ const subName = sub.names?.[catLocale] ?? sub.names?.el ?? sub.slug; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: categories.includes(sub.slug), onChange: ()=>toggleCategory(sub.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm text-gray-600", children: subName }) ] }, sub.id); }) }) ] }, cat.id); }) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving }) ] }); } // ─── Step 5: Geography ───────────────────────────────────────────────────── function Step5Geography({ t, onNext, onBack, card, catLocale }) { const [locations, setLocations] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(card?.locations ?? []); const [locationTree, setLocationTree] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [saving, setSaving] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getLocations */ .Vs().then(setLocationTree).catch(()=>{}); }, []); function toggleLocation(slug, childSlugs = []) { if (locations.includes(slug)) { setLocations(locations.filter((c)=>c !== slug && !childSlugs.includes(c))); } else { setLocations([ ...new Set([ ...locations, slug, ...childSlugs ]) ]); } } async function handleSave() { if (!card) { onNext(); return; } setSaving(true); try { await _lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zc(card.id, { locations }); onNext(); } catch {} finally{ setSaving(false); } } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "text-xl font-bold text-gray-900 mb-1", children: t('specialist_setup.step5.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-gray-500 text-sm mb-2", children: t('specialist_setup.step5.subtitle') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 mb-5", children: t('specialist_setup.step5.hint') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-3 max-h-72 overflow-y-auto border border-gray-200 rounded-xl p-3 mb-6", children: locationTree.map((city)=>{ const cityName = city.names?.[catLocale] ?? city.names?.el ?? city.slug; const districts = city.children ?? []; const districtSlugs = districts.map((d)=>d.slug); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: locations.includes(city.slug), onChange: ()=>toggleLocation(city.slug, districtSlugs), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm font-medium text-gray-800", children: cityName }) ] }), districts.length > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "ml-6 mt-1.5 space-y-1.5", children: districts.map((d)=>{ const dName = d.names?.[catLocale] ?? d.names?.el ?? d.slug; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-2.5 cursor-pointer", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", checked: locations.includes(d.slug), onChange: ()=>toggleLocation(d.slug), className: "w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm text-gray-600", children: dName }) ] }, d.id); }) }) ] }, city.id); }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(NavButtons, { t: t, onBack: onBack, onNext: handleSave, loading: saving, isLast: true }) ] }); } // ─── Done screen ─────────────────────────────────────────────────────────── function StepDone({ t }) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-center py-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-6", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "#16a34a", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M20 6L9 17l-5-5" }) }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "text-2xl font-bold text-gray-900 mb-2", children: t('specialist_setup.done.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-green-600 font-medium mb-4", children: t('specialist_setup.done.subtitle') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-gray-500 text-sm leading-relaxed mb-8 max-w-sm mx-auto", children: t('specialist_setup.done.desc') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-col sm:flex-row gap-3 justify-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("a", { href: "/profile", className: "px-6 py-3 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 transition text-center", children: t('specialist_setup.go_to_profile') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("a", { href: "/tasks", className: "px-6 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition text-center", children: t('specialist_setup.browse_tasks') }) ] }) ] }); } // ─── Navigation buttons ──────────────────────────────────────────────────── function NavButtons({ t, onBack, onNext, loading, isLast }) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex gap-3 pt-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: onBack, className: "flex-1 px-4 py-3 bg-gray-100 text-gray-700 rounded-xl font-semibold hover:bg-gray-200 transition", children: [ "← ", t('specialist_setup.back') ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: onNext, disabled: loading, className: "flex-[2] px-4 py-3 bg-blue-600 text-white rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 transition", children: loading ? '...' : isLast ? t('specialist_setup.finish') : `${t('specialist_setup.next')} →` }) ] }); } // ─── Main page ───────────────────────────────────────────────────────────── function SpecialistSetupPage() { const { data: session, isPending } = (0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)(); const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const { t, locale } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)(); const [step, setStep] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(1); const [card, setCard] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(null); const catLocale = locale === 'ru' ? 'ru' : locale === 'en' ? 'en' : 'el'; process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!isPending && !session) router.push('/login'); if (!isPending && session && session.user?.role !== 'specialist') router.push('/become-specialist'); }, [ session, isPending ]); if (isPending || !session) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-20 text-white", children: t('common.loading') }); } const isDone = step > TOTAL_STEPS; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "min-h-screen py-10 px-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "max-w-lg mx-auto", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-center mb-6", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-lg font-semibold text-white/90", children: t('specialist_setup.page_title') }), !isDone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-white/50 mt-0.5", children: t('specialist_setup.step_of').replace('{current}', String(step)).replace('{total}', String(TOTAL_STEPS)) }) ] }), !isDone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(StepIndicator, { current: step, total: TOTAL_STEPS }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-2xl border border-gray-200 p-6 shadow-sm", children: [ isDone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(StepDone, { t: t }), step === 1 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Step1Welcome, { t: t, onNext: ()=>setStep(2) }), step === 2 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Step2Profile, { t: t, onNext: ()=>setStep(3), onBack: ()=>setStep(1) }), step === 3 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Step3Card, { t: t, onNext: ()=>setStep(4), onBack: ()=>setStep(2), onCardCreated: setCard }), step === 4 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Step4Skills, { t: t, onNext: ()=>setStep(5), onBack: ()=>setStep(3), card: card, catLocale: catLocale }), step === 5 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Step5Geography, { t: t, onNext: ()=>setStep(6), onBack: ()=>setStep(4), card: card, catLocale: catLocale }) ] }), step >= 2 && step <= TOTAL_STEPS && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center mt-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setStep(step + 1), className: "text-sm text-white/50 hover:text-white/80 transition", children: t('specialist_setup.skip') }) }) ] }) }); }    J__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SpecialistSetupPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(96484); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91864); -61123undefined125176undefined178221undefined223262undefined264308undefined310342undefined516519(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined702706(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined833836(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined11741177(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined14151418(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined18251828(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined21472151(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined22422245(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined24072411(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined28012804(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined29572960(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined31943197(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33773380(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined35553558(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined37583762(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined39233926(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined41444147(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined46104614(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined48104813(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined52755279(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined57605767(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined58045811(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined58505857(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined59055912(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined59595966(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined59966001(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined60656073(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined60896099_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined65546584"https://api.canhelp.gr"undefined658966110undefined68816911"https://api.canhelp.gr"undefined691669380undefined69676977_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined74017411_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .request */ .Emundefined77467750(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined78077810(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined79897992(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined81638167(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined82758278(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined84968500(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined86518654(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined88978900(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined91359139(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined95689571(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined97729775(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1013710141(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1024610249(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1086510868(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1119411197(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1163111635(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1174311746(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1197211975(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1248912493(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1260112604(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1283212835(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1330313306(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1364713654(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1368913696(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1373513742(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1378213789(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1404714070_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .createSpecialistCard */ .eRundefined1432914333(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1439014393(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1457214575(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1474614750(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1485814861(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1508915092(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1568915692(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1588815892(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1600016003(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1623016233(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1675016753(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1709917106(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1716917176(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1722317230(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1730317310(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1735917366(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1740517412(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined1747717485(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined1750117517_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getCategories */ .bWundefined1762617634(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined1765017672_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getSkillSuggestions */ .rlundefined1857318596_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zcundefined1879818802(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1885918862(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1904119044(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1921519219(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1932719330(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1958019583(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1972219726(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1999920002(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2049920503(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2064120644(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2141521418(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2188621889(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2216822172(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2274622750(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2285822861(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2309423097(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2356523569(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2367423678(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2389623899(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2439924403(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2464924652(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2518225185(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2552425528(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2577025773(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2630926312(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2691726920(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2727627283(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined2735327360(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined2739927406(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined2747127479(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined2749527510_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .getLocations */ .Vsundefined2812628149_lib_api__WEBPACK_IMPORTED_MODULE_5__/* .updateSpecialistCard */ .zcundefined2832628330(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2838728390(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2856928572(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2874328746(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2891328916(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2935129355(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2944429448(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2964229645(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3010130104(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3043430437(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3073530739(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3095730960(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3144331446(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3192731930(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3226432268(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3236432367(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3253032533(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3289932902(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3304333046(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3322533228(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3340333406(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3360533609(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3375933762(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3407834081(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3458134585(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3468034684(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3505135054(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3554635560undefined3563535644(0,_lib_auth__WEBPACK_IMPORTED_MODULE_3__/* .useSession */ .wV)undefined3566835676(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined3570735715(0,_context_locale__WEBPACK_IMPORTED_MODULE_4__/* .useLocale */ .Y)undefined3574835755(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined3578935796(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined3593835946(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined3623636239(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3642936432(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3652136525(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3663336637(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3676936772(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3700837011(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3734437347(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3749037494(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3767737680(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3780737810(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3799337996(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3823138234(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3851838521(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3884538848(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3923039233(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3933939342(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined   webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CreateTaskPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(96484); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(56003); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(91864); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(48178); /* harmony import */ var _lib_formatLastSeen__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(49598); /* harmony import */ var _components_TaskLocationPicker__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(53863); /* harmony import */ var _components_TaskCategoryPicker__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(88142); /* harmony import */ var _components_Turnstile__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(32589); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource/* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState, useEffect, useRef } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { useSession } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { useLocation } from '@/context/location'; import { createTask, getCategories, getLocations, getSpecialists } from '@/lib/api'; import { formatShortName } from '@/lib/formatName'; import { formatLastSeen } from '@/lib/formatLastSeen'; import { TaskLocationPicker } from '@/components/TaskLocationPicker'; import { TaskCategoryPicker } from '@/components/TaskCategoryPicker'; import { TurnstileWidget } from '@/components/Turnstile'; import { CAPTCHA_ENABLED } from '@/components/Turnstile'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const localISO = (d)=>{ const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; }; export default function CreateTaskPage() { const { data: session, isPending } = useSession(); const router = useRouter(); const searchParams = useSearchParams(); const preselectedCategory = searchParams.get('category') ?? ''; const { t, locale } = useLocale(); const [categories, setCategories] = useState([]); const [locations, setLocations] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [topSpecialists, setTopSpecialists] = useState([]); const [deadline, setDeadline] = useState(()=>{ const d = new Date(); d.setDate(d.getDate() + 1); return localISO(d); }); const [calendarMonth, setCalendarMonth] = useState(()=>{ const d = new Date(); d.setDate(d.getDate() + 1); return localISO(d).slice(0, 7); }); const calendarInputRef = useRef(null); const [specialistAvailMap, setSpecialistAvailMap] = useState({}); const [invitedIds, setInvitedIds] = useState(new Set()); const [captchaToken, setCaptchaToken] = useState(CAPTCHA_ENABLED ? '' : 'dev'); const { locationSlug: ctxLocation } = useLocation(); const [selectedLocation, setSelectedLocation] = useState(''); const [selectedCategory, setSelectedCategory] = useState(preselectedCategory); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (ctxLocation) setSelectedLocation(ctxLocation); }, [ ctxLocation ]); const [images, setImages] = useState([]); const [photoUploading, setPhotoUploading] = useState(false); const fileInputRef = useRef(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!isPending && !session) router.push('/login'); getCategories().then(setCategories).catch(()=>{}); getLocations().then(setLocations).catch(()=>{}); }, [ session, isPending ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!selectedCategory) { setTopSpecialists([]); return; } getSpecialists({ limit: '5', category: selectedCategory }).then((r)=>setTopSpecialists(r.data)).catch(()=>{}); }, [ selectedCategory ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!deadline || topSpecialists.length === 0) return; const month = deadline.slice(0, 7); const ids = topSpecialists.map((u)=>u.id); Promise.all(ids.map((id)=>fetch(`${API}/api/availability/user/${id}?month=${month}`, { credentials: 'include' }).then((r)=>r.ok ? r.json() : []).then((rows)=>{ const row = rows.find((r)=>r.date === deadline); return { id, status: row?.status ?? null }; }).catch(()=>({ id, status: null })))).then((results)=>{ const map = {}; results.forEach(({ id, status })=>{ map[id] = status; }); setSpecialistAvailMap(map); }); }, [ deadline, topSpecialists ]); async function handlePhotoChange(e) { const file = e.target.files?.[0]; if (!file) return; setPhotoUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${API}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); setImages((prev)=>[ ...prev, `${API}${url}` ]); } catch { setError(t('profile.upload.error')); } finally{ setPhotoUploading(false); if (fileInputRef.current) fileInputRef.current.value = ''; } } async function handleSubmit(e) { e.preventDefault(); setError(''); setLoading(true); const form = new FormData(e.currentTarget); const data = { title: form.get('title'), description: form.get('description'), category: form.get('category') || undefined, location: form.get('location') || undefined, budget: form.get('budget') ? Number(form.get('budget')) : undefined, budgetNegotiable: form.get('budgetNegotiable') === 'on', deadline: form.get('deadline') ? new Date(form.get('deadline')).toISOString() : undefined, timeSlot: form.get('timeSlot') || undefined, district: form.get('district') || undefined, street: form.get('street') || undefined, houseNumber: form.get('houseNumber') || undefined, confidentialNote: form.get('confidentialNote') || undefined, images: images.length > 0 ? images : undefined, status: 'open', locale: locale, inviteSpecialistIds: invitedIds.size > 0 ? [ ...invitedIds ] : undefined }; try { const task = await createTask({ ...data, captchaToken }); router.push(`/tasks/${task.id}`); } catch (err) { setError(err.message || t('create.error')); } finally{ setLoading(false); } } if (isPending) return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white", children: t('common.loading') }); const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const dateLocale = locale === 'ru' ? 'ru-RU' : locale === 'en' ? 'en-US' : 'el-GR'; const todayMidnight = new Date(); todayMidnight.setHours(0, 0, 0, 0); const [cmYear, cmMonth] = calendarMonth.split('-').map(Number); const daysInMonth = new Date(cmYear, cmMonth, 0).getDate(); const calendarDates = []; for(let day = 1; day <= daysInMonth; day++){ const d = new Date(cmYear, cmMonth - 1, day); if (d >= todayMidnight) calendarDates.push(d); } const monthOptions = Array.from({ length: 12 }, (_, i)=>{ const d = new Date(); d.setDate(1); d.setMonth(d.getMonth() + i); return { value: localISO(d).slice(0, 7), label: d.toLocaleDateString(dateLocale, { month: 'long', year: 'numeric' }) }; }); const sidebarTitle = t('tasks.new.top_specialists'); return /*#__PURE__*/ _jsxs("div", { className: "max-w-5xl mx-auto px-3 sm:px-4 py-6 sm:py-8", children: [ /*#__PURE__*/ _jsx("h1", { className: "text-xl sm:text-2xl font-bold text-white mb-4 sm:mb-6", children: t('create.title') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col lg:flex-row gap-6 lg:gap-8 items-start", children: [ /*#__PURE__*/ _jsx("div", { className: "flex-1 min-w-0 w-full", children: /*#__PURE__*/ _jsxs("form", { onSubmit: handleSubmit, className: "bg-white rounded-xl border border-gray-200 p-4 sm:p-6 space-y-4 sm:space-y-5", children: [ error && /*#__PURE__*/ _jsx("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4", children: [ /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.category') }), /*#__PURE__*/ _jsx(TaskCategoryPicker, { categories: categories, locale: catLocale, value: selectedCategory, onChange: setSelectedCategory, placeholder: t('create.field.category.select') }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.location') }), /*#__PURE__*/ _jsx(TaskLocationPicker, { locations: locations, value: selectedLocation, onChange: setSelectedLocation, anyLabel: t('create.field.location.any'), allLabel: t('create.field.location.all') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.title'), " ", /*#__PURE__*/ _jsx("span", { className: "text-red-500", children: "*" }) ] }), /*#__PURE__*/ _jsx("input", { name: "title", required: true, minLength: 5, maxLength: 200, placeholder: t('create.field.title.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.description'), " ", /*#__PURE__*/ _jsx("span", { className: "text-red-500", children: "*" }) ] }), /*#__PURE__*/ _jsx("textarea", { name: "description", required: true, minLength: 20, rows: 4, placeholder: t('create.field.description.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.budget') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-3", children: [ /*#__PURE__*/ _jsx("input", { name: "budget", type: "number", min: 1, step: 1, placeholder: t('create.field.budget.placeholder'), className: "w-full sm:flex-1 border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer select-none", children: [ /*#__PURE__*/ _jsx("input", { type: "checkbox", name: "budgetNegotiable", className: "w-4 h-4 rounded border-gray-300 text-blue-600" }), /*#__PURE__*/ _jsx("span", { className: "text-sm text-gray-700", children: t('create.field.budget_negotiable') }) ] }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-2", children: [ /*#__PURE__*/ _jsx("label", { className: "text-sm font-medium text-gray-700 shrink-0", children: t('create.field.deadline') }), /*#__PURE__*/ _jsx("select", { value: calendarMonth, onChange: (e)=>setCalendarMonth(e.target.value), className: "flex-1 border border-gray-300 rounded-lg px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400", children: monthOptions.map((mo)=>/*#__PURE__*/ _jsx("option", { value: mo.value, children: mo.label }, mo.value)) }), /*#__PURE__*/ _jsx("button", { type: "button", title: "Открыть календарь", onClick: ()=>{ try { calendarInputRef.current?.showPicker(); } catch { calendarInputRef.current?.click(); } }, className: "shrink-0 w-8 h-8 flex items-center justify-center rounded-lg border border-gray-300 text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: /*#__PURE__*/ _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [ /*#__PURE__*/ _jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), /*#__PURE__*/ _jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), /*#__PURE__*/ _jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), /*#__PURE__*/ _jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" }) ] }) }), /*#__PURE__*/ _jsx("input", { ref: calendarInputRef, type: "date", min: localISO(todayMidnight), value: deadline, onChange: (e)=>{ if (!e.target.value) return; setDeadline(e.target.value); setCalendarMonth(e.target.value.slice(0, 7)); }, className: "absolute w-0 h-0 opacity-0 pointer-events-none" }) ] }), /*#__PURE__*/ _jsx("div", { className: "flex gap-2 overflow-x-auto pb-1 snap-x snap-mandatory", children: calendarDates.map((d)=>{ const iso = localISO(d); const isSelected = deadline === iso; const dayName = d.toLocaleDateString(dateLocale, { weekday: 'short' }); const dayNum = d.getDate(); return /*#__PURE__*/ _jsxs("button", { type: "button", onClick: ()=>setDeadline(iso), className: `flex-shrink-0 snap-start flex flex-col items-center justify-center w-14 h-16 rounded-xl border-2 transition select-none ${isSelected ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-200 bg-white text-gray-700 hover:border-blue-300 hover:bg-gray-50'}`, children: [ /*#__PURE__*/ _jsx("span", { className: "text-xs font-medium uppercase leading-none mb-0.5", children: dayName }), /*#__PURE__*/ _jsx("span", { className: "text-xl font-bold leading-none", children: dayNum }) ] }, iso); }) }), /*#__PURE__*/ _jsx("input", { type: "hidden", name: "deadline", value: deadline }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.time_slot') }), /*#__PURE__*/ _jsxs("select", { name: "timeSlot", className: "w-full border border-gray-300 rounded-lg px-3 py-2", children: [ /*#__PURE__*/ _jsx("option", { value: "", children: t('create.field.time_slot.any') }), /*#__PURE__*/ _jsx("option", { value: "morning", children: t('create.field.time_slot.morning') }), /*#__PURE__*/ _jsx("option", { value: "afternoon", children: t('create.field.time_slot.afternoon') }), /*#__PURE__*/ _jsx("option", { value: "evening", children: t('create.field.time_slot.evening') }), /*#__PURE__*/ _jsx("option", { value: "weekend", children: t('create.field.time_slot.weekend') }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('create.field.address') }), /*#__PURE__*/ _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-2 sm:gap-3", children: [ /*#__PURE__*/ _jsx("input", { name: "district", placeholder: t('create.field.address.district'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("input", { name: "street", placeholder: t('create.field.address.street'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ _jsx("input", { name: "houseNumber", placeholder: t('create.field.address.house'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('create.field.photos') }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-wrap gap-2 mb-2", children: [ images.map((url, i)=>/*#__PURE__*/ _jsxs("div", { className: "relative w-20 h-20 rounded-lg overflow-hidden border border-gray-200", children: [ /*#__PURE__*/ _jsx("img", { src: url, alt: "", className: "w-full h-full object-cover" }), /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setImages((prev)=>prev.filter((_, j)=>j !== i)), className: "absolute top-0.5 right-0.5 bg-black/50 text-white rounded-full w-5 h-5 flex items-center justify-center text-xs hover:bg-black/70", children: "\xd7" }) ] }, i)), images.length < 5 && /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>fileInputRef.current?.click(), disabled: photoUploading, className: "w-20 h-20 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400 hover:border-blue-400 hover:text-blue-400 text-xs disabled:opacity-50", children: photoUploading ? '...' : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("span", { className: "text-2xl leading-none", children: "+" }), /*#__PURE__*/ _jsx("span", { children: t('create.field.photos.add') }) ] }) }) ] }), /*#__PURE__*/ _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", className: "hidden", onChange: handlePhotoChange }) ] }), /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsxs("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.confidential'), /*#__PURE__*/ _jsxs("span", { className: "ml-2 text-xs font-normal text-gray-400", children: [ "\uD83D\uDD12 ", t('create.field.confidential.hint') ] }) ] }), /*#__PURE__*/ _jsx("textarea", { name: "confidentialNote", rows: 2, placeholder: t('create.field.confidential.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ _jsx(TurnstileWidget, { onSuccess: setCaptchaToken, onError: ()=>setCaptchaToken(''), onExpire: ()=>setCaptchaToken('') }), /*#__PURE__*/ _jsx("button", { type: "submit", disabled: loading || !captchaToken, className: "w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed", children: loading ? t('create.submitting') : t('create.submit') }) ] }) }), /*#__PURE__*/ _jsx("aside", { className: "hidden lg:block lg:w-64 shrink-0", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-5 sticky top-24", children: [ /*#__PURE__*/ _jsx("h3", { className: "font-semibold text-gray-900 mb-4 text-sm", children: sidebarTitle }), !selectedCategory ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 text-center py-4", children: t('tasks.new.select_category') }) : topSpecialists.length === 0 ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400 text-center py-4", children: t('specialists.empty') }) : /*#__PURE__*/ _jsx("div", { className: "space-y-3", children: topSpecialists.map((u)=>{ const name = formatShortName(u.firstName, u.lastName, u.name); const initials = `${u.firstName?.[0] ?? ''}${u.lastName?.[0] ?? ''}`.toUpperCase() || u.name?.[0]?.toUpperCase() || '?'; const seen = formatLastSeen(u.lastSeenAt, t); const avail = specialistAvailMap[u.id]; const isInvited = invitedIds.has(u.id); return /*#__PURE__*/ _jsxs("div", { className: "rounded-lg border border-gray-100 hover:bg-gray-50 transition", children: [ /*#__PURE__*/ _jsxs(Link, { href: `/users/${u.id}`, target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-3 p-2", children: [ /*#__PURE__*/ _jsx("div", { className: "w-12 h-12 rounded-full bg-blue-100 flex-shrink-0 flex items-center justify-center text-blue-700 font-bold text-sm overflow-hidden border border-gray-100", children: u.image ? /*#__PURE__*/ _jsx("img", { src: u.image, alt: name, className: "w-full h-full object-cover" }) : initials }), /*#__PURE__*/ _jsxs("div", { className: "min-w-0 flex-1", children: [ /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: name }), /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-1.5 flex-wrap", children: [ u.rating ? /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-500", children: [ "★ ", Number(u.rating).toFixed(1) ] }) : seen ? /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-400", children: seen }) : null, typeof u.reviewCount === 'number' && u.reviewCount > 0 && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-400", children: [ u.reviewCount, " ", t('reviews.count') ] }), typeof u.positivePercent === 'number' && u.reviewCount > 0 && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-green-600", children: [ u.positivePercent, "% \uD83D\uDC4D" ] }), avail === 'available' && /*#__PURE__*/ _jsxs("span", { className: "inline-flex items-center gap-0.5 text-xs font-medium text-green-700 bg-green-100 px-1.5 py-0.5 rounded-full", children: [ /*#__PURE__*/ _jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-green-500 inline-block" }), t('schedule.available') ] }), avail === 'busy' && /*#__PURE__*/ _jsxs("span", { className: "inline-flex items-center gap-0.5 text-xs font-medium text-red-700 bg-red-100 px-1.5 py-0.5 rounded-full", children: [ /*#__PURE__*/ _jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-red-500 inline-block" }), t('schedule.busy') ] }) ] }) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "px-2 pb-2", children: /*#__PURE__*/ _jsx("button", { type: "button", onClick: ()=>setInvitedIds((prev)=>{ const next = new Set(prev); if (next.has(u.id)) next.delete(u.id); else next.add(u.id); return next; }), className: `w-full text-xs font-medium py-1 rounded-lg transition ${isInvited ? 'bg-blue-600 text-white hover:bg-blue-700' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`, children: isInvited ? t('tasks.new.invited') : t('tasks.new.invite') }) }) ] }, u.id); }) }) ] }) }) ] }) ] }); } @`=_#%LNz|57ln24lz~_'#*RYelIP_  U \ } * 2 } T \ js_N R h!l!""v#z#L$P$$$&& &1&(())^*a*c*t*"-&--_-//f0i033y3}344N6Q699v9y9::;;2>6>@?C?@@;C?CCCD_DEEGGIILLEOHOQQXS[SUUkWnW^[a[6^:^``b bd dpetee_eggChFhcifijjkkllnnooCpGp1q4qs sttAwEwwwxxy_yzz||߃ȅ˅15osƋɋ#FI}_ВӒٓܓܔߔWZ#R'jm$(>BmpЯԯX["https://api.canhelp.gr"0(0,_lib_auth__WEBPACK_IMPORTED_MODULE_4__/* .useSession */ .wV)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)(0,_context_locale__WEBPACK_IMPORTED_MODULE_5__/* .useLocale */ .Y)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)_components_Turnstile__WEBPACK_IMPORTED_MODULE_10__/* .CAPTCHA_ENABLED */ .l(0,_context_location__WEBPACK_IMPORTED_MODULE_6__/* .useLocation */ .z)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .bW)(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getLocations */ .Vs)(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getSpecialists */ .F7)(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createTask */ .UT)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)_components_TaskCategoryPicker__WEBPACK_IMPORTED_MODULE_9__/* .TaskCategoryPicker */ .W_components_TaskLocationPicker__WEBPACK_IMPORTED_MODULE_8__/* .TaskLocationPicker */ .Vreact_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment_components_Turnstile__WEBPACK_IMPORTED_MODULE_10__/* .TurnstileWidget */ .$(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_11__/* .formatShortName */ .H)(0,_lib_formatLastSeen__WEBPACK_IMPORTED_MODULE_12__/* .formatLastSeen */ .V)(next_link__WEBPACK_IMPORTED_MODULE_3___default()) __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CreateTaskPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(96484); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(56003); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(91864); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(48178); /* harmony import */ var _lib_formatLastSeen__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(49598); /* harmony import */ var _components_TaskLocationPicker__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(53863); /* harmony import */ var _components_TaskCategoryPicker__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(88142); /* harmony import */ var _components_Turnstile__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(32589); /* __next_internal_client_entry_do_not_use__ default auto */ const API = "https://api.canhelp.gr" || 0; const localISO = (d)=>{ const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; }; function CreateTaskPage() { const { data: session, isPending } = (0,_lib_auth__WEBPACK_IMPORTED_MODULE_4__/* .useSession */ .wV)(); const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const searchParams = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)(); const preselectedCategory = searchParams.get('category') ?? ''; const { t, locale } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_5__/* .useLocale */ .Y)(); const [categories, setCategories] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [locations, setLocations] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const [error, setError] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [topSpecialists, setTopSpecialists] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [deadline, setDeadline] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(()=>{ const d = new Date(); d.setDate(d.getDate() + 1); return localISO(d); }); const [calendarMonth, setCalendarMonth] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(()=>{ const d = new Date(); d.setDate(d.getDate() + 1); return localISO(d).slice(0, 7); }); const calendarInputRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); const [specialistAvailMap, setSpecialistAvailMap] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({}); const [invitedIds, setInvitedIds] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(new Set()); const [captchaToken, setCaptchaToken] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(_components_Turnstile__WEBPACK_IMPORTED_MODULE_10__/* .CAPTCHA_ENABLED */ .l ? '' : 'dev'); const { locationSlug: ctxLocation } = (0,_context_location__WEBPACK_IMPORTED_MODULE_6__/* .useLocation */ .z)(); const [selectedLocation, setSelectedLocation] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(''); const [selectedCategory, setSelectedCategory] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(preselectedCategory); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (ctxLocation) setSelectedLocation(ctxLocation); }, [ ctxLocation ]); const [images, setImages] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [photoUploading, setPhotoUploading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const fileInputRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!isPending && !session) router.push('/login'); (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .bW)().then(setCategories).catch(()=>{}); (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getLocations */ .Vs)().then(setLocations).catch(()=>{}); }, [ session, isPending ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!selectedCategory) { setTopSpecialists([]); return; } (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getSpecialists */ .F7)({ limit: '5', category: selectedCategory }).then((r)=>setTopSpecialists(r.data)).catch(()=>{}); }, [ selectedCategory ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ if (!deadline || topSpecialists.length === 0) return; const month = deadline.slice(0, 7); const ids = topSpecialists.map((u)=>u.id); Promise.all(ids.map((id)=>fetch(`${API}/api/availability/user/${id}?month=${month}`, { credentials: 'include' }).then((r)=>r.ok ? r.json() : []).then((rows)=>{ const row = rows.find((r)=>r.date === deadline); return { id, status: row?.status ?? null }; }).catch(()=>({ id, status: null })))).then((results)=>{ const map = {}; results.forEach(({ id, status })=>{ map[id] = status; }); setSpecialistAvailMap(map); }); }, [ deadline, topSpecialists ]); async function handlePhotoChange(e) { const file = e.target.files?.[0]; if (!file) return; setPhotoUploading(true); try { const form = new FormData(); form.append('file', file); const res = await fetch(`${API}/api/uploads`, { method: 'POST', credentials: 'include', body: form }); if (!res.ok) throw new Error('Upload failed'); const { url } = await res.json(); setImages((prev)=>[ ...prev, `${API}${url}` ]); } catch { setError(t('profile.upload.error')); } finally{ setPhotoUploading(false); if (fileInputRef.current) fileInputRef.current.value = ''; } } async function handleSubmit(e) { e.preventDefault(); setError(''); setLoading(true); const form = new FormData(e.currentTarget); const data = { title: form.get('title'), description: form.get('description'), category: form.get('category') || undefined, location: form.get('location') || undefined, budget: form.get('budget') ? Number(form.get('budget')) : undefined, budgetNegotiable: form.get('budgetNegotiable') === 'on', deadline: form.get('deadline') ? new Date(form.get('deadline')).toISOString() : undefined, timeSlot: form.get('timeSlot') || undefined, district: form.get('district') || undefined, street: form.get('street') || undefined, houseNumber: form.get('houseNumber') || undefined, confidentialNote: form.get('confidentialNote') || undefined, images: images.length > 0 ? images : undefined, status: 'open', locale: locale, inviteSpecialistIds: invitedIds.size > 0 ? [ ...invitedIds ] : undefined }; try { const task = await (0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createTask */ .UT)({ ...data, captchaToken }); router.push(`/tasks/${task.id}`); } catch (err) { setError(err.message || t('create.error')); } finally{ setLoading(false); } } if (isPending) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-20 text-white", children: t('common.loading') }); const catLocale = locale === 'en' ? 'en' : locale === 'ru' ? 'ru' : 'el'; const dateLocale = locale === 'ru' ? 'ru-RU' : locale === 'en' ? 'en-US' : 'el-GR'; const todayMidnight = new Date(); todayMidnight.setHours(0, 0, 0, 0); const [cmYear, cmMonth] = calendarMonth.split('-').map(Number); const daysInMonth = new Date(cmYear, cmMonth, 0).getDate(); const calendarDates = []; for(let day = 1; day <= daysInMonth; day++){ const d = new Date(cmYear, cmMonth - 1, day); if (d >= todayMidnight) calendarDates.push(d); } const monthOptions = Array.from({ length: 12 }, (_, i)=>{ const d = new Date(); d.setDate(1); d.setMonth(d.getMonth() + i); return { value: localISO(d).slice(0, 7), label: d.toLocaleDateString(dateLocale, { month: 'long', year: 'numeric' }) }; }); const sidebarTitle = t('tasks.new.top_specialists'); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "max-w-5xl mx-auto px-3 sm:px-4 py-6 sm:py-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-xl sm:text-2xl font-bold text-white mb-4 sm:mb-6", children: t('create.title') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-col lg:flex-row gap-6 lg:gap-8 items-start", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex-1 min-w-0 w-full", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("form", { onSubmit: handleSubmit, className: "bg-white rounded-xl border border-gray-200 p-4 sm:p-6 space-y-4 sm:space-y-5", children: [ error && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "bg-red-50 text-red-700 p-3 rounded-lg text-sm", children: error }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.category') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_TaskCategoryPicker__WEBPACK_IMPORTED_MODULE_9__/* .TaskCategoryPicker */ .W, { categories: categories, locale: catLocale, value: selectedCategory, onChange: setSelectedCategory, placeholder: t('create.field.category.select') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.location') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_TaskLocationPicker__WEBPACK_IMPORTED_MODULE_8__/* .TaskLocationPicker */ .V, { locations: locations, value: selectedLocation, onChange: setSelectedLocation, anyLabel: t('create.field.location.any'), allLabel: t('create.field.location.all') }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.title'), " ", /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-red-500", children: "*" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { name: "title", required: true, minLength: 5, maxLength: 200, placeholder: t('create.field.title.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.description'), " ", /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-red-500", children: "*" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { name: "description", required: true, minLength: 20, rows: 4, placeholder: t('create.field.description.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.budget') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { name: "budget", type: "number", min: 1, step: 1, placeholder: t('create.field.budget.placeholder'), className: "w-full sm:flex-1 border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "flex items-center gap-1.5 cursor-pointer select-none", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "checkbox", name: "budgetNegotiable", className: "w-4 h-4 rounded border-gray-300 text-blue-600" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-sm text-gray-700", children: t('create.field.budget_negotiable') }) ] }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "text-sm font-medium text-gray-700 shrink-0", children: t('create.field.deadline') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("select", { value: calendarMonth, onChange: (e)=>setCalendarMonth(e.target.value), className: "flex-1 border border-gray-300 rounded-lg px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400", children: monthOptions.map((mo)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: mo.value, children: mo.label }, mo.value)) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", title: "Открыть календарь", onClick: ()=>{ try { calendarInputRef.current?.showPicker(); } catch { calendarInputRef.current?.click(); } }, className: "shrink-0 w-8 h-8 flex items-center justify-center rounded-lg border border-gray-300 text-gray-500 hover:border-blue-400 hover:text-blue-600 transition", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("line", { x1: "3", y1: "10", x2: "21", y2: "10" }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { ref: calendarInputRef, type: "date", min: localISO(todayMidnight), value: deadline, onChange: (e)=>{ if (!e.target.value) return; setDeadline(e.target.value); setCalendarMonth(e.target.value.slice(0, 7)); }, className: "absolute w-0 h-0 opacity-0 pointer-events-none" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex gap-2 overflow-x-auto pb-1 snap-x snap-mandatory", children: calendarDates.map((d)=>{ const iso = localISO(d); const isSelected = deadline === iso; const dayName = d.toLocaleDateString(dateLocale, { weekday: 'short' }); const dayNum = d.getDate(); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("button", { type: "button", onClick: ()=>setDeadline(iso), className: `flex-shrink-0 snap-start flex flex-col items-center justify-center w-14 h-16 rounded-xl border-2 transition select-none ${isSelected ? 'border-blue-500 bg-blue-50 text-blue-700' : 'border-gray-200 bg-white text-gray-700 hover:border-blue-300 hover:bg-gray-50'}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs font-medium uppercase leading-none mb-0.5", children: dayName }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xl font-bold leading-none", children: dayNum }) ] }, iso); }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { type: "hidden", name: "deadline", value: deadline }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: t('create.field.time_slot') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("select", { name: "timeSlot", className: "w-full border border-gray-300 rounded-lg px-3 py-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "", children: t('create.field.time_slot.any') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "morning", children: t('create.field.time_slot.morning') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "afternoon", children: t('create.field.time_slot.afternoon') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "evening", children: t('create.field.time_slot.evening') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("option", { value: "weekend", children: t('create.field.time_slot.weekend') }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('create.field.address') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-2 sm:gap-3", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { name: "district", placeholder: t('create.field.address.district'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { name: "street", placeholder: t('create.field.address.street'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { name: "houseNumber", placeholder: t('create.field.address.house'), className: "border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400" }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: t('create.field.photos') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex flex-wrap gap-2 mb-2", children: [ images.map((url, i)=>/*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "relative w-20 h-20 rounded-lg overflow-hidden border border-gray-200", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: url, alt: "", className: "w-full h-full object-cover" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setImages((prev)=>prev.filter((_, j)=>j !== i)), className: "absolute top-0.5 right-0.5 bg-black/50 text-white rounded-full w-5 h-5 flex items-center justify-center text-xs hover:bg-black/70", children: "\xd7" }) ] }, i)), images.length < 5 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>fileInputRef.current?.click(), disabled: photoUploading, className: "w-20 h-20 border-2 border-dashed border-gray-300 rounded-lg flex flex-col items-center justify-center text-gray-400 hover:border-blue-400 hover:text-blue-400 text-xs disabled:opacity-50", children: photoUploading ? '...' : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-2xl leading-none", children: "+" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { children: t('create.field.photos.add') }) ] }) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input", { ref: fileInputRef, type: "file", accept: "image/*", className: "hidden", onChange: handlePhotoChange }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("label", { className: "block text-sm font-medium text-gray-700 mb-1", children: [ t('create.field.confidential'), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "ml-2 text-xs font-normal text-gray-400", children: [ "\uD83D\uDD12 ", t('create.field.confidential.hint') ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("textarea", { name: "confidentialNote", rows: 2, placeholder: t('create.field.confidential.placeholder'), className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 resize-none" }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_Turnstile__WEBPACK_IMPORTED_MODULE_10__/* .TurnstileWidget */ .$, { onSuccess: setCaptchaToken, onError: ()=>setCaptchaToken(''), onExpire: ()=>setCaptchaToken('') }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "submit", disabled: loading || !captchaToken, className: "w-full bg-blue-600 text-white py-3 rounded-xl font-semibold hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed", children: loading ? t('create.submitting') : t('create.submit') }) ] }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("aside", { className: "hidden lg:block lg:w-64 shrink-0", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "bg-white rounded-xl border border-gray-200 p-5 sticky top-24", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h3", { className: "font-semibold text-gray-900 mb-4 text-sm", children: sidebarTitle }), !selectedCategory ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 text-center py-4", children: t('tasks.new.select_category') }) : topSpecialists.length === 0 ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400 text-center py-4", children: t('specialists.empty') }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-3", children: topSpecialists.map((u)=>{ const name = (0,_lib_formatName__WEBPACK_IMPORTED_MODULE_11__/* .formatShortName */ .H)(u.firstName, u.lastName, u.name); const initials = `${u.firstName?.[0] ?? ''}${u.lastName?.[0] ?? ''}`.toUpperCase() || u.name?.[0]?.toUpperCase() || '?'; const seen = (0,_lib_formatLastSeen__WEBPACK_IMPORTED_MODULE_12__/* .formatLastSeen */ .V)(u.lastSeenAt, t); const avail = specialistAvailMap[u.id]; const isInvited = invitedIds.has(u.id); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "rounded-lg border border-gray-100 hover:bg-gray-50 transition", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)((next_link__WEBPACK_IMPORTED_MODULE_3___default()), { href: `/users/${u.id}`, target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-3 p-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-12 h-12 rounded-full bg-blue-100 flex-shrink-0 flex items-center justify-center text-blue-700 font-bold text-sm overflow-hidden border border-gray-100", children: u.image ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: u.image, alt: name, className: "w-full h-full object-cover" }) : initials }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "min-w-0 flex-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-gray-900 truncate", children: name }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-1.5 flex-wrap", children: [ u.rating ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-xs text-gray-500", children: [ "★ ", Number(u.rating).toFixed(1) ] }) : seen ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-400", children: seen }) : null, typeof u.reviewCount === 'number' && u.reviewCount > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-xs text-gray-400", children: [ u.reviewCount, " ", t('reviews.count') ] }), typeof u.positivePercent === 'number' && u.reviewCount > 0 && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-xs text-green-600", children: [ u.positivePercent, "% \uD83D\uDC4D" ] }), avail === 'available' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "inline-flex items-center gap-0.5 text-xs font-medium text-green-700 bg-green-100 px-1.5 py-0.5 rounded-full", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-green-500 inline-block" }), t('schedule.available') ] }), avail === 'busy' && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "inline-flex items-center gap-0.5 text-xs font-medium text-red-700 bg-red-100 px-1.5 py-0.5 rounded-full", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "w-1.5 h-1.5 rounded-full bg-red-500 inline-block" }), t('schedule.busy') ] }) ] }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "px-2 pb-2", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { type: "button", onClick: ()=>setInvitedIds((prev)=>{ const next = new Set(prev); if (next.has(u.id)) next.delete(u.id); else next.add(u.id); return next; }), className: `w-full text-xs font-medium py-1 rounded-lg transition ${isInvited ? 'bg-blue-600 text-white hover:bg-blue-700' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`, children: isInvited ? t('tasks.new.invited') : t('tasks.new.invite') }) }) ] }, u.id); }) }) ] }) }) ] }) ] }); }    __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CreateTaskPage) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _lib_auth__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13260); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(96484); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(56003); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(91864); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(48178); /* harmony import */ var _lib_formatLastSeen__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(49598); /* harmony import */ var _components_TaskLocationPicker__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(53863); /* harmony import */ var _components_TaskCategoryPicker__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(88142); /* harmony import */ var _components_Turnstile__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(32589); d(61146undefined148199undefined201261undefined263291undefined293332undefined334378undefined380428undefined430513undefined515565undefined567620undefined622690undefined692760undefined762818undefined820876undefined890920"https://api.canhelp.gr"undefined9259470undefined11501164undefined12341243(0,_lib_auth__WEBPACK_IMPORTED_MODULE_4__/* .useSession */ .wV)undefined12671275(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined13051319(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useSearchParams)undefined14181426(0,_context_locale__WEBPACK_IMPORTED_MODULE_5__/* .useLocale */ .Y)undefined14711478(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined15231530(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined15711578(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined16181625(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined16801687(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined17301737(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined18931900(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined20512056(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined21212128(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined21752182(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22402247(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined22492263_components_Turnstile__WEBPACK_IMPORTED_MODULE_10__/* .CAPTCHA_ENABLED */ .lundefined23222332(0,_context_location__WEBPACK_IMPORTED_MODULE_6__/* .useLocation */ .z)undefined23892396(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined24552462(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined25412549(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined26852692(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined27472754(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined27892794(0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)undefined28582866(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined29412953(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getCategories */ .bW)undefined30003011(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getLocations */ .Vs)undefined31563164(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined32783291(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .getSpecialists */ .F7)undefined35183526(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined65066515(0,_lib_api__WEBPACK_IMPORTED_MODULE_7__/* .createTask */ .UT)undefined68216824(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined79607964(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined80878090(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined82708274(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined84308433(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined85528556(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined88348837(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined90789082(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined92929296(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined94259428(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined97559758(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined97609777_components_TaskCategoryPicker__WEBPACK_IMPORTED_MODULE_9__/* .TaskCategoryPicker */ .Wundefined1038310387(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1051610519(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1084610849(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1085110868_components_TaskLocationPicker__WEBPACK_IMPORTED_MODULE_8__/* .TaskLocationPicker */ .Vundefined1155411558(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1167111675(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1203512038(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1239012393(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1306013064(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1317713181(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1354713550(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1390213905(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1459314597(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1471014713(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1500615010(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1525415257(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1592215926(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1619216195(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1662116624(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1721117215(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1732817332(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined1754817551(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1787617879(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1834618349(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1870318706(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1966519669(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2029320296(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2089020893(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2133621339(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2178021783(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2237922382(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2339023393(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2411824122(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2474824751(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2509525098(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2560725610(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2596825972(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2608526088(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2638426388(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2669126694(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2697926982(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2727827281(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2758127584(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2788027883(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2832528329(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2844228445(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2873928743(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined2897728980(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2944729450(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined2991329916(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3052930533(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3064630649(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3094230946(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3118031184(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3147631479(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3187931882(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3265532658(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3326733271(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3327333281react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined3342833431(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3375933762(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3424834251(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3474834752(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3486534869(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3518335187(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3578235785(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3636836371(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3637336387_components_Turnstile__WEBPACK_IMPORTED_MODULE_10__/* .TurnstileWidget */ .$undefined3667836681(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3724537248(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3738037384(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3758437587(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3784937852(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3810838111(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3832938332(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined3852838542(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_11__/* .formatShortName */ .H)undefined3879238805(0,_lib_formatLastSeen__WEBPACK_IMPORTED_MODULE_12__/* .formatLastSeen */ .V)undefined3904639050(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3929939303(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined3930539308(next_link__WEBPACK_IMPORTED_MODULE_3___default())undefined3976739770(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4010240105(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4057740581(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4083140834(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4119741201(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4150741511(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4209042093(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4253242536(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4332643330(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4400144005(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4439744400(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4500845012(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined4540045403(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4632346326(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined4648946492(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined   +webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { getTranslations } from '@/lib/translations'; const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ createContext({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } export function LocaleProvider({ children, initialLocale }) { const router = useRouter(); const [locale, setLocaleState] = useState(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = useCallback((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = useCallback((key, fallback)=>getTranslations(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ _jsx(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } export function useLocale() { return useContext(LocaleContext); } cN}_5$ow2::?U  1 4 B (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)"https://api.canhelp.gr"0(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)0(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)  /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } function LocaleProvider({ children, initialLocale }) { const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const [locale, setLocaleState] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((key, fallback)=>(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } function useLocale() { return (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(LocaleContext); }    /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); ;G78125undefined127210undefined212255undefined257309undefined413425(0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)undefined798804undefined879887(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined929936(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10741082(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined13081338"https://api.canhelp.gr"undefined134313650undefined17121722(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined20012031"https://api.canhelp.gr"undefined203620580undefined24902500(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined25192533(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)undefined26092612(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined27622768undefined28032812(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)undefined 8  uwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcefQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); _X[aX^ :@7_=L R E K  R X k q > D v | g_mkq06sy<B_e=Cdj &_>D5;PV CI<Bkq_  D!J!!"V"\"$$%%'$'j'p''(>(D(((W)])*_*I*O***R+X+,,B,H,,,-"---h.n./%///\0b081>111113_344:44444;5A555b6h666+717888889a9g9::P;V;;;<_<==T=Z===>>>>??@ @@@-A3AtAzABB^BdBCCdCjCCCJDHPDDD;EAE|EEOFUF true"https://api.canhelp.gr"00true wk/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`);     /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */  v  w4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ TaskListClient: () => (/* binding */ TaskListClient) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(96484); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(12998); /* harmony import */ var _lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8293); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(48178); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceu)/* __next_internal_client_entry_do_not_use__ TaskListClient auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState } from 'react'; import Link from 'next/link'; import { useLocale } from '@/context/locale'; import { getTranslations } from '@/lib/translations'; import { taskTitle, taskDescription, formatPrice } from '@/lib/taskLocale'; import { shortName } from '@/lib/formatName'; const BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function TaskListClient({ initialTasks, initialTotal, filterParams, locale: localeProp, catMap, locMap, mode = 'all' }) { const { locale } = useLocale(); const t = getTranslations(locale); const [tasks, setTasks] = useState(initialTasks); const [total] = useState(initialTotal); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const hasMore = tasks.length < total; async function loadMore() { setLoading(true); try { const nextPage = page + 1; const params = new URLSearchParams({ ...filterParams, page: String(nextPage), limit: '10' }); const endpoint = mode === 'for_me' ? '/tasks/for-me' : '/tasks'; const res = await fetch(`${BASE}/api${endpoint}?${params}`, { credentials: 'include' }); const json = await res.json(); setTasks((prev)=>[ ...prev, ...json.data || [] ]); setPage(nextPage); } finally{ setLoading(false); } } if (tasks.length === 0) { return /*#__PURE__*/ _jsx("div", { className: "text-center py-20 text-white/70", children: /*#__PURE__*/ _jsx("p", { className: "text-lg", children: t('tasks.empty') }) }); } return /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("div", { className: "space-y-4", children: tasks.map((row)=>{ const task = row.task || row; const customer = row.customer; return /*#__PURE__*/ _jsx(Link, { href: `/tasks/${task.id}`, className: "block bg-white rounded-xl border border-gray-200 p-5 hover:shadow-md hover:border-blue-300 transition", children: /*#__PURE__*/ _jsxs("div", { className: "flex justify-between items-start gap-4", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center gap-2 mb-2", children: [ /*#__PURE__*/ _jsx("span", { className: "text-xs font-medium text-blue-600 bg-blue-50 px-2 py-0.5 rounded-full", children: task.category ? catMap[task.category] ?? task.category : t('tasks.category.general') }), task.location && /*#__PURE__*/ _jsxs("span", { className: "text-xs text-gray-500", children: [ "\uD83D\uDCCD ", locMap[task.location] ?? task.location ] }) ] }), /*#__PURE__*/ _jsx("h2", { className: "font-semibold text-gray-900 text-lg mb-1 truncate", children: taskTitle(task, locale) }), /*#__PURE__*/ _jsx("p", { className: "text-sm text-gray-500 line-clamp-2", children: taskDescription(task, locale) }) ] }), /*#__PURE__*/ _jsxs("div", { className: "text-right shrink-0", children: [ task.budget ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs("p", { className: "text-lg font-bold text-green-600", children: [ formatPrice(task.budget), "€" ] }), task.budgetNegotiable && /*#__PURE__*/ _jsx("p", { className: "text-xs text-green-600", children: t('task.budget_negotiable') }) ] }) : task.budgetNegotiable ? /*#__PURE__*/ _jsx("p", { className: "text-sm font-medium text-green-600", children: t('task.budget_negotiable') }) : null, /*#__PURE__*/ _jsxs("p", { className: "text-xs text-gray-600 mt-1", children: [ /*#__PURE__*/ _jsxs("span", { className: "text-gray-500", children: [ task.deadline ? t('task.deadline') : t('task.created_at'), ": " ] }), new Date(task.deadline ?? task.createdAt).toLocaleDateString(locale === 'ru' ? 'ru-RU' : locale === 'en' ? 'en-US' : 'el-GR') ] }), customer && /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-end gap-1.5 mt-2", children: [ /*#__PURE__*/ _jsxs("div", { className: "text-right", children: [ /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 leading-none", children: shortName(customer.name) }), customer.rating && /*#__PURE__*/ _jsxs("p", { className: "text-xs text-yellow-500 leading-none mt-0.5", children: [ "★ ", Number(customer.rating).toFixed(1) ] }) ] }), /*#__PURE__*/ _jsx("div", { className: "w-7 h-7 rounded-full overflow-hidden bg-blue-100 shrink-0 flex items-center justify-center", children: customer.image ? /*#__PURE__*/ _jsx("img", { src: customer.image, alt: shortName(customer.name), className: "w-full h-full object-cover" }) : /*#__PURE__*/ _jsx("span", { className: "text-blue-600 font-semibold text-xs", children: shortName(customer.name).charAt(0).toUpperCase() }) }) ] }) ] }) ] }) }, task.id); }) }), hasMore && /*#__PURE__*/ _jsx("div", { className: "flex justify-center mt-8", children: /*#__PURE__*/ _jsx("button", { onClick: loadMore, disabled: loading, className: "px-6 py-2.5 bg-white border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:border-blue-400 hover:text-blue-600 disabled:opacity-50 transition", children: loading ? t('common.loading') : t('tasks.load_more') }) }) ] }); } a4D_ =?LS{_CF    p t L O BEkn _!y}[^"]"`"e#h##$$F$y%%X'['''"https://api.canhelp.gr"0(0,_context_locale__WEBPACK_IMPORTED_MODULE_3__/* .useLocale */ .Y)(0,_lib_translations__WEBPACK_IMPORTED_MODULE_4__/* .getTranslations */ .$)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(next_link__WEBPACK_IMPORTED_MODULE_2___default())(0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .taskTitle */ .Oj)(0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .taskDescription */ .GZ)react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment(0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .formatPrice */ .$g)(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_6__/* .shortName */ .E) H5/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ TaskListClient: () => (/* binding */ TaskListClient) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(96484); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(12998); /* harmony import */ var _lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8293); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(48178); /* __next_internal_client_entry_do_not_use__ TaskListClient auto */ const BASE = "https://api.canhelp.gr" || 0; function TaskListClient({ initialTasks, initialTotal, filterParams, locale: localeProp, catMap, locMap, mode = 'all' }) { const { locale } = (0,_context_locale__WEBPACK_IMPORTED_MODULE_3__/* .useLocale */ .Y)(); const t = (0,_lib_translations__WEBPACK_IMPORTED_MODULE_4__/* .getTranslations */ .$)(locale); const [tasks, setTasks] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialTasks); const [total] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialTotal); const [page, setPage] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(1); const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); const hasMore = tasks.length < total; async function loadMore() { setLoading(true); try { const nextPage = page + 1; const params = new URLSearchParams({ ...filterParams, page: String(nextPage), limit: '10' }); const endpoint = mode === 'for_me' ? '/tasks/for-me' : '/tasks'; const res = await fetch(`${BASE}/api${endpoint}?${params}`, { credentials: 'include' }); const json = await res.json(); setTasks((prev)=>[ ...prev, ...json.data || [] ]); setPage(nextPage); } finally{ setLoading(false); } } if (tasks.length === 0) { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "text-center py-20 text-white/70", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-lg", children: t('tasks.empty') }) }); } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "space-y-4", children: tasks.map((row)=>{ const task = row.task || row; const customer = row.customer; return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)((next_link__WEBPACK_IMPORTED_MODULE_2___default()), { href: `/tasks/${task.id}`, className: "block bg-white rounded-xl border border-gray-200 p-5 hover:shadow-md hover:border-blue-300 transition", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex justify-between items-start gap-4", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-xs font-medium text-blue-600 bg-blue-50 px-2 py-0.5 rounded-full", children: task.category ? catMap[task.category] ?? task.category : t('tasks.category.general') }), task.location && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-xs text-gray-500", children: [ "\uD83D\uDCCD ", locMap[task.location] ?? task.location ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h2", { className: "font-semibold text-gray-900 text-lg mb-1 truncate", children: (0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .taskTitle */ .Oj)(task, locale) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm text-gray-500 line-clamp-2", children: (0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .taskDescription */ .GZ)(task, locale) }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-right shrink-0", children: [ task.budget ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-lg font-bold text-green-600", children: [ (0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .formatPrice */ .$g)(task.budget), "€" ] }), task.budgetNegotiable && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-green-600", children: t('task.budget_negotiable') }) ] }) : task.budgetNegotiable ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-sm font-medium text-green-600", children: t('task.budget_negotiable') }) : null, /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-xs text-gray-600 mt-1", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("span", { className: "text-gray-500", children: [ task.deadline ? t('task.deadline') : t('task.created_at'), ": " ] }), new Date(task.deadline ?? task.createdAt).toLocaleDateString(locale === 'ru' ? 'ru-RU' : locale === 'en' ? 'en-US' : 'el-GR') ] }), customer && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "flex items-center justify-end gap-1.5 mt-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { className: "text-right", children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xs text-gray-500 leading-none", children: (0,_lib_formatName__WEBPACK_IMPORTED_MODULE_6__/* .shortName */ .E)(customer.name) }), customer.rating && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("p", { className: "text-xs text-yellow-500 leading-none mt-0.5", children: [ "★ ", Number(customer.rating).toFixed(1) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "w-7 h-7 rounded-full overflow-hidden bg-blue-100 shrink-0 flex items-center justify-center", children: customer.image ? /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", { src: customer.image, alt: (0,_lib_formatName__WEBPACK_IMPORTED_MODULE_6__/* .shortName */ .E)(customer.name), className: "w-full h-full object-cover" }) : /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", { className: "text-blue-600 font-semibold text-xs", children: (0,_lib_formatName__WEBPACK_IMPORTED_MODULE_6__/* .shortName */ .E)(customer.name).charAt(0).toUpperCase() }) }) ] }) ] }) ] }) }, task.id); }) }), hasMore && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "flex justify-center mt-8", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { onClick: loadMore, disabled: loading, className: "px-6 py-2.5 bg-white border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:border-blue-400 hover:text-blue-600 disabled:opacity-50 transition", children: loading ? t('common.loading') : t('tasks.load_more') }) }) ] }); }     /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ TaskListClient: () => (/* binding */ TaskListClient) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(94496); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(96484); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(12998); /* harmony import */ var _lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8293); /* harmony import */ var _lib_formatName__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(48178);  68153undefined155187undefined189217undefined219263undefined265317undefined319393undefined395439undefined454484"https://api.canhelp.gr"undefined4895110undefined514520undefined666674(0,_context_locale__WEBPACK_IMPORTED_MODULE_3__/* .useLocale */ .Y)undefined693707(0,_lib_translations__WEBPACK_IMPORTED_MODULE_4__/* .getTranslations */ .$)undefined748755(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined792799(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined844851(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined891898(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined17511754(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined18591862(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined20102014(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined20712074(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined23122315(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined23172320(next_link__WEBPACK_IMPORTED_MODULE_2___default())undefined25642568(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined27462750(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined29282932(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined31483151(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined35773581(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined41624165(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined43374345(0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .taskTitle */ .Oj)undefined44594462(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined46184632(0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .taskDescription */ .GZ)undefined48114815(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined50125016(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined50185026react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragmentundefined51495153(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined53815391(0,_lib_taskLocale__WEBPACK_IMPORTED_MODULE_5__/* .formatPrice */ .$g)undefined56605663(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined60316034(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined63236327(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined65396543(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined73117315(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined75457549(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined77717774(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined79627970(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_6__/* .shortName */ .E)undefined81368140(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined87978800(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined90619064(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined92139221(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_6__/* .shortName */ .E)undefined94069409(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined95939601(0,_lib_formatName__WEBPACK_IMPORTED_MODULE_6__/* .shortName */ .E)undefined1007210075(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined1018110184(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined k  xwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource import { createAuthClient } from 'better-auth/react'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export const authClient = createAuthClient({ baseURL: API_URL }); export const { signIn, signOut, signUp, useSession } = authClient; d4FdiE"https://api.canhelp.gr"0(0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M) /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); const API_URL = "https://api.canhelp.gr" || 0; const authClient = (0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)({ baseURL: API_URL }); const { signIn, signOut, signUp, useSession } = authClient;    /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); 052undefined70100"https://api.canhelp.gr"undefined1051270undefined130136undefined156171(0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)undefined200206undefined `  tvuw Awebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceconst APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; export default function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } e.3ILZ"http://canhelp.gr"0buffersourcesizemapshashconst APP_URL = "http://canhelp.gr" || 0; function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } {"finalSource":false}mapbufferedMap ReplaceSourceRawSourceconst APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; export default function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } ;1646"http://canhelp.gr"undefined51730undefined7690undefinedc // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__   webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* dynamic asset route */ import { NextResponse } from 'next/server' import handler from "/opt/canhelp/apps/web/src/app/robots.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const contentType = "text/plain" const fileType = "robots" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } export async function GET() { const data = await handler() const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } bCEL-3 ,7__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._-/* dynamic asset route */ const contentType = "text/plain" const fileType = "robots" if (typeof __WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__._ !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } async function GET() { const data = await __WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__._() const content = __WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._(data, fileType) return new __WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) }  /* dynamic asset route */ import { NextResponse } from 'next/server' import handler from "/opt/canhelp/apps/web/src/app/robots.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const contentType = "text/plain" const fileType = "robots" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } export async function GET() { const data = await handler() const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 2667undefined69129undefined131224undefined301307__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__._undefined430436undefined481487__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__._undefined509524__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined556567__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined`hF]+Krobots(0,resolve_route_data.resolveRouteData)server.NextResponse ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=!  fHwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceG=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map c;^`_%'np "_abd/_Aem<AB]TS - / 5 f z } O v ]k^k_$5Xmq$$$%`&m&+'8'((6(r*}*-,-..11224R444;5P5666688H9O9O:]::;L;<<__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._".next"0 false: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._false{}__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._A // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new __WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._({ definition: { kind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._ }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return __WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = __WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = __WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: __WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._(req); const nodeNextRes = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._(res); const nextReq = __WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._.fromNodeNextRequest(nodeNextReq, __WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== __WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = __WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(response.headers); if (cacheTags) { headers[__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = __WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(cacheEntry.value.headers); if (!(__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isIsr)) { headers.delete(__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', __WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._(cacheEntry.cacheControl)); } await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest, { spanName: `${method} ${req.url}`, kind: __WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map  G=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741442undefined15831601__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16371645__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18171852".next"undefined185718580undefined18851923 falseundefined21322131: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24372447__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25162605undefined26072613undefined29182938falseundefined29413005{}undefined31513190falseundefined37163731__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41894203__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50455053__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54705483__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60876101__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61376152__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61806197__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62326253__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68896902__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78807893__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93299353__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94519472__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98249837__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1002710040__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028010294__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1086610877__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1154611564__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200112009__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1255912573__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1303913052__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1347513501__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1354813561__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1362713648__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1396813988__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1404914060__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455214565__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1466414671__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1492714941__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516215180__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552215533__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined`"_%i@rP  x uUq_)[!n""<#_$$%&'S')),,..1c1533<555F6664888=9);w;;<=z=CW>>@t@module_compiled.AppRouteRouteModuleroute_kind.RouteKindnext_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject(0,patch_fetch.patchFetch)(0,app_paths_.normalizeAppPath)no_fallback_error_external_.NoFallbackError(0,trace_tracer.getTracer)(0,request_meta.getRequestMeta)node.NodeNextRequestnode.NodeNextResponsenext_request.NextRequestAdapter(0,next_request.signalFromNodeResponse)constants.BaseServerSpan(0,web_utils.toNodeOutgoingHttpHeaders)lib_constants.NEXT_CACHE_TAGS_HEADERlib_constants.INFINITE_CACHEresponse_cache.CachedRouteKind(0,send_response/* sendResponse */.I)(0,utils/* getRevalidateReason */.c)(0,web_utils.fromNodeOutgoingHttpHeaders)(0,cache_control.getCacheControlHeader)trace_tracer.SpanKind |4M// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts const APP_URL = "http://canhelp.gr" || 0; function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ /* dynamic asset route */ const contentType = "text/plain" const fileType = "robots" if (typeof robots !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } async function GET() { const data = await robots() const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map }   ` // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts  ReplaceSource;1646"http://canhelp.gr"undefined51730undefined7690undefined RawSourcec // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ ~/* dynamic asset route */ import { NextResponse } from 'next/server' import handler from "/opt/canhelp/apps/web/src/app/robots.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const contentType = "text/plain" const fileType = "robots" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } export async function GET() { const data = await handler() const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 2667undefined69129undefined131224undefined301307__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__._undefined430436undefined481487__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__._undefined509524__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined556567__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined104182robotsundefined349432robotsundefined454555(0,resolve_route_data.resolveRouteData)undefined587675server.NextResponseundefinedRawSource ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! zG=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741442undefined15831601__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16371645__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18171852".next"undefined185718580undefined18851923 falseundefined21322131: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24372447__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25162605undefined26072613undefined29182938falseundefined29413005{}undefined31513190falseundefined37163731__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41894203__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50455053__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54705483__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60876101__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61376152__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61806197__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62326253__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68896902__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78807893__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93299353__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94519472__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98249837__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1002710040__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028010294__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1086610877__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1154611564__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200112009__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1255912573__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1303913052__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1347513501__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1354813561__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1362713648__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1396813988__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1404914060__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455214565__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1466414671__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1492714941__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516215180__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552215533__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined156257module_compiled.AppRouteRouteModuleundefined293361route_kind.RouteKindundefined787832next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectundefined11381226(0,patch_fetch.patchFetch)undefined22842384(0,app_paths_.normalizeAppPath)undefined28422936no_fallback_error_external_.NoFallbackErrorundefined37783864(0,trace_tracer.getTracer)undefined42814377(0,request_meta.getRequestMeta)undefined49815074node.NodeNextRequestundefined51105205node.NodeNextResponseundefined52335324next_request.NextRequestAdapterundefined53595471(0,next_request.signalFromNodeResponse)undefined61076185constants.BaseServerSpanundefined71637259(0,request_meta.getRequestMeta)undefined86958814(0,web_utils.toNodeOutgoingHttpHeaders)undefined89129020lib_constants.NEXT_CACHE_TAGS_HEADERundefined93729464lib_constants.INFINITE_CACHEundefined96549746lib_constants.INFINITE_CACHEundefined998610067response_cache.CachedRouteKindundefined1063910732(0,send_response/* sendResponse */.I)undefined1140111507(0,utils/* getRevalidateReason */.c)undefined1194412012route_kind.RouteKindundefined1256212643response_cache.CachedRouteKindundefined1310913205(0,request_meta.getRequestMeta)undefined1362813751(0,web_utils.fromNodeOutgoingHttpHeaders)undefined1379813894(0,request_meta.getRequestMeta)undefined1396014068lib_constants.NEXT_CACHE_TAGS_HEADERundefined1438814499(0,cache_control.getCacheControlHeader)undefined1456014653(0,send_response/* sendResponse */.I)undefined1514515223constants.BaseServerSpanundefined1532215388trace_tracer.SpanKindundefined1564415738no_fallback_error_external_.NoFallbackErrorundefined1595916065(0,utils/* getRevalidateReason */.c)undefined1640716500(0,send_response/* sendResponse */.I)undefined5 `?module_compiledmodule_compiled_namespaceObjectmodule_compiled_defaultroute_kindroute_kind_namespaceObjectpatch_fetchpatch_fetch_namespaceObjectpatch_fetch_defaultrequest_metarequest_meta_namespaceObjectrequest_meta_defaulttrace_tracertracer_namespaceObjecttracer_defaultapp_paths_app_paths_namespaceObjectapp_paths_defaultnodenode_namespaceObjectnode_defaultnext_requestnext_request_namespaceObjectnext_request_defaultconstantsconstants_namespaceObjectconstants_defaultutilsutils_namespaceObjectsend_responsesend_response_namespaceObjectweb_utilsweb_utils_namespaceObjectutils_defaultcache_controlcache_control_namespaceObjectlib_constantslib_constants_namespaceObjectlib_constants_defaultno_fallback_error_external_no_fallback_error_external_namespaceObjectno_fallback_error_external_defaultresponse_cacheresponse_cache_namespaceObjectresponse_cache_defaultrobots_namespaceObjectresolve_route_dataresolve_route_data_namespaceObjectresolve_route_data_defaultcontentTypefileTypeGETnext_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectnextConfigOutputrouteModuleworkAsyncStorageworkUnitAsyncStorageserverHookspatchFetchhandlerrnext_app_loaderpage_2Frobots_txt_2Froute_name_app_2Frobots_txt_2Froute_pagePath_private_next_app_dir_2Frobots_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Frobots_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_namespaceObject  >=; $ )webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource(// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource  webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } export default async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } f.3I\zB "http://canhelp.gr"0"https://api.canhelp.gr"0buffersourcesizemapshashI const APP_URL = "http://canhelp.gr" || 0; const API_URL = "https://api.canhelp.gr" || 0; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } {"finalSource":false}mapbufferedMap ReplaceSourceRawSource const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } export default async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } u1646"http://canhelp.gr"undefined51730undefined92122"https://api.canhelp.gr"undefined1271490undefined27202734undefinedd // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__  vwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceimport { NextResponse } from 'next/server' import * as userland from "/opt/canhelp/apps/web/src/app/sitemap.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const sitemapModule = { ...userland } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new NextResponse('Not Found', { status: 404, }) } if (process.env.NODE_ENV !== 'production' && sitemapModule.generateSitemaps) { const sitemaps = await sitemapModule.generateSitemaps() for (const item of sitemaps) { if (item?.id == null) { throw new Error('id property is required for every item returned from generateSitemaps') } } } const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) }  c)+npNHK;__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__.___WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._false{}__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._ const sitemapModule = { ...__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__._ } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new __WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._('Not Found', { status: 404, }) } if (false) {} const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = __WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._(data, fileType) return new __WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) }  import { NextResponse } from 'next/server' import * as userland from "/opt/canhelp/apps/web/src/app/sitemap.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const sitemapModule = { ...userland } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new NextResponse('Not Found', { status: 404, }) } if (process.env.NODE_ENV !== 'production' && sitemapModule.generateSitemaps) { const sitemaps = await sitemapModule.generateSitemaps() for (const item of sitemaps) { if (item?.id == null) { throw new Error('id property is required for every item returned from generateSitemaps') } } } const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 041undefined43110undefined112205undefined235242__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__._undefined494500undefined705716__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined770840falseundefined8431083{}undefined12231238__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined12701281__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefinedaLEl6sitemap_namespaceObjectserver.NextResponse(0,resolve_route_data.resolveRouteData) ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=!  mHwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceN=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map c;^`_%'np "_abd0_BfnAFGbZY 3 5 ; m V } drer_+<_tx$$$%g&t&2'?'/(=(y**!-3-..1$1234R445B5W5666688O9V9V:d:A;S;<<__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._".next"0 false: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._false{}__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._A // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new __WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._({ definition: { kind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._ }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return __WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = __WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = __WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: __WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._(req); const nodeNextRes = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._(res); const nextReq = __WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._.fromNodeNextRequest(nodeNextReq, __WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== __WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = __WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(response.headers); if (cacheTags) { headers[__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = __WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(cacheEntry.value.headers); if (!(__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isIsr)) { headers.delete(__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', __WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._(cacheEntry.cacheControl)); } await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest, { spanName: `${method} ${req.url}`, kind: __WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map  N=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741443undefined15841602__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16381646__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18221857".next"undefined186218630undefined18901928 falseundefined21382137: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24432453__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25222611undefined26132619undefined29252945falseundefined29483012{}undefined31583197falseundefined37233738__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41964210__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50525060__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54775490__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60946108__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61446159__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61876204__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62396260__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68966909__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78877900__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93369360__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94589479__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98319844__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1003410047__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028710301__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1087310884__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1155311571__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200812016__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1256612580__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1304613059__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1348213508__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1355513568__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1363413655__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1397513995__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1405614067__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455914572__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1467114678__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1493414948__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516915187__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552915540__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined`#_%iEw$*V ~ {[we/a!t"_"B#$$%&'Y')),,..1i1;33B555L666:888C9/;};;"<E"==]>>@z@module_compiled.AppRouteRouteModuleroute_kind.RouteKindnext_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject(0,patch_fetch.patchFetch)nnext_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler(0,app_paths_.normalizeAppPath)no_fallback_error_external_.NoFallbackError(0,trace_tracer.getTracer)(0,request_meta.getRequestMeta)node.NodeNextRequestnode.NodeNextResponsenext_request.NextRequestAdapter(0,next_request.signalFromNodeResponse)constants.BaseServerSpan(0,web_utils.toNodeOutgoingHttpHeaders)lib_constants.NEXT_CACHE_TAGS_HEADERlib_constants.INFINITE_CACHEresponse_cache.CachedRouteKind(0,send_response/* sendResponse */.I)(0,utils/* getRevalidateReason */.c)(0,web_utils.fromNodeOutgoingHttpHeaders)(0,cache_control.getCacheControlHeader)trace_tracer.SpanKind )[// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts const APP_URL = "http://canhelp.gr" || 0; const API_URL = "https://api.canhelp.gr" || 0; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ const sitemapModule = { ...sitemap_namespaceObject } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new server.NextResponse('Not Found', { status: 404, }) } if (false) {} const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map * -  `.(// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts /u1646"http://canhelp.gr"undefined51730undefined92122"https://api.canhelp.gr"undefined1271490undefined27202734undefinedd // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ -import { NextResponse } from 'next/server' import * as userland from "/opt/canhelp/apps/web/src/app/sitemap.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const sitemapModule = { ...userland } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new NextResponse('Not Found', { status: 404, }) } if (process.env.NODE_ENV !== 'production' && sitemapModule.generateSitemaps) { const sitemaps = await sitemapModule.generateSitemaps() for (const item of sitemaps) { if (item?.id == null) { throw new Error('id property is required for every item returned from generateSitemaps') } } } const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 041undefined43110undefined112205undefined235242__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__._undefined494500undefined705716__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined770840falseundefined8431083{}undefined12231238__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined12701281__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined3176sitemap_namespaceObjectundefined532620server.NextResponseundefined822923(0,resolve_route_data.resolveRouteData)undefined9551043server.NextResponseundefinedRawSource ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! )N=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741443undefined15841602__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16381646__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18221857".next"undefined186218630undefined18901928 falseundefined21382137: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24432453__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25222611undefined26132619undefined29252945falseundefined29483012{}undefined31583197falseundefined37233738__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41964210__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50525060__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54775490__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60946108__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61446159__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61876204__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62396260__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68966909__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78877900__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93369360__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94589479__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98319844__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1003410047__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028710301__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1087310884__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1155311571__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200812016__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1256612580__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1304613059__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1348213508__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1355513568__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1363413655__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1397513995__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1405614067__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455914572__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1467114678__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1493414948__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516915187__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552915540__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined~156257module_compiled.AppRouteRouteModuleundefined293361route_kind.RouteKindundefined792837next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectundefined11431231(0,patch_fetch.patchFetch)undefined13161322next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handlerundefined22902390(0,app_paths_.normalizeAppPath)undefined28482942no_fallback_error_external_.NoFallbackErrorundefined37843870(0,trace_tracer.getTracer)undefined42874383(0,request_meta.getRequestMeta)undefined49875080node.NodeNextRequestundefined51165211node.NodeNextResponseundefined52395330next_request.NextRequestAdapterundefined53655477(0,next_request.signalFromNodeResponse)undefined61136191constants.BaseServerSpanundefined71697265(0,request_meta.getRequestMeta)undefined87018820(0,web_utils.toNodeOutgoingHttpHeaders)undefined89189026lib_constants.NEXT_CACHE_TAGS_HEADERundefined93789470lib_constants.INFINITE_CACHEundefined96609752lib_constants.INFINITE_CACHEundefined999210073response_cache.CachedRouteKindundefined1064510738(0,send_response/* sendResponse */.I)undefined1140711513(0,utils/* getRevalidateReason */.c)undefined1195012018route_kind.RouteKindundefined1256812649response_cache.CachedRouteKindundefined1311513211(0,request_meta.getRequestMeta)undefined1363413757(0,web_utils.fromNodeOutgoingHttpHeaders)undefined1380413900(0,request_meta.getRequestMeta)undefined1396614074lib_constants.NEXT_CACHE_TAGS_HEADERundefined1439414505(0,cache_control.getCacheControlHeader)undefined1456614659(0,send_response/* sendResponse */.I)undefined1515115229constants.BaseServerSpanundefined1532815394trace_tracer.SpanKindundefined1565015744no_fallback_error_external_.NoFallbackErrorundefined1596516071(0,utils/* getRevalidateReason */.c)undefined1641316506(0,send_response/* sendResponse */.I)undefined `Esitemap_namespaceObjectݍsitemapModulenext_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectnnext_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handlervnext_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_namespaceObject $#!   )webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcepimport { jsx as _jsx } from "react/jsx-runtime"; const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; export function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ _jsx("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ _jsx("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ _jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } `/G"%03__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._buffersourcesizemapshash const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } {"finalSource":false}mapbufferedMap ReplaceSourceRawSourcepimport { jsx as _jsx } from "react/jsx-runtime"; const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; export function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ _jsx("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ _jsx("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ _jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } 1047undefined63606366undefined65426545__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined66906693__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69606963__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefinedEW2|(0,react_jsx_runtime.jsx)! ;// ./src/components/Footer.tsx  webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcez/* __next_internal_client_entry_do_not_use__ Footer auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useLocale } from '@/context/locale'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { SocialIcons } from './SocialIcons'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Footer() { const { t } = useLocale(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = useState({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ _jsx("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ _jsx("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ _jsx("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ _jsxs("ul", { className: "space-y-2", children: [ /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ _jsx(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); } c&FZ^2_6 O R $'uxz} \_adVZH "https://api.canhelp.gr"0__WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._/* __next_internal_client_entry_do_not_use__ Footer auto */ const API = "https://api.canhelp.gr" || 0; function Footer() { const { t } = __WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = __WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__._({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("ul", { className: "space-y-2", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); }  z/* __next_internal_client_entry_do_not_use__ Footer auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useLocale } from '@/context/locale'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { SocialIcons } from './SocialIcons'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Footer() { const { t } = useLocale(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = useState({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ _jsx("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ _jsx("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ _jsx("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ _jsxs("ul", { className: "space-y-2", children: [ /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ _jsx(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); }  60122undefined124168undefined170213undefined215243undefined245288undefined302332"https://api.canhelp.gr"undefined3373590undefined362368undefined407415__WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined505512__WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__._undefined574582__WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined939942__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined10501054__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined11901194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13701374__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined15601563__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18111814__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined20982102__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined22622265__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined25122516__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined26882691__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27692772__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27742777__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined31513154__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32323235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32373240__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined36203623__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37013704__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37063709__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined41074110__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41884191__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41934196__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined46944698__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined48584861__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51105113__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53455348__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53505360__WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._undefined56395643__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined`_B*Eeae]  < 2 ['qs< mE,j TM 7(0,locale/* useLocale */.Y)(0,react.useState)(0,react.useEffect)(0,react_jsx_runtime.jsxs)(link_default())SocialIcons 8 // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ (0,react_jsx_runtime.jsx)("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } ;// ./src/components/Footer.tsx /* __next_internal_client_entry_do_not_use__ Footer auto */ const API = "https://api.canhelp.gr" || 0; function Footer() { const { t } = (0,locale/* useLocale */.Y)(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = (0,react.useState)({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("ul", { className: "space-y-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); }    `  // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx pimport { jsx as _jsx } from "react/jsx-runtime"; const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; export function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ _jsx("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ _jsx("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ _jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } 1047undefined63606366undefined65426545__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined66906693__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69606963__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined64876561(0,react_jsx_runtime.jsx)undefined67066780(0,react_jsx_runtime.jsx)undefined70477121(0,react_jsx_runtime.jsx)undefinedRawSource! ;// ./src/components/Footer.tsx  60122undefined124168undefined170213undefined215243undefined245288undefined302332"https://api.canhelp.gr"undefined3373590undefined362368undefined407415__WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined505512__WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__._undefined574582__WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined939942__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined10501054__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined11901194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13701374__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined15601563__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18111814__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined20982102__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined22622265__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined25122516__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined26882691__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27692772__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27742777__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined31513154__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32323235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32373240__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined36203623__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37013704__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37063709__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined41074110__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41884191__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41934196__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined46944698__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined48584861__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51105113__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53455348__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53505360__WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._undefined56395643__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined146232(0,locale/* useLocale */.Y)undefined322406(0,react.useState)undefined468554(0,react.useEffect)undefined911985(0,react_jsx_runtime.jsx)undefined10931169(0,react_jsx_runtime.jsxs)undefined13051381(0,react_jsx_runtime.jsxs)undefined15571633(0,react_jsx_runtime.jsxs)undefined18191893(0,react_jsx_runtime.jsx)undefined21412215(0,react_jsx_runtime.jsx)undefined24992575(0,react_jsx_runtime.jsxs)undefined27352809(0,react_jsx_runtime.jsx)undefined30563132(0,react_jsx_runtime.jsxs)undefined33043378(0,react_jsx_runtime.jsx)undefined34563530(0,react_jsx_runtime.jsx)undefined35323609(link_default())undefined39834057(0,react_jsx_runtime.jsx)undefined41354209(0,react_jsx_runtime.jsx)undefined42114288(link_default())undefined46684742(0,react_jsx_runtime.jsx)undefined48204894(0,react_jsx_runtime.jsx)undefined48964973(link_default())undefined53715445(0,react_jsx_runtime.jsx)undefined55235597(0,react_jsx_runtime.jsx)undefined55995676(link_default())undefined61746250(0,react_jsx_runtime.jsxs)undefined64106484(0,react_jsx_runtime.jsx)undefined67336807(0,react_jsx_runtime.jsx)undefined70397113(0,react_jsx_runtime.jsx)undefined71157200SocialIconsundefined74797555(0,react_jsx_runtime.jsxs)undefined `react_jsx_runtimereact_jsx_runtime_namespaceObjectreact_jsx_runtime_defaultlocalereact_namespaceObjectreact_defaultapp_dir_linklink_namespaceObjectlink_defaultICONSSocialIcons_namespaceObjectFooter_namespaceObject  t Dwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource // EXPORTS __webpack_require__.d(__webpack_exports__, { l: () => (/* binding */ CAPTCHA_ENABLED), $: () => (/* binding */ TurnstileWidget) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); ;// ../../node_modules/@marsidev/react-turnstile/dist/index.js webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource ,webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource'/* __next_internal_client_entry_do_not_use__ DEFAULT_CONTAINER_ID,DEFAULT_ONLOAD_NAME,DEFAULT_SCRIPT_ID,SCRIPT_URL,Turnstile auto */ import { forwardRef as e, useCallback as t, useEffect as n, useImperativeHandle as r, useMemo as i, useRef as a, useState as o } from "react"; import { jsx as s } from "react/jsx-runtime"; var c = /*#__PURE__*/ e(({ as: e = `div`, ...t }, n)=>s(e, { ...t, ref: n })); const l = `https://challenges.cloudflare.com/turnstile/v0/api.js`, u = `cf-turnstile-script`, d = `cf-turnstile`, f = `onloadTurnstileCallback`, p = (e)=>!!document.getElementById(e), m = ({ render: e = `explicit`, onLoadCallbackName: t = f, scriptOptions: { nonce: n = ``, defer: r = !0, async: i = !0, id: a = ``, appendTo: o, onError: s, crossOrigin: c = `` } = {} })=>{ let u = a || `cf-turnstile-script`; if (p(u)) return; let d = document.createElement(`script`); d.id = u, d.src = `${l}?onload=${t}&render=${e}`, !document.querySelector(`script[src="${d.src}"]`) && (d.defer = !!r, d.async = !!i, n && (d.nonce = n), c && (d.crossOrigin = c), s && (d.onerror = s, delete window[t]), (o === `body` ? document.body : document.getElementsByTagName(`head`)[0]).appendChild(d)); }, h = { normal: { width: 300, height: 65 }, compact: { width: 150, height: 140 }, invisible: { width: 0, height: 0, overflow: `hidden` }, flexible: { minWidth: 300, width: `100%`, height: 65 }, interactionOnly: { width: `fit-content`, height: `auto`, display: `flex` } }; function g(e) { if (e !== `invisible` && e !== `interactionOnly`) return e; } function _(e = u) { let [t, r] = o(!1); return process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && n(()=>{ let t = ()=>{ p(e) && r(!0); }, n = new MutationObserver(t); return n.observe(document, { childList: !0, subtree: !0 }), t(), ()=>{ n.disconnect(); }; }, [ e ]), t; } let v = `unloaded`, y; const b = new Promise((e, t)=>{ y = { resolve: e, reject: t }, v === `ready` && e(void 0); }), x = (e = f)=>(v === `unloaded` && (v = `loading`, window[e] = ()=>{ y.resolve(), v = `ready`, delete window[e]; }), b), S = /*#__PURE__*/ e((e, l)=>{ let { scriptOptions: u, options: d = {}, siteKey: f, onWidgetLoad: p, onSuccess: y, onExpire: b, onError: S, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E, onLoadScript: D, id: O, style: k, as: A = `div`, injectScript: j = !0, rerenderOnCallbackChange: M = !1, ...N } = e, P = d.size, F = t(()=>P === void 0 ? {} : d.execution === `execute` ? h.invisible : d.appearance === `interaction-only` ? h.interactionOnly : h[P], [ d.execution, P, d.appearance ]), [I, L] = o(F()), R = a(null), [z, B] = o(!1), V = a(void 0), H = a(!1), U = O || `cf-turnstile`, W = a({ onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); n(()=>{ M || (W.current = { onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); }); let G = u?.id || `cf-turnstile-script`, K = _(G), q = u?.onLoadCallbackName || `onloadTurnstileCallback`, J = d.appearance || `always`, Y = i(()=>({ sitekey: f, action: d.action, cData: d.cData, theme: d.theme || `auto`, language: d.language || `auto`, tabindex: d.tabIndex, "response-field": d.responseField, "response-field-name": d.responseFieldName, size: g(P), retry: d.retry || `auto`, "retry-interval": d.retryInterval || 8e3, "refresh-expired": d.refreshExpired || `auto`, "refresh-timeout": d.refreshTimeout || `auto`, execution: d.execution || `render`, appearance: d.appearance || `always`, "feedback-enabled": d.feedbackEnabled ?? !0, callback: (e)=>{ H.current = !0, M ? y?.(e) : W.current.onSuccess?.(e); }, "error-callback": M ? S : (...e)=>W.current.onError?.(...e), "expired-callback": M ? b : (...e)=>W.current.onExpire?.(...e), "before-interactive-callback": M ? C : (...e)=>W.current.onBeforeInteractive?.(...e), "after-interactive-callback": M ? w : (...e)=>W.current.onAfterInteractive?.(...e), "unsupported-callback": M ? T : (...e)=>W.current.onUnsupported?.(...e), "timeout-callback": M ? E : (...e)=>W.current.onTimeout?.(...e) }), [ d.action, d.appearance, d.cData, d.execution, d.language, d.refreshExpired, d.responseField, d.responseFieldName, d.retry, d.retryInterval, d.tabIndex, d.theme, d.feedbackEnabled, d.refreshTimeout, f, P, M, M ? y : null, M ? S : null, M ? b : null, M ? C : null, M ? w : null, M ? T : null, M ? E : null ]), X = t(()=>"undefined" < `u` && !!window.turnstile, []); return n(function() { j && !z && (x(q), m({ onLoadCallbackName: q, scriptOptions: { ...u, id: G } })); }, [ j, z, u, G, q ]), n(function() { v !== `ready` && x(q).then(()=>B(!0)).catch(console.error); }, [ q ]), n(function() { if (!R.current || !z) return; let e = !1; return (async ()=>{ e || !R.current || (V.current = window.turnstile.render(R.current, Y), V.current && p?.(V.current)); })(), ()=>{ e = !0, V.current && (window.turnstile.remove(V.current), H.current = !1); }; }, [ U, z, Y ]), r(l, ()=>{ let { turnstile: e } = window; return { getResponse () { if (!e?.getResponse || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } return e.getResponse(V.current); }, async getResponsePromise (e = 3e4, t = 100) { return new Promise((n, r)=>{ let i, a = async ()=>{ if (H.current && window.turnstile && V.current) try { let e = window.turnstile.getResponse(V.current); return i && clearTimeout(i), e ? n(e) : r(Error(`No response received`)); } catch (e) { return i && clearTimeout(i), console.warn(`Failed to get response`, e), r(Error(`Failed to get response`)); } i ||= setTimeout(()=>{ i && clearTimeout(i), r(Error(`Timeout`)); }, e), await new Promise((e)=>setTimeout(e, t)), await a(); }; a(); }); }, reset () { if (!e?.reset || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } d.execution === `execute` && L(h.invisible); try { H.current = !1, e.reset(V.current); } catch (e) { console.warn(`Failed to reset Turnstile widget ${V.current}`, e); } }, remove () { if (!e?.remove || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } L(h.invisible), H.current = !1, e.remove(V.current), V.current = null; }, render () { if (!e?.render || !R.current || !X() || V.current) { console.warn(`Turnstile has not been loaded or container not found`); return; } let t = e.render(R.current, Y); return V.current = t, V.current && p?.(V.current), d.execution !== `execute` && L(P ? h[P] : {}), t; }, execute () { if (d.execution !== `execute`) { console.warn(`Execution mode is not set to "execute"`); return; } if (!e?.execute || !R.current || !V.current || !X()) { console.warn(`Turnstile has not been loaded or container not found`); return; } e.execute(R.current, Y), L(P ? h[P] : {}); }, isExpired () { return !e?.isExpired || !V.current || !X() ? (console.warn(`Turnstile has not been loaded`), !1) : e.isExpired(V.current); } }; }, [ V, d.execution, P, Y, R, X, z, p ]), n(()=>{ if (z || !K) return; if (window.turnstile) { B(!0); return; } let e = setInterval(()=>{ window.turnstile && (B(!0), clearInterval(e)); }, 50); return ()=>{ clearInterval(e); }; }, [ z, K ]), n(()=>{ L(F()); }, [ d.execution, P, J ]), n(()=>{ !K || typeof D != `function` || D(); }, [ K ]), s(c, { ref: R, as: A, id: U, style: { ...I, ...k }, ...N }); }); S.displayName = `Turnstile`; export { d as DEFAULT_CONTAINER_ID, f as DEFAULT_ONLOAD_NAME, u as DEFAULT_SCRIPT_ID, l as SCRIPT_URL, S as Turnstile }; `_@XXxxZ Z w w [ !!QQWgl}vv$$0&0&&&&&}''__WEBPACK_MODULE_REFERENCE__1_5b22666f7277617264526566225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(/* unused pure expression or super */ null && ())__WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b2275736543616c6c6261636b225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b227573654d656d6f225d_call_directImport_asiSafe1__._ false0__WEBPACK_MODULE_REFERENCE__1_5b22757365496d706572617469766548616e646c65225d_call_directImport_asiSafe1__._buffersourcesizemapshashy./* __next_internal_client_entry_do_not_use__ DEFAULT_CONTAINER_ID,DEFAULT_ONLOAD_NAME,DEFAULT_SCRIPT_ID,SCRIPT_URL,Turnstile auto */ var c = /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__1_5b22666f7277617264526566225d_call_directImport_asiSafe1__._(({ as: e = `div`, ...t }, n)=>__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(e, { ...t, ref: n })); const l = `https://challenges.cloudflare.com/turnstile/v0/api.js`, u = `cf-turnstile-script`, d = (/* unused pure expression or super */ null && (`cf-turnstile`)), f = `onloadTurnstileCallback`, p = (e)=>!!document.getElementById(e), m = ({ render: e = `explicit`, onLoadCallbackName: t = f, scriptOptions: { nonce: n = ``, defer: r = !0, async: i = !0, id: a = ``, appendTo: o, onError: s, crossOrigin: c = `` } = {} })=>{ let u = a || `cf-turnstile-script`; if (p(u)) return; let d = document.createElement(`script`); d.id = u, d.src = `${l}?onload=${t}&render=${e}`, !document.querySelector(`script[src="${d.src}"]`) && (d.defer = !!r, d.async = !!i, n && (d.nonce = n), c && (d.crossOrigin = c), s && (d.onerror = s, delete window[t]), (o === `body` ? document.body : document.getElementsByTagName(`head`)[0]).appendChild(d)); }, h = { normal: { width: 300, height: 65 }, compact: { width: 150, height: 140 }, invisible: { width: 0, height: 0, overflow: `hidden` }, flexible: { minWidth: 300, width: `100%`, height: 65 }, interactionOnly: { width: `fit-content`, height: `auto`, display: `flex` } }; function g(e) { if (e !== `invisible` && e !== `interactionOnly`) return e; } function _(e = u) { let [t, r] = __WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._(!1); return process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ let t = ()=>{ p(e) && r(!0); }, n = new MutationObserver(t); return n.observe(document, { childList: !0, subtree: !0 }), t(), ()=>{ n.disconnect(); }; }, [ e ]), t; } let v = `unloaded`, y; const b = new Promise((e, t)=>{ y = { resolve: e, reject: t }, v === `ready` && e(void 0); }), x = (e = f)=>(v === `unloaded` && (v = `loading`, window[e] = ()=>{ y.resolve(), v = `ready`, delete window[e]; }), b), S = /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__1_5b22666f7277617264526566225d_call_directImport_asiSafe1__._((e, l)=>{ let { scriptOptions: u, options: d = {}, siteKey: f, onWidgetLoad: p, onSuccess: y, onExpire: b, onError: S, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E, onLoadScript: D, id: O, style: k, as: A = `div`, injectScript: j = !0, rerenderOnCallbackChange: M = !1, ...N } = e, P = d.size, F = __WEBPACK_MODULE_REFERENCE__1_5b2275736543616c6c6261636b225d_call_directImport_asiSafe1__._(()=>P === void 0 ? {} : d.execution === `execute` ? h.invisible : d.appearance === `interaction-only` ? h.interactionOnly : h[P], [ d.execution, P, d.appearance ]), [I, L] = __WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._(F()), R = __WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._(null), [z, B] = __WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._(!1), V = __WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._(void 0), H = __WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._(!1), U = O || `cf-turnstile`, W = __WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._({ onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ M || (W.current = { onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); }); let G = u?.id || `cf-turnstile-script`, K = _(G), q = u?.onLoadCallbackName || `onloadTurnstileCallback`, J = d.appearance || `always`, Y = __WEBPACK_MODULE_REFERENCE__1_5b227573654d656d6f225d_call_directImport_asiSafe1__._(()=>({ sitekey: f, action: d.action, cData: d.cData, theme: d.theme || `auto`, language: d.language || `auto`, tabindex: d.tabIndex, "response-field": d.responseField, "response-field-name": d.responseFieldName, size: g(P), retry: d.retry || `auto`, "retry-interval": d.retryInterval || 8e3, "refresh-expired": d.refreshExpired || `auto`, "refresh-timeout": d.refreshTimeout || `auto`, execution: d.execution || `render`, appearance: d.appearance || `always`, "feedback-enabled": d.feedbackEnabled ?? !0, callback: (e)=>{ H.current = !0, M ? y?.(e) : W.current.onSuccess?.(e); }, "error-callback": M ? S : (...e)=>W.current.onError?.(...e), "expired-callback": M ? b : (...e)=>W.current.onExpire?.(...e), "before-interactive-callback": M ? C : (...e)=>W.current.onBeforeInteractive?.(...e), "after-interactive-callback": M ? w : (...e)=>W.current.onAfterInteractive?.(...e), "unsupported-callback": M ? T : (...e)=>W.current.onUnsupported?.(...e), "timeout-callback": M ? E : (...e)=>W.current.onTimeout?.(...e) }), [ d.action, d.appearance, d.cData, d.execution, d.language, d.refreshExpired, d.responseField, d.responseFieldName, d.retry, d.retryInterval, d.tabIndex, d.theme, d.feedbackEnabled, d.refreshTimeout, f, P, M, M ? y : null, M ? S : null, M ? b : null, M ? C : null, M ? w : null, M ? T : null, M ? E : null ]), X = __WEBPACK_MODULE_REFERENCE__1_5b2275736543616c6c6261636b225d_call_directImport_asiSafe1__._(()=> false && 0, []); return __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(function() { j && !z && (x(q), m({ onLoadCallbackName: q, scriptOptions: { ...u, id: G } })); }, [ j, z, u, G, q ]), __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(function() { v !== `ready` && x(q).then(()=>B(!0)).catch(console.error); }, [ q ]), __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(function() { if (!R.current || !z) return; let e = !1; return (async ()=>{ e || !R.current || (V.current = window.turnstile.render(R.current, Y), V.current && p?.(V.current)); })(), ()=>{ e = !0, V.current && (window.turnstile.remove(V.current), H.current = !1); }; }, [ U, z, Y ]), __WEBPACK_MODULE_REFERENCE__1_5b22757365496d706572617469766548616e646c65225d_call_directImport_asiSafe1__._(l, ()=>{ let { turnstile: e } = window; return { getResponse () { if (!e?.getResponse || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } return e.getResponse(V.current); }, async getResponsePromise (e = 3e4, t = 100) { return new Promise((n, r)=>{ let i, a = async ()=>{ if (H.current && window.turnstile && V.current) try { let e = window.turnstile.getResponse(V.current); return i && clearTimeout(i), e ? n(e) : r(Error(`No response received`)); } catch (e) { return i && clearTimeout(i), console.warn(`Failed to get response`, e), r(Error(`Failed to get response`)); } i ||= setTimeout(()=>{ i && clearTimeout(i), r(Error(`Timeout`)); }, e), await new Promise((e)=>setTimeout(e, t)), await a(); }; a(); }); }, reset () { if (!e?.reset || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } d.execution === `execute` && L(h.invisible); try { H.current = !1, e.reset(V.current); } catch (e) { console.warn(`Failed to reset Turnstile widget ${V.current}`, e); } }, remove () { if (!e?.remove || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } L(h.invisible), H.current = !1, e.remove(V.current), V.current = null; }, render () { if (!e?.render || !R.current || !X() || V.current) { console.warn(`Turnstile has not been loaded or container not found`); return; } let t = e.render(R.current, Y); return V.current = t, V.current && p?.(V.current), d.execution !== `execute` && L(P ? h[P] : {}), t; }, execute () { if (d.execution !== `execute`) { console.warn(`Execution mode is not set to "execute"`); return; } if (!e?.execute || !R.current || !V.current || !X()) { console.warn(`Turnstile has not been loaded or container not found`); return; } e.execute(R.current, Y), L(P ? h[P] : {}); }, isExpired () { return !e?.isExpired || !V.current || !X() ? (console.warn(`Turnstile has not been loaded`), !1) : e.isExpired(V.current); } }; }, [ V, d.execution, P, Y, R, X, z, p ]), __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ if (z || !K) return; if (window.turnstile) { B(!0); return; } let e = setInterval(()=>{ window.turnstile && (B(!0), clearInterval(e)); }, 50); return ()=>{ clearInterval(e); }; }, [ z, K ]), __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ L(F()); }, [ d.execution, P, J ]), __WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ !K || typeof D != `function` || D(); }, [ K ]), __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(c, { ref: R, as: A, id: U, style: { ...I, ...k }, ...N }); }); S.displayName = `Turnstile`; {"finalSource":false}mapbufferedMap ReplaceSourceRawSource'/* __next_internal_client_entry_do_not_use__ DEFAULT_CONTAINER_ID,DEFAULT_ONLOAD_NAME,DEFAULT_SCRIPT_ID,SCRIPT_URL,Turnstile auto */ import { forwardRef as e, useCallback as t, useEffect as n, useImperativeHandle as r, useMemo as i, useRef as a, useState as o } from "react"; import { jsx as s } from "react/jsx-runtime"; var c = /*#__PURE__*/ e(({ as: e = `div`, ...t }, n)=>s(e, { ...t, ref: n })); const l = `https://challenges.cloudflare.com/turnstile/v0/api.js`, u = `cf-turnstile-script`, d = `cf-turnstile`, f = `onloadTurnstileCallback`, p = (e)=>!!document.getElementById(e), m = ({ render: e = `explicit`, onLoadCallbackName: t = f, scriptOptions: { nonce: n = ``, defer: r = !0, async: i = !0, id: a = ``, appendTo: o, onError: s, crossOrigin: c = `` } = {} })=>{ let u = a || `cf-turnstile-script`; if (p(u)) return; let d = document.createElement(`script`); d.id = u, d.src = `${l}?onload=${t}&render=${e}`, !document.querySelector(`script[src="${d.src}"]`) && (d.defer = !!r, d.async = !!i, n && (d.nonce = n), c && (d.crossOrigin = c), s && (d.onerror = s, delete window[t]), (o === `body` ? document.body : document.getElementsByTagName(`head`)[0]).appendChild(d)); }, h = { normal: { width: 300, height: 65 }, compact: { width: 150, height: 140 }, invisible: { width: 0, height: 0, overflow: `hidden` }, flexible: { minWidth: 300, width: `100%`, height: 65 }, interactionOnly: { width: `fit-content`, height: `auto`, display: `flex` } }; function g(e) { if (e !== `invisible` && e !== `interactionOnly`) return e; } function _(e = u) { let [t, r] = o(!1); return process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && n(()=>{ let t = ()=>{ p(e) && r(!0); }, n = new MutationObserver(t); return n.observe(document, { childList: !0, subtree: !0 }), t(), ()=>{ n.disconnect(); }; }, [ e ]), t; } let v = `unloaded`, y; const b = new Promise((e, t)=>{ y = { resolve: e, reject: t }, v === `ready` && e(void 0); }), x = (e = f)=>(v === `unloaded` && (v = `loading`, window[e] = ()=>{ y.resolve(), v = `ready`, delete window[e]; }), b), S = /*#__PURE__*/ e((e, l)=>{ let { scriptOptions: u, options: d = {}, siteKey: f, onWidgetLoad: p, onSuccess: y, onExpire: b, onError: S, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E, onLoadScript: D, id: O, style: k, as: A = `div`, injectScript: j = !0, rerenderOnCallbackChange: M = !1, ...N } = e, P = d.size, F = t(()=>P === void 0 ? {} : d.execution === `execute` ? h.invisible : d.appearance === `interaction-only` ? h.interactionOnly : h[P], [ d.execution, P, d.appearance ]), [I, L] = o(F()), R = a(null), [z, B] = o(!1), V = a(void 0), H = a(!1), U = O || `cf-turnstile`, W = a({ onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); n(()=>{ M || (W.current = { onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); }); let G = u?.id || `cf-turnstile-script`, K = _(G), q = u?.onLoadCallbackName || `onloadTurnstileCallback`, J = d.appearance || `always`, Y = i(()=>({ sitekey: f, action: d.action, cData: d.cData, theme: d.theme || `auto`, language: d.language || `auto`, tabindex: d.tabIndex, "response-field": d.responseField, "response-field-name": d.responseFieldName, size: g(P), retry: d.retry || `auto`, "retry-interval": d.retryInterval || 8e3, "refresh-expired": d.refreshExpired || `auto`, "refresh-timeout": d.refreshTimeout || `auto`, execution: d.execution || `render`, appearance: d.appearance || `always`, "feedback-enabled": d.feedbackEnabled ?? !0, callback: (e)=>{ H.current = !0, M ? y?.(e) : W.current.onSuccess?.(e); }, "error-callback": M ? S : (...e)=>W.current.onError?.(...e), "expired-callback": M ? b : (...e)=>W.current.onExpire?.(...e), "before-interactive-callback": M ? C : (...e)=>W.current.onBeforeInteractive?.(...e), "after-interactive-callback": M ? w : (...e)=>W.current.onAfterInteractive?.(...e), "unsupported-callback": M ? T : (...e)=>W.current.onUnsupported?.(...e), "timeout-callback": M ? E : (...e)=>W.current.onTimeout?.(...e) }), [ d.action, d.appearance, d.cData, d.execution, d.language, d.refreshExpired, d.responseField, d.responseFieldName, d.retry, d.retryInterval, d.tabIndex, d.theme, d.feedbackEnabled, d.refreshTimeout, f, P, M, M ? y : null, M ? S : null, M ? b : null, M ? C : null, M ? w : null, M ? T : null, M ? E : null ]), X = t(()=>"undefined" < `u` && !!window.turnstile, []); return n(function() { j && !z && (x(q), m({ onLoadCallbackName: q, scriptOptions: { ...u, id: G } })); }, [ j, z, u, G, q ]), n(function() { v !== `ready` && x(q).then(()=>B(!0)).catch(console.error); }, [ q ]), n(function() { if (!R.current || !z) return; let e = !1; return (async ()=>{ e || !R.current || (V.current = window.turnstile.render(R.current, Y), V.current && p?.(V.current)); })(), ()=>{ e = !0, V.current && (window.turnstile.remove(V.current), H.current = !1); }; }, [ U, z, Y ]), r(l, ()=>{ let { turnstile: e } = window; return { getResponse () { if (!e?.getResponse || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } return e.getResponse(V.current); }, async getResponsePromise (e = 3e4, t = 100) { return new Promise((n, r)=>{ let i, a = async ()=>{ if (H.current && window.turnstile && V.current) try { let e = window.turnstile.getResponse(V.current); return i && clearTimeout(i), e ? n(e) : r(Error(`No response received`)); } catch (e) { return i && clearTimeout(i), console.warn(`Failed to get response`, e), r(Error(`Failed to get response`)); } i ||= setTimeout(()=>{ i && clearTimeout(i), r(Error(`Timeout`)); }, e), await new Promise((e)=>setTimeout(e, t)), await a(); }; a(); }); }, reset () { if (!e?.reset || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } d.execution === `execute` && L(h.invisible); try { H.current = !1, e.reset(V.current); } catch (e) { console.warn(`Failed to reset Turnstile widget ${V.current}`, e); } }, remove () { if (!e?.remove || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } L(h.invisible), H.current = !1, e.remove(V.current), V.current = null; }, render () { if (!e?.render || !R.current || !X() || V.current) { console.warn(`Turnstile has not been loaded or container not found`); return; } let t = e.render(R.current, Y); return V.current = t, V.current && p?.(V.current), d.execution !== `execute` && L(P ? h[P] : {}), t; }, execute () { if (d.execution !== `execute`) { console.warn(`Execution mode is not set to "execute"`); return; } if (!e?.execute || !R.current || !V.current || !X()) { console.warn(`Turnstile has not been loaded or container not found`); return; } e.execute(R.current, Y), L(P ? h[P] : {}); }, isExpired () { return !e?.isExpired || !V.current || !X() ? (console.warn(`Turnstile has not been loaded`), !1) : e.isExpired(V.current); } }; }, [ V, d.execution, P, Y, R, X, z, p ]), n(()=>{ if (z || !K) return; if (window.turnstile) { B(!0); return; } let e = setInterval(()=>{ window.turnstile && (B(!0), clearInterval(e)); }, 50); return ()=>{ clearInterval(e); }; }, [ z, K ]), n(()=>{ L(F()); }, [ d.execution, P, J ]), n(()=>{ !K || typeof D != `function` || D(); }, [ K ]), s(c, { ref: R, as: A, id: U, style: { ...I, ...k }, ...N }); }); S.displayName = `Turnstile`; export { d as DEFAULT_CONTAINER_ID, f as DEFAULT_ONLOAD_NAME, u as DEFAULT_SCRIPT_ID, l as SCRIPT_URL, S as Turnstile };  133274undefined276320undefined344344__WEBPACK_MODULE_REFERENCE__1_5b22666f7277617264526566225d_call_directImport_asiSafe1__._undefined376376__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined519518(/* unused pure expression or super */ null && (undefined533532))undefined17541754__WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._undefined18231823__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined23942394__WEBPACK_MODULE_REFERENCE__1_5b22666f7277617264526566225d_call_directImport_asiSafe1__._undefined27312731__WEBPACK_MODULE_REFERENCE__1_5b2275736543616c6c6261636b225d_call_directImport_asiSafe1__._undefined29352935__WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._undefined29472947__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined29652965__WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._undefined29762976__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined29912991__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined30273027__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined32163216__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined36173617__WEBPACK_MODULE_REFERENCE__1_5b227573654d656d6f225d_call_directImport_asiSafe1__._undefined54575457__WEBPACK_MODULE_REFERENCE__1_5b2275736543616c6c6261636b225d_call_directImport_asiSafe1__._undefined54635479 falseundefined548455010undefined55205520__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined57715771__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined58815881__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined62626262__WEBPACK_MODULE_REFERENCE__1_5b22757365496d706572617469766548616e646c65225d_call_directImport_asiSafe1__._undefined94499449__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined97769776__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined98599859__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined99399939__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1010910228undefined`__G u @ L  ]l0C&V)M$z>%**5,,,4---(0,react.forwardRef)(0,react_jsx_runtime.jsx)(0,react.useState)(0,react.useEffect)(0,react.useCallback)(0,react.useRef)(0,react.useMemo)(0,react.useImperativeHandle)$ ;// ./src/components/Turnstile.tsx  pwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* __next_internal_client_entry_do_not_use__ CAPTCHA_ENABLED,TurnstileWidget auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { Turnstile } from '@marsidev/react-turnstile'; const SITE_KEY = process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ?? ''; /** false in dev when NEXT_PUBLIC_TURNSTILE_SITE_KEY is not set */ export const CAPTCHA_ENABLED = !!SITE_KEY; export function TurnstileWidget({ onSuccess, onError, onExpire }) { if (!SITE_KEY) return null; return /*#__PURE__*/ _jsx(Turnstile, { siteKey: SITE_KEY, onSuccess: onSuccess, onError: onError, onExpire: onExpire, options: { theme: 'light', language: 'auto' } }); } `UNCInt"0x4AAAAAAC_FtTQJ0_6Cp9-9"0__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b225475726e7374696c65225d_directImport_asiSafe1__._/* __next_internal_client_entry_do_not_use__ CAPTCHA_ENABLED,TurnstileWidget auto */ const SITE_KEY = "0x4AAAAAAC_FtTQJ0_6Cp9-9" ?? 0; /** false in dev when NEXT_PUBLIC_TURNSTILE_SITE_KEY is not set */ const CAPTCHA_ENABLED = !!SITE_KEY; function TurnstileWidget({ onSuccess, onError, onExpire }) { if (!SITE_KEY) return null; return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__2_5b225475726e7374696c65225d_directImport_asiSafe1__._, { siteKey: SITE_KEY, onSuccess: onSuccess, onError: onError, onExpire: onExpire, options: { theme: 'light', language: 'auto' } }); }  /* __next_internal_client_entry_do_not_use__ CAPTCHA_ENABLED,TurnstileWidget auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { Turnstile } from '@marsidev/react-turnstile'; const SITE_KEY = process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY ?? ''; /** false in dev when NEXT_PUBLIC_TURNSTILE_SITE_KEY is not set */ export const CAPTCHA_ENABLED = !!SITE_KEY; export function TurnstileWidget({ onSuccess, onError, onExpire }) { if (!SITE_KEY) return null; return /*#__PURE__*/ _jsx(Turnstile, { siteKey: SITE_KEY, onSuccess: onSuccess, onError: onError, onExpire: onExpire, options: { theme: 'light', language: 'auto' } }); } /85132undefined134187undefined206247"0x4AAAAAAC_FtTQJ0_6Cp9-9"undefined2522530undefined323329undefined366372undefined491494__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined496504__WEBPACK_MODULE_REFERENCE__2_5b225475726e7374696c65225d_directImport_asiSafe1__._undefinedCfS - // EXPORTS __webpack_require__.d(__webpack_exports__, { l: () => (/* binding */ CAPTCHA_ENABLED), $: () => (/* binding */ TurnstileWidget) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); ;// ../../node_modules/@marsidev/react-turnstile/dist/index.js /* __next_internal_client_entry_do_not_use__ DEFAULT_CONTAINER_ID,DEFAULT_ONLOAD_NAME,DEFAULT_SCRIPT_ID,SCRIPT_URL,Turnstile auto */ var c = /*#__PURE__*/ (0,react.forwardRef)(({ as: e = `div`, ...t }, n)=>(0,react_jsx_runtime.jsx)(e, { ...t, ref: n })); const l = `https://challenges.cloudflare.com/turnstile/v0/api.js`, u = `cf-turnstile-script`, d = (/* unused pure expression or super */ null && (`cf-turnstile`)), f = `onloadTurnstileCallback`, p = (e)=>!!document.getElementById(e), m = ({ render: e = `explicit`, onLoadCallbackName: t = f, scriptOptions: { nonce: n = ``, defer: r = !0, async: i = !0, id: a = ``, appendTo: o, onError: s, crossOrigin: c = `` } = {} })=>{ let u = a || `cf-turnstile-script`; if (p(u)) return; let d = document.createElement(`script`); d.id = u, d.src = `${l}?onload=${t}&render=${e}`, !document.querySelector(`script[src="${d.src}"]`) && (d.defer = !!r, d.async = !!i, n && (d.nonce = n), c && (d.crossOrigin = c), s && (d.onerror = s, delete window[t]), (o === `body` ? document.body : document.getElementsByTagName(`head`)[0]).appendChild(d)); }, h = { normal: { width: 300, height: 65 }, compact: { width: 150, height: 140 }, invisible: { width: 0, height: 0, overflow: `hidden` }, flexible: { minWidth: 300, width: `100%`, height: 65 }, interactionOnly: { width: `fit-content`, height: `auto`, display: `flex` } }; function g(e) { if (e !== `invisible` && e !== `interactionOnly`) return e; } function _(e = u) { let [t, r] = (0,react.useState)(!1); return process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ let t = ()=>{ p(e) && r(!0); }, n = new MutationObserver(t); return n.observe(document, { childList: !0, subtree: !0 }), t(), ()=>{ n.disconnect(); }; }, [ e ]), t; } let v = `unloaded`, y; const b = new Promise((e, t)=>{ y = { resolve: e, reject: t }, v === `ready` && e(void 0); }), x = (e = f)=>(v === `unloaded` && (v = `loading`, window[e] = ()=>{ y.resolve(), v = `ready`, delete window[e]; }), b), S = /*#__PURE__*/ (0,react.forwardRef)((e, l)=>{ let { scriptOptions: u, options: d = {}, siteKey: f, onWidgetLoad: p, onSuccess: y, onExpire: b, onError: S, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E, onLoadScript: D, id: O, style: k, as: A = `div`, injectScript: j = !0, rerenderOnCallbackChange: M = !1, ...N } = e, P = d.size, F = (0,react.useCallback)(()=>P === void 0 ? {} : d.execution === `execute` ? h.invisible : d.appearance === `interaction-only` ? h.interactionOnly : h[P], [ d.execution, P, d.appearance ]), [I, L] = (0,react.useState)(F()), R = (0,react.useRef)(null), [z, B] = (0,react.useState)(!1), V = (0,react.useRef)(void 0), H = (0,react.useRef)(!1), U = O || `cf-turnstile`, W = (0,react.useRef)({ onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); (0,react.useEffect)(()=>{ M || (W.current = { onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); }); let G = u?.id || `cf-turnstile-script`, K = _(G), q = u?.onLoadCallbackName || `onloadTurnstileCallback`, J = d.appearance || `always`, Y = (0,react.useMemo)(()=>({ sitekey: f, action: d.action, cData: d.cData, theme: d.theme || `auto`, language: d.language || `auto`, tabindex: d.tabIndex, "response-field": d.responseField, "response-field-name": d.responseFieldName, size: g(P), retry: d.retry || `auto`, "retry-interval": d.retryInterval || 8e3, "refresh-expired": d.refreshExpired || `auto`, "refresh-timeout": d.refreshTimeout || `auto`, execution: d.execution || `render`, appearance: d.appearance || `always`, "feedback-enabled": d.feedbackEnabled ?? !0, callback: (e)=>{ H.current = !0, M ? y?.(e) : W.current.onSuccess?.(e); }, "error-callback": M ? S : (...e)=>W.current.onError?.(...e), "expired-callback": M ? b : (...e)=>W.current.onExpire?.(...e), "before-interactive-callback": M ? C : (...e)=>W.current.onBeforeInteractive?.(...e), "after-interactive-callback": M ? w : (...e)=>W.current.onAfterInteractive?.(...e), "unsupported-callback": M ? T : (...e)=>W.current.onUnsupported?.(...e), "timeout-callback": M ? E : (...e)=>W.current.onTimeout?.(...e) }), [ d.action, d.appearance, d.cData, d.execution, d.language, d.refreshExpired, d.responseField, d.responseFieldName, d.retry, d.retryInterval, d.tabIndex, d.theme, d.feedbackEnabled, d.refreshTimeout, f, P, M, M ? y : null, M ? S : null, M ? b : null, M ? C : null, M ? w : null, M ? T : null, M ? E : null ]), X = (0,react.useCallback)(()=> false && 0, []); return (0,react.useEffect)(function() { j && !z && (x(q), m({ onLoadCallbackName: q, scriptOptions: { ...u, id: G } })); }, [ j, z, u, G, q ]), (0,react.useEffect)(function() { v !== `ready` && x(q).then(()=>B(!0)).catch(console.error); }, [ q ]), (0,react.useEffect)(function() { if (!R.current || !z) return; let e = !1; return (async ()=>{ e || !R.current || (V.current = window.turnstile.render(R.current, Y), V.current && p?.(V.current)); })(), ()=>{ e = !0, V.current && (window.turnstile.remove(V.current), H.current = !1); }; }, [ U, z, Y ]), (0,react.useImperativeHandle)(l, ()=>{ let { turnstile: e } = window; return { getResponse () { if (!e?.getResponse || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } return e.getResponse(V.current); }, async getResponsePromise (e = 3e4, t = 100) { return new Promise((n, r)=>{ let i, a = async ()=>{ if (H.current && window.turnstile && V.current) try { let e = window.turnstile.getResponse(V.current); return i && clearTimeout(i), e ? n(e) : r(Error(`No response received`)); } catch (e) { return i && clearTimeout(i), console.warn(`Failed to get response`, e), r(Error(`Failed to get response`)); } i ||= setTimeout(()=>{ i && clearTimeout(i), r(Error(`Timeout`)); }, e), await new Promise((e)=>setTimeout(e, t)), await a(); }; a(); }); }, reset () { if (!e?.reset || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } d.execution === `execute` && L(h.invisible); try { H.current = !1, e.reset(V.current); } catch (e) { console.warn(`Failed to reset Turnstile widget ${V.current}`, e); } }, remove () { if (!e?.remove || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } L(h.invisible), H.current = !1, e.remove(V.current), V.current = null; }, render () { if (!e?.render || !R.current || !X() || V.current) { console.warn(`Turnstile has not been loaded or container not found`); return; } let t = e.render(R.current, Y); return V.current = t, V.current && p?.(V.current), d.execution !== `execute` && L(P ? h[P] : {}), t; }, execute () { if (d.execution !== `execute`) { console.warn(`Execution mode is not set to "execute"`); return; } if (!e?.execute || !R.current || !V.current || !X()) { console.warn(`Turnstile has not been loaded or container not found`); return; } e.execute(R.current, Y), L(P ? h[P] : {}); }, isExpired () { return !e?.isExpired || !V.current || !X() ? (console.warn(`Turnstile has not been loaded`), !1) : e.isExpired(V.current); } }; }, [ V, d.execution, P, Y, R, X, z, p ]), (0,react.useEffect)(()=>{ if (z || !K) return; if (window.turnstile) { B(!0); return; } let e = setInterval(()=>{ window.turnstile && (B(!0), clearInterval(e)); }, 50); return ()=>{ clearInterval(e); }; }, [ z, K ]), (0,react.useEffect)(()=>{ L(F()); }, [ d.execution, P, J ]), (0,react.useEffect)(()=>{ !K || typeof D != `function` || D(); }, [ K ]), (0,react_jsx_runtime.jsx)(c, { ref: R, as: A, id: U, style: { ...I, ...k }, ...N }); }); S.displayName = `Turnstile`; ;// ./src/components/Turnstile.tsx /* __next_internal_client_entry_do_not_use__ CAPTCHA_ENABLED,TurnstileWidget auto */ const SITE_KEY = "0x4AAAAAAC_FtTQJ0_6Cp9-9" ?? 0; /** false in dev when NEXT_PUBLIC_TURNSTILE_SITE_KEY is not set */ const CAPTCHA_ENABLED = !!SITE_KEY; function TurnstileWidget({ onSuccess, onError, onExpire }) { if (!SITE_KEY) return null; return /*#__PURE__*/ (0,react_jsx_runtime.jsx)(S, { siteKey: SITE_KEY, onSuccess: onSuccess, onError: onError, onExpire: onExpire, options: { theme: 'light', language: 'auto' } }); }    `  // EXPORTS __webpack_require__.d(__webpack_exports__, { l: () => (/* binding */ CAPTCHA_ENABLED), $: () => (/* binding */ TurnstileWidget) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); ;// ../../node_modules/@marsidev/react-turnstile/dist/index.js u'/* __next_internal_client_entry_do_not_use__ DEFAULT_CONTAINER_ID,DEFAULT_ONLOAD_NAME,DEFAULT_SCRIPT_ID,SCRIPT_URL,Turnstile auto */ import { forwardRef as e, useCallback as t, useEffect as n, useImperativeHandle as r, useMemo as i, useRef as a, useState as o } from "react"; import { jsx as s } from "react/jsx-runtime"; var c = /*#__PURE__*/ e(({ as: e = `div`, ...t }, n)=>s(e, { ...t, ref: n })); const l = `https://challenges.cloudflare.com/turnstile/v0/api.js`, u = `cf-turnstile-script`, d = `cf-turnstile`, f = `onloadTurnstileCallback`, p = (e)=>!!document.getElementById(e), m = ({ render: e = `explicit`, onLoadCallbackName: t = f, scriptOptions: { nonce: n = ``, defer: r = !0, async: i = !0, id: a = ``, appendTo: o, onError: s, crossOrigin: c = `` } = {} })=>{ let u = a || `cf-turnstile-script`; if (p(u)) return; let d = document.createElement(`script`); d.id = u, d.src = `${l}?onload=${t}&render=${e}`, !document.querySelector(`script[src="${d.src}"]`) && (d.defer = !!r, d.async = !!i, n && (d.nonce = n), c && (d.crossOrigin = c), s && (d.onerror = s, delete window[t]), (o === `body` ? document.body : document.getElementsByTagName(`head`)[0]).appendChild(d)); }, h = { normal: { width: 300, height: 65 }, compact: { width: 150, height: 140 }, invisible: { width: 0, height: 0, overflow: `hidden` }, flexible: { minWidth: 300, width: `100%`, height: 65 }, interactionOnly: { width: `fit-content`, height: `auto`, display: `flex` } }; function g(e) { if (e !== `invisible` && e !== `interactionOnly`) return e; } function _(e = u) { let [t, r] = o(!1); return process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && n(()=>{ let t = ()=>{ p(e) && r(!0); }, n = new MutationObserver(t); return n.observe(document, { childList: !0, subtree: !0 }), t(), ()=>{ n.disconnect(); }; }, [ e ]), t; } let v = `unloaded`, y; const b = new Promise((e, t)=>{ y = { resolve: e, reject: t }, v === `ready` && e(void 0); }), x = (e = f)=>(v === `unloaded` && (v = `loading`, window[e] = ()=>{ y.resolve(), v = `ready`, delete window[e]; }), b), S = /*#__PURE__*/ e((e, l)=>{ let { scriptOptions: u, options: d = {}, siteKey: f, onWidgetLoad: p, onSuccess: y, onExpire: b, onError: S, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E, onLoadScript: D, id: O, style: k, as: A = `div`, injectScript: j = !0, rerenderOnCallbackChange: M = !1, ...N } = e, P = d.size, F = t(()=>P === void 0 ? {} : d.execution === `execute` ? h.invisible : d.appearance === `interaction-only` ? h.interactionOnly : h[P], [ d.execution, P, d.appearance ]), [I, L] = o(F()), R = a(null), [z, B] = o(!1), V = a(void 0), H = a(!1), U = O || `cf-turnstile`, W = a({ onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); n(()=>{ M || (W.current = { onSuccess: y, onError: S, onExpire: b, onBeforeInteractive: C, onAfterInteractive: w, onUnsupported: T, onTimeout: E }); }); let G = u?.id || `cf-turnstile-script`, K = _(G), q = u?.onLoadCallbackName || `onloadTurnstileCallback`, J = d.appearance || `always`, Y = i(()=>({ sitekey: f, action: d.action, cData: d.cData, theme: d.theme || `auto`, language: d.language || `auto`, tabindex: d.tabIndex, "response-field": d.responseField, "response-field-name": d.responseFieldName, size: g(P), retry: d.retry || `auto`, "retry-interval": d.retryInterval || 8e3, "refresh-expired": d.refreshExpired || `auto`, "refresh-timeout": d.refreshTimeout || `auto`, execution: d.execution || `render`, appearance: d.appearance || `always`, "feedback-enabled": d.feedbackEnabled ?? !0, callback: (e)=>{ H.current = !0, M ? y?.(e) : W.current.onSuccess?.(e); }, "error-callback": M ? S : (...e)=>W.current.onError?.(...e), "expired-callback": M ? b : (...e)=>W.current.onExpire?.(...e), "before-interactive-callback": M ? C : (...e)=>W.current.onBeforeInteractive?.(...e), "after-interactive-callback": M ? w : (...e)=>W.current.onAfterInteractive?.(...e), "unsupported-callback": M ? T : (...e)=>W.current.onUnsupported?.(...e), "timeout-callback": M ? E : (...e)=>W.current.onTimeout?.(...e) }), [ d.action, d.appearance, d.cData, d.execution, d.language, d.refreshExpired, d.responseField, d.responseFieldName, d.retry, d.retryInterval, d.tabIndex, d.theme, d.feedbackEnabled, d.refreshTimeout, f, P, M, M ? y : null, M ? S : null, M ? b : null, M ? C : null, M ? w : null, M ? T : null, M ? E : null ]), X = t(()=>"undefined" < `u` && !!window.turnstile, []); return n(function() { j && !z && (x(q), m({ onLoadCallbackName: q, scriptOptions: { ...u, id: G } })); }, [ j, z, u, G, q ]), n(function() { v !== `ready` && x(q).then(()=>B(!0)).catch(console.error); }, [ q ]), n(function() { if (!R.current || !z) return; let e = !1; return (async ()=>{ e || !R.current || (V.current = window.turnstile.render(R.current, Y), V.current && p?.(V.current)); })(), ()=>{ e = !0, V.current && (window.turnstile.remove(V.current), H.current = !1); }; }, [ U, z, Y ]), r(l, ()=>{ let { turnstile: e } = window; return { getResponse () { if (!e?.getResponse || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } return e.getResponse(V.current); }, async getResponsePromise (e = 3e4, t = 100) { return new Promise((n, r)=>{ let i, a = async ()=>{ if (H.current && window.turnstile && V.current) try { let e = window.turnstile.getResponse(V.current); return i && clearTimeout(i), e ? n(e) : r(Error(`No response received`)); } catch (e) { return i && clearTimeout(i), console.warn(`Failed to get response`, e), r(Error(`Failed to get response`)); } i ||= setTimeout(()=>{ i && clearTimeout(i), r(Error(`Timeout`)); }, e), await new Promise((e)=>setTimeout(e, t)), await a(); }; a(); }); }, reset () { if (!e?.reset || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } d.execution === `execute` && L(h.invisible); try { H.current = !1, e.reset(V.current); } catch (e) { console.warn(`Failed to reset Turnstile widget ${V.current}`, e); } }, remove () { if (!e?.remove || !V.current || !X()) { console.warn(`Turnstile has not been loaded`); return; } L(h.invisible), H.current = !1, e.remove(V.current), V.current = null; }, render () { if (!e?.render || !R.current || !X() || V.current) { console.warn(`Turnstile has not been loaded or container not found`); return; } let t = e.render(R.current, Y); return V.current = t, V.current && p?.(V.current), d.execution !== `execute` && L(P ? h[P] : {}), t; }, execute () { if (d.execution !== `execute`) { console.warn(`Execution mode is not set to "execute"`); return; } if (!e?.execute || !R.current || !V.current || !X()) { console.warn(`Turnstile has not been loaded or container not found`); return; } e.execute(R.current, Y), L(P ? h[P] : {}); }, isExpired () { return !e?.isExpired || !V.current || !X() ? (console.warn(`Turnstile has not been loaded`), !1) : e.isExpired(V.current); } }; }, [ V, d.execution, P, Y, R, X, z, p ]), n(()=>{ if (z || !K) return; if (window.turnstile) { B(!0); return; } let e = setInterval(()=>{ window.turnstile && (B(!0), clearInterval(e)); }, 50); return ()=>{ clearInterval(e); }; }, [ z, K ]), n(()=>{ L(F()); }, [ d.execution, P, J ]), n(()=>{ !K || typeof D != `function` || D(); }, [ K ]), s(c, { ref: R, as: A, id: U, style: { ...I, ...k }, ...N }); }); S.displayName = `Turnstile`; export { d as DEFAULT_CONTAINER_ID, f as DEFAULT_ONLOAD_NAME, u as DEFAULT_SCRIPT_ID, l as SCRIPT_URL, S as Turnstile };  133274undefined276320undefined344344__WEBPACK_MODULE_REFERENCE__1_5b22666f7277617264526566225d_call_directImport_asiSafe1__._undefined376376__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined519518(/* unused pure expression or super */ null && (undefined533532))undefined17541754__WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._undefined18231823__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined23942394__WEBPACK_MODULE_REFERENCE__1_5b22666f7277617264526566225d_call_directImport_asiSafe1__._undefined27312731__WEBPACK_MODULE_REFERENCE__1_5b2275736543616c6c6261636b225d_call_directImport_asiSafe1__._undefined29352935__WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._undefined29472947__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined29652965__WEBPACK_MODULE_REFERENCE__1_5b227573655374617465225d_call_directImport_asiSafe1__._undefined29762976__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined29912991__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined30273027__WEBPACK_MODULE_REFERENCE__1_5b22757365526566225d_call_directImport_asiSafe1__._undefined32163216__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined36173617__WEBPACK_MODULE_REFERENCE__1_5b227573654d656d6f225d_call_directImport_asiSafe1__._undefined54575457__WEBPACK_MODULE_REFERENCE__1_5b2275736543616c6c6261636b225d_call_directImport_asiSafe1__._undefined54635479 falseundefined548455010undefined55205520__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined57715771__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined58815881__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined62626262__WEBPACK_MODULE_REFERENCE__1_5b22757365496d706572617469766548616e646c65225d_call_directImport_asiSafe1__._undefined94499449__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined97769776__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined98599859__WEBPACK_MODULE_REFERENCE__1_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined99399939__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1010910228undefinedT157245(0,react.forwardRef)undefined277351(0,react_jsx_runtime.jsx)undefined17791863(0,react.useState)undefined19322018(0,react.useEffect)undefined25892677(0,react.forwardRef)undefined30143104(0,react.useCallback)undefined33083392(0,react.useState)undefined34043484(0,react.useRef)undefined35023586(0,react.useState)undefined35973677(0,react.useRef)undefined36923772(0,react.useRef)undefined38083888(0,react.useRef)undefined40774163(0,react.useEffect)undefined45644646(0,react.useMemo)undefined64866576(0,react.useCallback)undefined66116697(0,react.useEffect)undefined69487034(0,react.useEffect)undefined71447230(0,react.useEffect)undefined76117717(0,react.useImperativeHandle)undefined1090410990(0,react.useEffect)undefined1131711403(0,react.useEffect)undefined1148611572(0,react.useEffect)undefined1165211726(0,react_jsx_runtime.jsx)undefinedRawSource$ ;// ./src/components/Turnstile.tsx q/85132undefined134187undefined206247"0x4AAAAAAC_FtTQJ0_6Cp9-9"undefined2522530undefined323329undefined366372undefined491494__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined496504__WEBPACK_MODULE_REFERENCE__2_5b225475726e7374696c65225d_directImport_asiSafe1__._undefined8358432(0,react_jsx_runtime.jsx)undefined434515Sundefined `cludfpmhg_vybxSdist_namespaceObjectTurnstile_namespaceObject  <webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSource`webpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceb(() => { var exports = {}; exports.id = 784; exports.ids = [784]; exports.modules = { /***/ 261: webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource 'webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Hmodule.exports = require("next/dist/shared/lib/router/utils/app-paths");  /***/ }) buffersourcesizemapshashv/***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/router/utils/app-paths"); /***/ }) {"finalSource":true}mapbufferedMap ConcatSourceRawSource$/***/ ((module) => { "use strict";  RawSourceHmodule.exports = require("next/dist/shared/lib/router/utils/app-paths"); /***/ }), /***/ 3295:  <webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; ]module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js"); /***/ })  ]module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js");, /***/ 10846:  3webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Tmodule.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js"); /***/ })  Tmodule.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js");, /***/ 14691:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource>/***/ ((__unused_webpack_module, exports) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource Nwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcek"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getOrigin: null, resolveArray: null, resolveAsArrayOrUndefined: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map e :NNW@Object.defineProperty(exports, "__esModule", ())0buffersourcesizemapshash Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map {"finalSource":true}mapbufferedMap ReplaceSourceRawSourcek"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getOrigin: null, resolveArray: null, resolveAsArrayOrUndefined: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.mape012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined871870undefined /***/ }) D/***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map /***/ })  >/***/ ((__unused_webpack_module, exports) => { "use strict"; ReplaceSourceRawSourcek"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getOrigin: null, resolveArray: null, resolveAsArrayOrUndefined: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.mape012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined871870undefined, /***/ 14905:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource Awebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceconst APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; export default function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } e.3ILZ"http://canhelp.gr"0buffersourcesizemapshashconst APP_URL = "http://canhelp.gr" || 0; function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } {"finalSource":false}mapbufferedMap ReplaceSourceRawSourceconst APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; export default function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } ;1646"http://canhelp.gr"undefined51730undefined7690undefinedc // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__   webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* dynamic asset route */ import { NextResponse } from 'next/server' import handler from "/opt/canhelp/apps/web/src/app/robots.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const contentType = "text/plain" const fileType = "robots" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } export async function GET() { const data = await handler() const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } bCEL-3 ,7__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._-/* dynamic asset route */ const contentType = "text/plain" const fileType = "robots" if (typeof __WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__._ !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } async function GET() { const data = await __WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__._() const content = __WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._(data, fileType) return new __WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) }  /* dynamic asset route */ import { NextResponse } from 'next/server' import handler from "/opt/canhelp/apps/web/src/app/robots.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const contentType = "text/plain" const fileType = "robots" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } export async function GET() { const data = await handler() const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 2667undefined69129undefined131224undefined301307__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__._undefined430436undefined481487__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__._undefined509524__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined556567__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined`hF]+Krobots(0,resolve_route_data.resolveRouteData)server.NextResponse ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=!  fHwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceG=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map c;^`_%'np "_abd/_Aem<AB]TS - / 5 f z } O v ]k^k_$5Xmq$$$%`&m&+'8'((6(r*}*-,-..11224R444;5P5666688H9O9O:]::;L;<<__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._".next"0 false: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._false{}__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._A // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new __WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._({ definition: { kind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._ }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return __WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = __WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = __WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: __WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._(req); const nodeNextRes = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._(res); const nextReq = __WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._.fromNodeNextRequest(nodeNextReq, __WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== __WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = __WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(response.headers); if (cacheTags) { headers[__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = __WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(cacheEntry.value.headers); if (!(__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isIsr)) { headers.delete(__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', __WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._(cacheEntry.cacheControl)); } await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest, { spanName: `${method} ${req.url}`, kind: __WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map  G=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741442undefined15831601__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16371645__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18171852".next"undefined185718580undefined18851923 falseundefined21322131: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24372447__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25162605undefined26072613undefined29182938falseundefined29413005{}undefined31513190falseundefined37163731__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41894203__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50455053__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54705483__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60876101__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61376152__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61806197__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62326253__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68896902__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78807893__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93299353__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94519472__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98249837__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1002710040__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028010294__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1086610877__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1154611564__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200112009__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1255912573__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1303913052__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1347513501__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1354813561__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1362713648__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1396813988__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1404914060__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455214565__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1466414671__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1492714941__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516215180__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552215533__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined`"_%i@rP  x uUq_)[!n""<#_$$%&'S')),,..1c1533<555F6664888=9);w;;<=z=CW>>@t@module_compiled.AppRouteRouteModuleroute_kind.RouteKindnext_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject(0,patch_fetch.patchFetch)(0,app_paths_.normalizeAppPath)no_fallback_error_external_.NoFallbackError(0,trace_tracer.getTracer)(0,request_meta.getRequestMeta)node.NodeNextRequestnode.NodeNextResponsenext_request.NextRequestAdapter(0,next_request.signalFromNodeResponse)constants.BaseServerSpan(0,web_utils.toNodeOutgoingHttpHeaders)lib_constants.NEXT_CACHE_TAGS_HEADERlib_constants.INFINITE_CACHEresponse_cache.CachedRouteKind(0,send_response/* sendResponse */.I)(0,utils/* getRevalidateReason */.c)(0,web_utils.fromNodeOutgoingHttpHeaders)(0,cache_control.getCacheControlHeader)trace_tracer.SpanKindbuffersourcesizemapshash4M// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts const APP_URL = "http://canhelp.gr" || 0; function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ /* dynamic asset route */ const contentType = "text/plain" const fileType = "robots" if (typeof robots !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } async function GET() { const data = await robots() const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map {"finalSource":true}mapbufferedMap `ConcatSourceRawSource // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts  ReplaceSourceReplaceSourceRawSourceconst APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; export default function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } ;1646"http://canhelp.gr"undefined51730undefined7690undefined RawSourcec // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ /* dynamic asset route */ import { NextResponse } from 'next/server' import handler from "/opt/canhelp/apps/web/src/app/robots.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const contentType = "text/plain" const fileType = "robots" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } export async function GET() { const data = await handler() const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 2667undefined69129undefined131224undefined301307__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__._undefined430436undefined481487__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__._undefined509524__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined556567__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined104182robotsundefined349432robotsundefined454555(0,resolve_route_data.resolveRouteData)undefined587675server.NextResponseundefinedRawSource ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! G=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741442undefined15831601__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16371645__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18171852".next"undefined185718580undefined18851923 falseundefined21322131: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24372447__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25162605undefined26072613undefined29182938falseundefined29413005{}undefined31513190falseundefined37163731__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41894203__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50455053__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54705483__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60876101__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61376152__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61806197__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62326253__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68896902__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78807893__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93299353__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94519472__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98249837__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1002710040__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028010294__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1086610877__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1154611564__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200112009__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1255912573__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1303913052__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1347513501__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1354813561__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1362713648__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1396813988__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1404914060__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455214565__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1466414671__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1492714941__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516215180__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552215533__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined156257module_compiled.AppRouteRouteModuleundefined293361route_kind.RouteKindundefined787832next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectundefined11381226(0,patch_fetch.patchFetch)undefined22842384(0,app_paths_.normalizeAppPath)undefined28422936no_fallback_error_external_.NoFallbackErrorundefined37783864(0,trace_tracer.getTracer)undefined42814377(0,request_meta.getRequestMeta)undefined49815074node.NodeNextRequestundefined51105205node.NodeNextResponseundefined52335324next_request.NextRequestAdapterundefined53595471(0,next_request.signalFromNodeResponse)undefined61076185constants.BaseServerSpanundefined71637259(0,request_meta.getRequestMeta)undefined86958814(0,web_utils.toNodeOutgoingHttpHeaders)undefined89129020lib_constants.NEXT_CACHE_TAGS_HEADERundefined93729464lib_constants.INFINITE_CACHEundefined96549746lib_constants.INFINITE_CACHEundefined998610067response_cache.CachedRouteKindundefined1063910732(0,send_response/* sendResponse */.I)undefined1140111507(0,utils/* getRevalidateReason */.c)undefined1194412012route_kind.RouteKindundefined1256212643response_cache.CachedRouteKindundefined1310913205(0,request_meta.getRequestMeta)undefined1362813751(0,web_utils.fromNodeOutgoingHttpHeaders)undefined1379813894(0,request_meta.getRequestMeta)undefined1396014068lib_constants.NEXT_CACHE_TAGS_HEADERundefined1438814499(0,cache_control.getCacheControlHeader)undefined1456014653(0,send_response/* sendResponse */.I)undefined1514515223constants.BaseServerSpanundefined1532215388trace_tracer.SpanKindundefined1564415738no_fallback_error_external_.NoFallbackErrorundefined1595916065(0,utils/* getRevalidateReason */.c)undefined1640716500(0,send_response/* sendResponse */.I)undefined /***/ }) M/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts const APP_URL = "http://canhelp.gr" || 0; function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ /* dynamic asset route */ const contentType = "text/plain" const fileType = "robots" if (typeof robots !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } async function GET() { const data = await robots() const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map /***/ })  `_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict";  // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts  ReplaceSourceconst APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; export default function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } ;1646"http://canhelp.gr"undefined51730undefined7690undefinedc // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ /* dynamic asset route */ import { NextResponse } from 'next/server' import handler from "/opt/canhelp/apps/web/src/app/robots.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const contentType = "text/plain" const fileType = "robots" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } export async function GET() { const data = await handler() const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 2667undefined69129undefined131224undefined301307__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_directImport_asiSafe1__._undefined430436undefined481487__WEBPACK_MODULE_REFERENCE__17_5b2264656661756c74225d_call_directImport_asiSafe1__._undefined509524__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined556567__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined104182robotsundefined349432robotsundefined454555(0,resolve_route_data.resolveRouteData)undefined587675server.NextResponseundefinedRawSource ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! G=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741442undefined15831601__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16371645__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18171852".next"undefined185718580undefined18851923 falseundefined21322131: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24372447__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25162605undefined26072613undefined29182938falseundefined29413005{}undefined31513190falseundefined37163731__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41894203__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50455053__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54705483__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60876101__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61376152__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61806197__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62326253__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68896902__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78807893__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93299353__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94519472__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98249837__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1002710040__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028010294__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1086610877__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1154611564__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200112009__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1255912573__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1303913052__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1347513501__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1354813561__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1362713648__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1396813988__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1404914060__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455214565__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1466414671__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1492714941__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516215180__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552215533__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined156257module_compiled.AppRouteRouteModuleundefined293361route_kind.RouteKindundefined787832next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectundefined11381226(0,patch_fetch.patchFetch)undefined22842384(0,app_paths_.normalizeAppPath)undefined28422936no_fallback_error_external_.NoFallbackErrorundefined37783864(0,trace_tracer.getTracer)undefined42814377(0,request_meta.getRequestMeta)undefined49815074node.NodeNextRequestundefined51105205node.NodeNextResponseundefined52335324next_request.NextRequestAdapterundefined53595471(0,next_request.signalFromNodeResponse)undefined61076185constants.BaseServerSpanundefined71637259(0,request_meta.getRequestMeta)undefined86958814(0,web_utils.toNodeOutgoingHttpHeaders)undefined89129020lib_constants.NEXT_CACHE_TAGS_HEADERundefined93729464lib_constants.INFINITE_CACHEundefined96549746lib_constants.INFINITE_CACHEundefined998610067response_cache.CachedRouteKindundefined1063910732(0,send_response/* sendResponse */.I)undefined1140111507(0,utils/* getRevalidateReason */.c)undefined1194412012route_kind.RouteKindundefined1256212643response_cache.CachedRouteKindundefined1310913205(0,request_meta.getRequestMeta)undefined1362813751(0,web_utils.fromNodeOutgoingHttpHeaders)undefined1379813894(0,request_meta.getRequestMeta)undefined1396014068lib_constants.NEXT_CACHE_TAGS_HEADERundefined1438814499(0,cache_control.getCacheControlHeader)undefined1456014653(0,send_response/* sendResponse */.I)undefined1514515223constants.BaseServerSpanundefined1532215388trace_tracer.SpanKindundefined1564415738no_fallback_error_external_.NoFallbackErrorundefined1595916065(0,utils/* getRevalidateReason */.c)undefined1640716500(0,send_response/* sendResponse */.I)undefined, /***/ 19121:  8webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Ymodule.exports = require("next/dist/server/app-render/action-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/action-async-storage.external.js"); /***/ })  Ymodule.exports = require("next/dist/server/app-render/action-async-storage.external.js");, /***/ 23757:  \Vwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceS/***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { resolveManifest: null, resolveRobots: null, resolveRouteData: null, resolveSitemap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = require("../../../../lib/metadata/generate/utils"); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map e :NNWDObject.defineProperty(exports, "__esModule", ())0__webpack_require__14691buffersourcesizemapshash1 Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = __webpack_require__(14691); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map {"finalSource":true}mapbufferedMap ReplaceSourceRawSource"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { resolveManifest: null, resolveRobots: null, resolveRouteData: null, resolveSitemap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = require("../../../../lib/metadata/generate/utils"); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined872110undefined693699__webpack_require__undefined70174114691undefined /***/ }) /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = __webpack_require__(14691); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map /***/ })  S/***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { resolveManifest: null, resolveRobots: null, resolveRouteData: null, resolveSitemap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = require("../../../../lib/metadata/generate/utils"); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined872110undefined693699__webpack_require__undefined70174114691undefined, /***/ 29294:  6webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Wmodule.exports = require("next/dist/server/app-render/work-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-async-storage.external.js"); /***/ })  Wmodule.exports = require("next/dist/server/app-render/work-async-storage.external.js");, /***/ 44870:  4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Umodule.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js"); /***/ })  Umodule.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js");, /***/ 63033:  ;webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; \module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js"); /***/ })  \module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js");, /***/ 80408:  4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource buffersourcesizemapshash {"finalSource":true}mapbufferedMap ReplaceSourceRawSource /***/ }) /***/ (() => { /***/ })  /***/ (() => { , /***/ 86439:  +webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Lmodule.exports = require("next/dist/shared/lib/no-fallback-error.external");  /***/ }) z/***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/no-fallback-error.external"); /***/ })  Lmodule.exports = require("next/dist/shared/lib/no-fallback-error.external");, /***/ 87032:  4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource buffersourcesizemapshash {"finalSource":true}mapbufferedMap ReplaceSourceRawSource /***/ }) y {~ w }; ; // load runtime var __webpack_require__ = require("../../webpack-runtime.js"); __webpack_require__.C(exports); var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) var __webpack_exports__ = __webpack_require__.X(0, [901,825], () => (__webpack_exec__(14905))); ,module.exports = __webpack_exports__; })();  :t(() => { var exports = {}; exports.id = 784; exports.ids = [784]; exports.modules = { /***/ 261: /***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/router/utils/app-paths"); /***/ }), /***/ 3295: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js"); /***/ }), /***/ 10846: /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js"); /***/ }), /***/ 14691: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map /***/ }), /***/ 14905: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/robots.ts const APP_URL = "http://canhelp.gr" || 0; function robots() { return { rules: { userAgent: '*', allow: '/', disallow: [ '/admin/', '/dashboard/', '/profile/', '/chat/', '/notifications/', '/favorites/', '/schedule/', '/payment/' ] }, sitemap: `${APP_URL}/sitemap.xml` }; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__ /* dynamic asset route */ const contentType = "text/plain" const fileType = "robots" if (typeof robots !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/robots.ts"') } async function GET() { const data = await robots() const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Frobots.txt%2Froute&name=app%2Frobots.txt%2Froute&pagePath=private-next-app-dir%2Frobots.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Frobots&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/robots.txt/route", pathname: "/robots.txt", filename: "robots", bundlePath: "app/robots.txt/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Frobots_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/robots.txt/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map /***/ }), /***/ 19121: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/action-async-storage.external.js"); /***/ }), /***/ 23757: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = __webpack_require__(14691); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map /***/ }), /***/ 29294: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-async-storage.external.js"); /***/ }), /***/ 44870: /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js"); /***/ }), /***/ 63033: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js"); /***/ }), /***/ 80408: /***/ (() => { /***/ }), /***/ 86439: /***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/no-fallback-error.external"); /***/ }), /***/ 87032: /***/ (() => { /***/ }) }; ; // load runtime var __webpack_require__ = require("../../webpack-runtime.js"); __webpack_require__.C(exports); var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) var __webpack_exports__ = __webpack_require__.X(0, [901,825], () => (__webpack_exec__(14905))); module.exports = __webpack_exports__; })(); {}   @b(() => { var exports = {}; exports.id = 784; exports.ids = [784]; exports.modules = { /***/ 261: $/***/ ((module) => { "use strict"; aHmodule.exports = require("next/dist/shared/lib/router/utils/app-paths");` /***/ })_, /***/ 3295: ^]module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js");]], /***/ 10846: \Tmodule.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js");[[, /***/ 14691: >/***/ ((__unused_webpack_module, exports) => { "use strict"; k"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getOrigin: null, resolveArray: null, resolveAsArrayOrUndefined: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.mape012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined871870undefinedWW, /***/ 14905: _/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; RScTUVSWXYZS[\]UU, /***/ 19121: TYmodule.exports = require("next/dist/server/app-render/action-async-storage.external.js");SS, /***/ 23757: S/***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { resolveManifest: null, resolveRobots: null, resolveRouteData: null, resolveSitemap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = require("../../../../lib/metadata/generate/utils"); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined872110undefined693699__webpack_require__undefined70174114691undefinedOO, /***/ 29294: NWmodule.exports = require("next/dist/server/app-render/work-async-storage.external.js");MM, /***/ 44870: LUmodule.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js");KK, /***/ 63033: J\module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js");II, /***/ 80408: /***/ (() => { FF, /***/ 86439: ELmodule.exports = require("next/dist/shared/lib/no-fallback-error.external");DD, /***/ 87032: CCw }; ; // load runtime var __webpack_require__ = require("../../webpack-runtime.js"); __webpack_require__.C(exports); Bvar __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) var __webpack_exports__ = __webpack_require__.X(0, [901,825], () => (__webpack_exec__(14905))); A,module.exports = __webpack_exports__; })(); ̢webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSource`webpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceb(() => { var exports = {}; exports.id = 475; exports.ids = [475]; exports.modules = { /***/ 261: webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource 'webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Hmodule.exports = require("next/dist/shared/lib/router/utils/app-paths");  /***/ }) buffersourcesizemapshashv/***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/router/utils/app-paths"); /***/ }) {"finalSource":true}mapbufferedMap ConcatSourceRawSource$/***/ ((module) => { "use strict";  RawSourceHmodule.exports = require("next/dist/shared/lib/router/utils/app-paths"); /***/ }), /***/ 3295:  <webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; ]module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js"); /***/ })  ]module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js");, /***/ 10846:  3webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Tmodule.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js"); /***/ })  Tmodule.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js");, /***/ 14691:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource>/***/ ((__unused_webpack_module, exports) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource Nwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcek"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getOrigin: null, resolveArray: null, resolveAsArrayOrUndefined: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map e :NNW@Object.defineProperty(exports, "__esModule", ())0buffersourcesizemapshash Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map {"finalSource":true}mapbufferedMap ReplaceSourceRawSourcek"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getOrigin: null, resolveArray: null, resolveAsArrayOrUndefined: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.mape012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined871870undefined /***/ }) D/***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map /***/ })  >/***/ ((__unused_webpack_module, exports) => { "use strict"; ReplaceSourceRawSourcek"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { getOrigin: null, resolveArray: null, resolveAsArrayOrUndefined: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.mape012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined871870undefined, /***/ 19121:  8webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Ymodule.exports = require("next/dist/server/app-render/action-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/action-async-storage.external.js"); /***/ })  Ymodule.exports = require("next/dist/server/app-render/action-async-storage.external.js");, /***/ 23757:  \Vwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceS/***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { resolveManifest: null, resolveRobots: null, resolveRouteData: null, resolveSitemap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = require("../../../../lib/metadata/generate/utils"); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map e :NNWDObject.defineProperty(exports, "__esModule", ())0__webpack_require__14691buffersourcesizemapshash1 Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = __webpack_require__(14691); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map {"finalSource":true}mapbufferedMap ReplaceSourceRawSource"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { resolveManifest: null, resolveRobots: null, resolveRouteData: null, resolveSitemap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = require("../../../../lib/metadata/generate/utils"); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined872110undefined693699__webpack_require__undefined70174114691undefined /***/ }) /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = __webpack_require__(14691); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map /***/ })  S/***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { resolveManifest: null, resolveRobots: null, resolveRouteData: null, resolveSitemap: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = require("../../../../lib/metadata/generate/utils"); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map012undefined1458Object.defineProperty(exports, "__esModule", (undefined7878))undefined872110undefined693699__webpack_require__undefined70174114691undefined, /***/ 29294:  6webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Wmodule.exports = require("next/dist/server/app-render/work-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-async-storage.external.js"); /***/ })  Wmodule.exports = require("next/dist/server/app-render/work-async-storage.external.js");, /***/ 44870:  4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Umodule.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js"); /***/ })  Umodule.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js");, /***/ 63033:  ;webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; \module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js");  /***/ }) /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js"); /***/ })  \module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js");, /***/ 80408:  4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource buffersourcesizemapshash {"finalSource":true}mapbufferedMap ReplaceSourceRawSource /***/ }) /***/ (() => { /***/ })  /***/ (() => { , /***/ 83019:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource )webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource(// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource  webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } export default async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } f.3I\zB "http://canhelp.gr"0"https://api.canhelp.gr"0buffersourcesizemapshashI const APP_URL = "http://canhelp.gr" || 0; const API_URL = "https://api.canhelp.gr" || 0; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } {"finalSource":false}mapbufferedMap ReplaceSourceRawSource const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } export default async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } u1646"http://canhelp.gr"undefined51730undefined92122"https://api.canhelp.gr"undefined1271490undefined27202734undefinedd // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__  vwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceimport { NextResponse } from 'next/server' import * as userland from "/opt/canhelp/apps/web/src/app/sitemap.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const sitemapModule = { ...userland } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new NextResponse('Not Found', { status: 404, }) } if (process.env.NODE_ENV !== 'production' && sitemapModule.generateSitemaps) { const sitemaps = await sitemapModule.generateSitemaps() for (const item of sitemaps) { if (item?.id == null) { throw new Error('id property is required for every item returned from generateSitemaps') } } } const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) }  c)+npNHK;__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__.___WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._false{}__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._ const sitemapModule = { ...__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__._ } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new __WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._('Not Found', { status: 404, }) } if (false) {} const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = __WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._(data, fileType) return new __WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) }  import { NextResponse } from 'next/server' import * as userland from "/opt/canhelp/apps/web/src/app/sitemap.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const sitemapModule = { ...userland } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new NextResponse('Not Found', { status: 404, }) } if (process.env.NODE_ENV !== 'production' && sitemapModule.generateSitemaps) { const sitemaps = await sitemapModule.generateSitemaps() for (const item of sitemaps) { if (item?.id == null) { throw new Error('id property is required for every item returned from generateSitemaps') } } } const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 041undefined43110undefined112205undefined235242__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__._undefined494500undefined705716__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined770840falseundefined8431083{}undefined12231238__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined12701281__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefinedaLEl6sitemap_namespaceObjectserver.NextResponse(0,resolve_route_data.resolveRouteData) ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=!  mHwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceN=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map c;^`_%'np "_abd0_BfnAFGbZY 3 5 ; m V } drer_+<_tx$$$%g&t&2'?'/(=(y**!-3-..1$1234R445B5W5666688O9V9V:d:A;S;<<__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._".next"0 false: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._false{}__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._A // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new __WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._({ definition: { kind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._ }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return __WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._({ workAsyncStorage, workUnitAsyncStorage }); } async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = __WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = __WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: __WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._(req); const nodeNextRes = new __WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._(res); const nextReq = __WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._.fromNodeNextRequest(nodeNextReq, __WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== __WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = __WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(response.headers); if (cacheTags) { headers[__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= __WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._ ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: __WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== __WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = __WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._(cacheEntry.value.headers); if (!(__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._(req, 'minimalMode') && isIsr)) { headers.delete(__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', __WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._(cacheEntry.cacheControl)); } await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._.handleRequest, { spanName: `${method} ${req.url}`, kind: __WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof __WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: __WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await __WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map  N=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741443undefined15841602__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16381646__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18221857".next"undefined186218630undefined18901928 falseundefined21382137: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24432453__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25222611undefined26132619undefined29252945falseundefined29483012{}undefined31583197falseundefined37233738__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41964210__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50525060__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54775490__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60946108__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61446159__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61876204__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62396260__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68966909__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78877900__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93369360__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94589479__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98319844__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1003410047__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028710301__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1087310884__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1155311571__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200812016__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1256612580__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1304613059__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1348213508__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1355513568__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1363413655__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1397513995__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1405614067__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455914572__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1467114678__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1493414948__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516915187__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552915540__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined`#_%iEw$*V ~ {[we/a!t"_"B#$$%&'Y')),,..1i1;33B555L666:888C9/;};;"<E"==]>>@z@module_compiled.AppRouteRouteModuleroute_kind.RouteKindnext_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject(0,patch_fetch.patchFetch)nnext_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler(0,app_paths_.normalizeAppPath)no_fallback_error_external_.NoFallbackError(0,trace_tracer.getTracer)(0,request_meta.getRequestMeta)node.NodeNextRequestnode.NodeNextResponsenext_request.NextRequestAdapter(0,next_request.signalFromNodeResponse)constants.BaseServerSpan(0,web_utils.toNodeOutgoingHttpHeaders)lib_constants.NEXT_CACHE_TAGS_HEADERlib_constants.INFINITE_CACHEresponse_cache.CachedRouteKind(0,send_response/* sendResponse */.I)(0,utils/* getRevalidateReason */.c)(0,web_utils.fromNodeOutgoingHttpHeaders)(0,cache_control.getCacheControlHeader)trace_tracer.SpanKindbuffersourcesizemapshash[// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts const APP_URL = "http://canhelp.gr" || 0; const API_URL = "https://api.canhelp.gr" || 0; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ const sitemapModule = { ...sitemap_namespaceObject } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new server.NextResponse('Not Found', { status: 404, }) } if (false) {} const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map {"finalSource":true}mapbufferedMap `ConcatSourceRawSource(// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts  ReplaceSourceReplaceSourceRawSource const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } export default async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } u1646"http://canhelp.gr"undefined51730undefined92122"https://api.canhelp.gr"undefined1271490undefined27202734undefined RawSourced // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ import { NextResponse } from 'next/server' import * as userland from "/opt/canhelp/apps/web/src/app/sitemap.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const sitemapModule = { ...userland } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new NextResponse('Not Found', { status: 404, }) } if (process.env.NODE_ENV !== 'production' && sitemapModule.generateSitemaps) { const sitemaps = await sitemapModule.generateSitemaps() for (const item of sitemaps) { if (item?.id == null) { throw new Error('id property is required for every item returned from generateSitemaps') } } } const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 041undefined43110undefined112205undefined235242__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__._undefined494500undefined705716__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined770840falseundefined8431083{}undefined12231238__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined12701281__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined3176sitemap_namespaceObjectundefined532620server.NextResponseundefined822923(0,resolve_route_data.resolveRouteData)undefined9551043server.NextResponseundefinedRawSource ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! N=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741443undefined15841602__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16381646__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18221857".next"undefined186218630undefined18901928 falseundefined21382137: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24432453__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25222611undefined26132619undefined29252945falseundefined29483012{}undefined31583197falseundefined37233738__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41964210__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50525060__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54775490__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60946108__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61446159__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61876204__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62396260__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68966909__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78877900__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93369360__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94589479__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98319844__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1003410047__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028710301__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1087310884__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1155311571__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200812016__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1256612580__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1304613059__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1348213508__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1355513568__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1363413655__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1397513995__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1405614067__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455914572__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1467114678__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1493414948__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516915187__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552915540__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined~156257module_compiled.AppRouteRouteModuleundefined293361route_kind.RouteKindundefined792837next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectundefined11431231(0,patch_fetch.patchFetch)undefined13161322next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handlerundefined22902390(0,app_paths_.normalizeAppPath)undefined28482942no_fallback_error_external_.NoFallbackErrorundefined37843870(0,trace_tracer.getTracer)undefined42874383(0,request_meta.getRequestMeta)undefined49875080node.NodeNextRequestundefined51165211node.NodeNextResponseundefined52395330next_request.NextRequestAdapterundefined53655477(0,next_request.signalFromNodeResponse)undefined61136191constants.BaseServerSpanundefined71697265(0,request_meta.getRequestMeta)undefined87018820(0,web_utils.toNodeOutgoingHttpHeaders)undefined89189026lib_constants.NEXT_CACHE_TAGS_HEADERundefined93789470lib_constants.INFINITE_CACHEundefined96609752lib_constants.INFINITE_CACHEundefined999210073response_cache.CachedRouteKindundefined1064510738(0,send_response/* sendResponse */.I)undefined1140711513(0,utils/* getRevalidateReason */.c)undefined1195012018route_kind.RouteKindundefined1256812649response_cache.CachedRouteKindundefined1311513211(0,request_meta.getRequestMeta)undefined1363413757(0,web_utils.fromNodeOutgoingHttpHeaders)undefined1380413900(0,request_meta.getRequestMeta)undefined1396614074lib_constants.NEXT_CACHE_TAGS_HEADERundefined1439414505(0,cache_control.getCacheControlHeader)undefined1456614659(0,send_response/* sendResponse */.I)undefined1515115229constants.BaseServerSpanundefined1532815394trace_tracer.SpanKindundefined1565015744no_fallback_error_external_.NoFallbackErrorundefined1596516071(0,utils/* getRevalidateReason */.c)undefined1641316506(0,send_response/* sendResponse */.I)undefined /***/ }) _\/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts const APP_URL = "http://canhelp.gr" || 0; const API_URL = "https://api.canhelp.gr" || 0; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ const sitemapModule = { ...sitemap_namespaceObject } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new server.NextResponse('Not Found', { status: 404, }) } if (false) {} const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map /***/ })  `_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; (// ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts  ReplaceSource const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } export default async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } u1646"http://canhelp.gr"undefined51730undefined92122"https://api.canhelp.gr"undefined1271490undefined27202734undefinedd // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ import { NextResponse } from 'next/server' import * as userland from "/opt/canhelp/apps/web/src/app/sitemap.ts" import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data' const sitemapModule = { ...userland } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } export async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new NextResponse('Not Found', { status: 404, }) } if (process.env.NODE_ENV !== 'production' && sitemapModule.generateSitemaps) { const sitemaps = await sitemapModule.generateSitemaps() for (const item of sitemaps) { if (item?.id == null) { throw new Error('id property is required for every item returned from generateSitemaps') } } } const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = resolveRouteData(data, fileType) return new NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } 041undefined43110undefined112205undefined235242__WEBPACK_MODULE_REFERENCE__17_ns_asiSafe1__._undefined494500undefined705716__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined770840falseundefined8431083{}undefined12231238__WEBPACK_MODULE_REFERENCE__18_5b227265736f6c7665526f75746544617461225d_call_directImport_asiSafe1__._undefined12701281__WEBPACK_MODULE_REFERENCE__16_5b224e657874526573706f6e7365225d_directImport_asiSafe1__._undefined3176sitemap_namespaceObjectundefined532620server.NextResponseundefined822923(0,resolve_route_data.resolveRouteData)undefined9551043server.NextResponseundefinedRawSource ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! N=import { AppRouteRouteModule } from "next/dist/server/route-modules/app-route/module.compiled"; import { RouteKind } from "next/dist/server/route-kind"; import { patchFetch as _patchFetch } from "next/dist/server/lib/patch-fetch"; import { getRequestMeta } from "next/dist/server/request-meta"; import { getTracer, SpanKind } from "next/dist/server/lib/trace/tracer"; import { normalizeAppPath } from "next/dist/shared/lib/router/utils/app-paths"; import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node"; import { NextRequestAdapter, signalFromNodeResponse } from "next/dist/server/web/spec-extension/adapters/next-request"; import { BaseServerSpan } from "next/dist/server/lib/trace/constants"; import { getRevalidateReason } from "next/dist/server/instrumentation/utils"; import { sendResponse } from "next/dist/server/send-response"; import { fromNodeOutgoingHttpHeaders, toNodeOutgoingHttpHeaders } from "next/dist/server/web/utils"; import { getCacheControlHeader } from "next/dist/server/lib/cache-control"; import { INFINITE_CACHE, NEXT_CACHE_TAGS_HEADER } from "next/dist/lib/constants"; import { NoFallbackError } from "next/dist/shared/lib/no-fallback-error.external"; import { CachedRouteKind } from "next/dist/server/response-cache"; import * as userland from "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__"; // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new AppRouteRouteModule({ definition: { kind: RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '', relativeProjectDir: process.env.__NEXT_RELATIVE_PROJECT_DIR || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return _patchFetch({ workAsyncStorage, workUnitAsyncStorage }); } export { routeModule, workAsyncStorage, workUnitAsyncStorage, serverHooks, patchFetch, }; export async function handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (process.env.TURBOPACK) { srcPage = srcPage.replace(/\/index$/, '') || '/'; } else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = process.env.__NEXT_MULTI_ZONE_DRAFT_MODE; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = normalizeAppPath(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = getTracer(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: getRequestMeta(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new NodeNextRequest(req); const nodeNextRes = new NodeNextResponse(res); const nextReq = NextRequestAdapter.fromNodeNextRequest(nodeNextReq, signalFromNodeResponse(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!getRequestMeta(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = toNodeOutgoingHttpHeaders(response.headers); if (cacheTags) { headers[NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await sendResponse(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!getRequestMeta(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = fromNodeOutgoingHttpHeaders(cacheEntry.value.headers); if (!(getRequestMeta(req, 'minimalMode') && isIsr)) { headers.delete(NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', getCacheControlHeader(cacheEntry.cacheControl)); } await sendResponse(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: getRevalidateReason({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await sendResponse(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map y094undefined96151undefined153229undefined231293undefined295366undefined368446undefined448531undefined533651undefined653722undefined724800undefined802863undefined865964undefined9661040undefined10421122undefined11241205undefined12071272undefined12741443undefined15841602__WEBPACK_MODULE_REFERENCE__0_5b22417070526f757465526f7574654d6f64756c65225d_directImport_asiSafe1__._undefined16381646__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined18221857".next"undefined186218630undefined18901928 falseundefined21382137: __WEBPACK_MODULE_REFERENCE__19_ns_asiSafe1__._undefined24432453__WEBPACK_MODULE_REFERENCE__2_5b2270617463684665746368225d_call_directImport_asiSafe1__._undefined25222611undefined26132619undefined29252945falseundefined29483012{}undefined31583197falseundefined37233738__WEBPACK_MODULE_REFERENCE__5_5b226e6f726d616c697a6541707050617468225d_call_directImport_asiSafe1__._undefined41964210__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined50525060__WEBPACK_MODULE_REFERENCE__4_5b22676574547261636572225d_call_directImport_asiSafe1__._undefined54775490__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined60946108__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e65787452657175657374225d_directImport_asiSafe1__._undefined61446159__WEBPACK_MODULE_REFERENCE__6_5b224e6f64654e657874526573706f6e7365225d_directImport_asiSafe1__._undefined61876204__WEBPACK_MODULE_REFERENCE__7_5b224e6578745265717565737441646170746572225d_call_asiSafe1__._undefined62396260__WEBPACK_MODULE_REFERENCE__7_5b227369676e616c46726f6d4e6f6465526573706f6e7365225d_call_directImport_asiSafe1__._undefined68966909__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined78877900__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined93369360__WEBPACK_MODULE_REFERENCE__11_5b22746f4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined94589479__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined98319844__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1003410047__WEBPACK_MODULE_REFERENCE__13_5b22494e46494e4954455f4341434845225d_directImport_asiSafe1__._undefined1028710301__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1087310884__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1155311571__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1200812016__WEBPACK_MODULE_REFERENCE__1_5b22526f7574654b696e64225d_asiSafe1__._undefined1256612580__WEBPACK_MODULE_REFERENCE__15_5b22436163686564526f7574654b696e64225d_asiSafe1__._undefined1304613059__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1348213508__WEBPACK_MODULE_REFERENCE__11_5b2266726f6d4e6f64654f7574676f696e674874747048656164657273225d_call_directImport_asiSafe1__._undefined1355513568__WEBPACK_MODULE_REFERENCE__3_5b22676574526571756573744d657461225d_call_directImport_asiSafe1__._undefined1363413655__WEBPACK_MODULE_REFERENCE__13_5b224e4558545f43414348455f544147535f484541444552225d_directImport_asiSafe1__._undefined1397513995__WEBPACK_MODULE_REFERENCE__12_5b226765744361636865436f6e74726f6c486561646572225d_call_directImport_asiSafe1__._undefined1405614067__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined1455914572__WEBPACK_MODULE_REFERENCE__8_5b22426173655365727665725370616e225d_asiSafe1__._undefined1467114678__WEBPACK_MODULE_REFERENCE__4_5b225370616e4b696e64225d_asiSafe1__._undefined1493414948__WEBPACK_MODULE_REFERENCE__14_5b224e6f46616c6c6261636b4572726f72225d_directImport_asiSafe1__._undefined1516915187__WEBPACK_MODULE_REFERENCE__9_5b22676574526576616c6964617465526561736f6e225d_call_directImport_asiSafe1__._undefined1552915540__WEBPACK_MODULE_REFERENCE__10_5b2273656e64526573706f6e7365225d_call_directImport_asiSafe1__._undefined~156257module_compiled.AppRouteRouteModuleundefined293361route_kind.RouteKindundefined792837next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObjectundefined11431231(0,patch_fetch.patchFetch)undefined13161322next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handlerundefined22902390(0,app_paths_.normalizeAppPath)undefined28482942no_fallback_error_external_.NoFallbackErrorundefined37843870(0,trace_tracer.getTracer)undefined42874383(0,request_meta.getRequestMeta)undefined49875080node.NodeNextRequestundefined51165211node.NodeNextResponseundefined52395330next_request.NextRequestAdapterundefined53655477(0,next_request.signalFromNodeResponse)undefined61136191constants.BaseServerSpanundefined71697265(0,request_meta.getRequestMeta)undefined87018820(0,web_utils.toNodeOutgoingHttpHeaders)undefined89189026lib_constants.NEXT_CACHE_TAGS_HEADERundefined93789470lib_constants.INFINITE_CACHEundefined96609752lib_constants.INFINITE_CACHEundefined999210073response_cache.CachedRouteKindundefined1064510738(0,send_response/* sendResponse */.I)undefined1140711513(0,utils/* getRevalidateReason */.c)undefined1195012018route_kind.RouteKindundefined1256812649response_cache.CachedRouteKindundefined1311513211(0,request_meta.getRequestMeta)undefined1363413757(0,web_utils.fromNodeOutgoingHttpHeaders)undefined1380413900(0,request_meta.getRequestMeta)undefined1396614074lib_constants.NEXT_CACHE_TAGS_HEADERundefined1439414505(0,cache_control.getCacheControlHeader)undefined1456614659(0,send_response/* sendResponse */.I)undefined1515115229constants.BaseServerSpanundefined1532815394trace_tracer.SpanKindundefined1565015744no_fallback_error_external_.NoFallbackErrorundefined1596516071(0,utils/* getRevalidateReason */.c)undefined1641316506(0,send_response/* sendResponse */.I)undefined, /***/ 86439:  +webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$/***/ ((module) => { "use strict"; Lmodule.exports = require("next/dist/shared/lib/no-fallback-error.external");  /***/ }) z/***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/no-fallback-error.external"); /***/ })  Lmodule.exports = require("next/dist/shared/lib/no-fallback-error.external");, /***/ 87032:  4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource buffersourcesizemapshash {"finalSource":true}mapbufferedMap ReplaceSourceRawSource /***/ }) y {~ w }; ; // load runtime var __webpack_require__ = require("../../webpack-runtime.js"); __webpack_require__.C(exports); var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) var __webpack_exports__ = __webpack_require__.X(0, [901,825], () => (__webpack_exec__(83019))); ,module.exports = __webpack_exports__; })();  (() => { var exports = {}; exports.id = 475; exports.ids = [475]; exports.modules = { /***/ 261: /***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/router/utils/app-paths"); /***/ }), /***/ 3295: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/after-task-async-storage.external.js"); /***/ }), /***/ 10846: /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-page.runtime.prod.js"); /***/ }), /***/ 14691: /***/ ((__unused_webpack_module, exports) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { getOrigin: function() { return getOrigin; }, resolveArray: function() { return resolveArray; }, resolveAsArrayOrUndefined: function() { return resolveAsArrayOrUndefined; } }); function resolveArray(value) { if (Array.isArray(value)) { return value; } return [ value ]; } function resolveAsArrayOrUndefined(value) { if (typeof value === 'undefined' || value === null) { return undefined; } return resolveArray(value); } function getOrigin(url) { let origin = undefined; if (typeof url === 'string') { try { url = new URL(url); origin = url.origin; } catch {} } return origin; } //# sourceMappingURL=utils.js.map /***/ }), /***/ 19121: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/action-async-storage.external.js"); /***/ }), /***/ 23757: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); 0 && (0); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { resolveManifest: function() { return resolveManifest; }, resolveRobots: function() { return resolveRobots; }, resolveRouteData: function() { return resolveRouteData; }, resolveSitemap: function() { return resolveSitemap; } }); const _utils = __webpack_require__(14691); function resolveRobots(data) { let content = ''; const rules = Array.isArray(data.rules) ? data.rules : [ data.rules ]; for (const rule of rules){ const userAgent = (0, _utils.resolveArray)(rule.userAgent || [ '*' ]); for (const agent of userAgent){ content += `User-Agent: ${agent}\n`; } if (rule.allow) { const allow = (0, _utils.resolveArray)(rule.allow); for (const item of allow){ content += `Allow: ${item}\n`; } } if (rule.disallow) { const disallow = (0, _utils.resolveArray)(rule.disallow); for (const item of disallow){ content += `Disallow: ${item}\n`; } } if (rule.crawlDelay) { content += `Crawl-delay: ${rule.crawlDelay}\n`; } content += '\n'; } if (data.host) { content += `Host: ${data.host}\n`; } if (data.sitemap) { const sitemap = (0, _utils.resolveArray)(data.sitemap); // TODO-METADATA: support injecting sitemap url into robots.txt sitemap.forEach((item)=>{ content += `Sitemap: ${item}\n`; }); } return content; } function resolveSitemap(data) { const hasAlternates = data.some((item)=>Object.keys(item.alternates ?? {}).length > 0); const hasImages = data.some((item)=>{ var _item_images; return Boolean((_item_images = item.images) == null ? void 0 : _item_images.length); }); const hasVideos = data.some((item)=>{ var _item_videos; return Boolean((_item_videos = item.videos) == null ? void 0 : _item_videos.length); }); let content = ''; content += '\n'; content += '${item.url}\n`; const languages = (_item_alternates = item.alternates) == null ? void 0 : _item_alternates.languages; if (languages && Object.keys(languages).length) { // Since sitemap is separated from the page rendering, there's not metadataBase accessible yet. // we give the default setting that won't effect the languages resolving. for(const language in languages){ content += `\n`; } } if ((_item_images = item.images) == null ? void 0 : _item_images.length) { for (const image of item.images){ content += `\n${image}\n\n`; } } if ((_item_videos = item.videos) == null ? void 0 : _item_videos.length) { for (const video of item.videos){ let videoFields = [ ``, `${video.title}`, `${video.thumbnail_loc}`, `${video.description}`, video.content_loc && `${video.content_loc}`, video.player_loc && `${video.player_loc}`, video.duration && `${video.duration}`, video.view_count && `${video.view_count}`, video.tag && `${video.tag}`, video.rating && `${video.rating}`, video.expiration_date && `${video.expiration_date}`, video.publication_date && `${video.publication_date}`, video.family_friendly && `${video.family_friendly}`, video.requires_subscription && `${video.requires_subscription}`, video.live && `${video.live}`, video.restriction && `${video.restriction.content}`, video.platform && `${video.platform.content}`, video.uploader && `${video.uploader.content}`, `\n` ].filter(Boolean); content += videoFields.join('\n'); } } if (item.lastModified) { const serializedDate = item.lastModified instanceof Date ? item.lastModified.toISOString() : item.lastModified; content += `${serializedDate}\n`; } if (item.changeFrequency) { content += `${item.changeFrequency}\n`; } if (typeof item.priority === 'number') { content += `${item.priority}\n`; } content += '\n'; } content += '\n'; return content; } function resolveManifest(data) { return JSON.stringify(data); } function resolveRouteData(data, fileType) { if (fileType === 'robots') { return resolveRobots(data); } if (fileType === 'sitemap') { return resolveSitemap(data); } if (fileType === 'manifest') { return resolveManifest(data); } return ''; } //# sourceMappingURL=resolve-route-data.js.map /***/ }), /***/ 29294: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-async-storage.external.js"); /***/ }), /***/ 44870: /***/ ((module) => { "use strict"; module.exports = require("next/dist/compiled/next-server/app-route.runtime.prod.js"); /***/ }), /***/ 63033: /***/ ((module) => { "use strict"; module.exports = require("next/dist/server/app-render/work-unit-async-storage.external.js"); /***/ }), /***/ 80408: /***/ (() => { /***/ }), /***/ 83019: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { handler: () => (/* binding */ next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler), patchFetch: () => (/* binding */ patchFetch), routeModule: () => (/* binding */ routeModule), serverHooks: () => (/* binding */ serverHooks), workAsyncStorage: () => (/* binding */ workAsyncStorage), workUnitAsyncStorage: () => (/* binding */ workUnitAsyncStorage) }); // NAMESPACE OBJECT: ./src/app/sitemap.ts var sitemap_namespaceObject = {}; __webpack_require__.r(sitemap_namespaceObject); __webpack_require__.d(sitemap_namespaceObject, { "default": () => (sitemap) }); // NAMESPACE OBJECT: ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ var next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject = {}; __webpack_require__.r(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject); __webpack_require__.d(next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject, { GET: () => (GET) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-route/module.compiled.js var module_compiled = __webpack_require__(26421); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-kind.js var route_kind = __webpack_require__(97714); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/patch-fetch.js var patch_fetch = __webpack_require__(85681); // EXTERNAL MODULE: ../../node_modules/next/dist/server/request-meta.js var request_meta = __webpack_require__(22369); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/tracer.js var trace_tracer = __webpack_require__(37587); // EXTERNAL MODULE: external "next/dist/shared/lib/router/utils/app-paths" var app_paths_ = __webpack_require__(261); // EXTERNAL MODULE: ../../node_modules/next/dist/server/base-http/node.js var node = __webpack_require__(46537); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/spec-extension/adapters/next-request.js var next_request = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/trace/constants.js var constants = __webpack_require__(1889); // EXTERNAL MODULE: ../../node_modules/next/dist/server/instrumentation/utils.js var utils = __webpack_require__(85250); // EXTERNAL MODULE: ../../node_modules/next/dist/server/send-response.js var send_response = __webpack_require__(23620); // EXTERNAL MODULE: ../../node_modules/next/dist/server/web/utils.js var web_utils = __webpack_require__(29790); // EXTERNAL MODULE: ../../node_modules/next/dist/server/lib/cache-control.js var cache_control = __webpack_require__(67876); // EXTERNAL MODULE: ../../node_modules/next/dist/lib/constants.js var lib_constants = __webpack_require__(57749); // EXTERNAL MODULE: external "next/dist/shared/lib/no-fallback-error.external" var no_fallback_error_external_ = __webpack_require__(86439); // EXTERNAL MODULE: ../../node_modules/next/dist/server/response-cache/index.js var response_cache = __webpack_require__(40139); // EXTERNAL MODULE: ../../node_modules/next/dist/api/server.js var server = __webpack_require__(53444); ;// ./src/app/sitemap.ts const APP_URL = "http://canhelp.gr" || 0; const API_URL = "https://api.canhelp.gr" || 0; const STATIC_ROUTES = [ { url: `${APP_URL}/`, changeFrequency: 'daily', priority: 1.0 }, { url: `${APP_URL}/tasks`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/specialists`, changeFrequency: 'hourly', priority: 0.9 }, { url: `${APP_URL}/pricing`, changeFrequency: 'weekly', priority: 0.6 }, { url: `${APP_URL}/become-specialist`, changeFrequency: 'monthly', priority: 0.7 } ]; async function fetchAllTasks() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/tasks?page=${page}&limit=${limit}&status=open`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const tasks = json.data ?? []; for (const { task } of tasks){ entries.push({ url: `${APP_URL}/tasks/${task.id}`, lastModified: task.updatedAt ? new Date(task.updatedAt) : undefined, changeFrequency: 'daily', priority: 0.8 }); } if (entries.length >= json.total || tasks.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function fetchAllSpecialists() { const entries = []; let page = 1; const limit = 100; try { while(true){ const res = await fetch(`${API_URL}/api/users/specialists?page=${page}&limit=${limit}`, { next: { revalidate: 3600 } }); if (!res.ok) break; const json = await res.json(); const specialists = json.data ?? []; for (const specialist of specialists){ entries.push({ url: `${APP_URL}/users/${specialist.id}`, lastModified: specialist.updatedAt ? new Date(specialist.updatedAt) : undefined, changeFrequency: 'weekly', priority: 0.75 }); } if (entries.length >= json.total || specialists.length < limit) break; page++; } } catch { // silently skip if API is unavailable during build } return entries; } async function sitemap() { const [tasks, specialists] = await Promise.all([ fetchAllTasks(), fetchAllSpecialists() ]); return [ ...STATIC_ROUTES, ...tasks, ...specialists ]; } // EXTERNAL MODULE: ../../node_modules/next/dist/build/webpack/loaders/metadata/resolve-route-data.js var resolve_route_data = __webpack_require__(23757); ;// ../../node_modules/next/dist/build/webpack/loaders/next-metadata-route-loader.js?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__ const sitemapModule = { ...sitemap_namespaceObject } const handler = sitemapModule.default const contentType = "application/xml" const fileType = "sitemap" if (typeof handler !== 'function') { throw new Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"') } async function GET(_, ctx) { const { __metadata_id__: id, ...params } = await ctx.params || {} const hasXmlExtension = id ? id.endsWith('.xml') : false if (id && !hasXmlExtension) { return new server.NextResponse('Not Found', { status: 404, }) } if (false) {} const targetId = id && hasXmlExtension ? id.slice(0, -4) : undefined const data = await handler({ id: targetId }) const content = (0,resolve_route_data.resolveRouteData)(data, fileType) return new server.NextResponse(content, { headers: { 'Content-Type': contentType, 'Cache-Control': "public, max-age=0, must-revalidate", }, }) } ;// ../../node_modules/next/dist/build/webpack/loaders/next-app-loader/index.js?page=%2Fsitemap.xml%2Froute&name=app%2Fsitemap.xml%2Froute&pagePath=private-next-app-dir%2Fsitemap.ts&appDir=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp&appPaths=%2Fsitemap&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D&isGlobalNotFoundEnabled=! // We inject the nextConfigOutput here so that we can use them in the route // module. const nextConfigOutput = "" const routeModule = new module_compiled.AppRouteRouteModule({ definition: { kind: route_kind.RouteKind.APP_ROUTE, page: "/sitemap.xml/route", pathname: "/sitemap.xml", filename: "sitemap", bundlePath: "app/sitemap.xml/route" }, distDir: ".next" || 0, relativeProjectDir: false || '', resolvedPagePath: "next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__", nextConfigOutput, userland: next_metadata_route_loaderfilePath_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_2Fsitemap_ts_isDynamicRouteExtension_1_next_metadata_route_namespaceObject }); // Pull out the exports that we need to expose from the module. This should // be eliminated when we've moved the other routes to the new format. These // are used to hook into the route. const { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule; function patchFetch() { return (0,patch_fetch.patchFetch)({ workAsyncStorage, workUnitAsyncStorage }); } async function next_app_loaderpage_2Fsitemap_xml_2Froute_name_app_2Fsitemap_xml_2Froute_pagePath_private_next_app_dir_2Fsitemap_ts_appDir_2Fopt_2Fcanhelp_2Fapps_2Fweb_2Fsrc_2Fapp_appPaths_2Fsitemap_pageExtensions_tsx_pageExtensions_ts_pageExtensions_jsx_pageExtensions_js_basePath_assetPrefix_nextConfigOutput_preferredRegion_middlewareConfig_e30_3D_isGlobalNotFoundEnabled_handler(req, res, ctx) { var _nextConfig_experimental; let srcPage = "/sitemap.xml/route"; // turbopack doesn't normalize `/index` in the page name // so we need to to process dynamic routes properly // TODO: fix turbopack providing differing value from webpack if (false) {} else if (srcPage === '/index') { // we always normalize /index specifically srcPage = '/'; } const multiZoneDraftMode = false; const prepareResult = await routeModule.prepare(req, res, { srcPage, multiZoneDraftMode }); if (!prepareResult) { res.statusCode = 400; res.end('Bad Request'); ctx.waitUntil == null ? void 0 : ctx.waitUntil.call(ctx, Promise.resolve()); return null; } const { buildId, params, nextConfig, isDraftMode, prerenderManifest, routerServerContext, isOnDemandRevalidate, revalidateOnlyGenerated, resolvedPathname } = prepareResult; const normalizedSrcPage = (0,app_paths_.normalizeAppPath)(srcPage); let isIsr = Boolean(prerenderManifest.dynamicRoutes[normalizedSrcPage] || prerenderManifest.routes[resolvedPathname]); if (isIsr && !isDraftMode) { const isPrerendered = Boolean(prerenderManifest.routes[resolvedPathname]); const prerenderInfo = prerenderManifest.dynamicRoutes[normalizedSrcPage]; if (prerenderInfo) { if (prerenderInfo.fallback === false && !isPrerendered) { throw new no_fallback_error_external_.NoFallbackError(); } } } let cacheKey = null; if (isIsr && !routeModule.isDev && !isDraftMode) { cacheKey = resolvedPathname; // ensure /index and / is normalized to one key cacheKey = cacheKey === '/index' ? '/' : cacheKey; } const supportsDynamicResponse = // If we're in development, we always support dynamic HTML routeModule.isDev === true || // If this is not SSG or does not have static paths, then it supports // dynamic HTML. !isIsr; // This is a revalidation request if the request is for a static // page and it is not being resumed from a postponed render and // it is not a dynamic RSC request then it is a revalidation // request. const isRevalidate = isIsr && !supportsDynamicResponse; const method = req.method || 'GET'; const tracer = (0,trace_tracer.getTracer)(); const activeSpan = tracer.getActiveScopeSpan(); const context = { params, prerenderManifest, renderOpts: { experimental: { cacheComponents: Boolean(nextConfig.experimental.cacheComponents), authInterrupts: Boolean(nextConfig.experimental.authInterrupts) }, supportsDynamicResponse, incrementalCache: (0,request_meta.getRequestMeta)(req, 'incrementalCache'), cacheLifeProfiles: (_nextConfig_experimental = nextConfig.experimental) == null ? void 0 : _nextConfig_experimental.cacheLife, isRevalidate, waitUntil: ctx.waitUntil, onClose: (cb)=>{ res.on('close', cb); }, onAfterTaskError: undefined, onInstrumentationRequestError: (error, _request, errorContext)=>routeModule.onRequestError(req, error, errorContext, routerServerContext) }, sharedContext: { buildId } }; const nodeNextReq = new node.NodeNextRequest(req); const nodeNextRes = new node.NodeNextResponse(res); const nextReq = next_request.NextRequestAdapter.fromNodeNextRequest(nodeNextReq, (0,next_request.signalFromNodeResponse)(res)); try { const invokeRouteModule = async (span)=>{ return routeModule.handle(nextReq, context).finally(()=>{ if (!span) return; span.setAttributes({ 'http.status_code': res.statusCode, 'next.rsc': false }); const rootSpanAttributes = tracer.getRootSpanAttributes(); // We were unable to get attributes, probably OTEL is not enabled if (!rootSpanAttributes) { return; } if (rootSpanAttributes.get('next.span_type') !== constants.BaseServerSpan.handleRequest) { console.warn(`Unexpected root span type '${rootSpanAttributes.get('next.span_type')}'. Please report this Next.js issue https://github.com/vercel/next.js`); return; } const route = rootSpanAttributes.get('next.route'); if (route) { const name = `${method} ${route}`; span.setAttributes({ 'next.route': route, 'http.route': route, 'next.span_name': name }); span.updateName(name); } else { span.updateName(`${method} ${req.url}`); } }); }; const handleResponse = async (currentSpan)=>{ var _cacheEntry_value; const responseGenerator = async ({ previousCacheEntry })=>{ try { if (!(0,request_meta.getRequestMeta)(req, 'minimalMode') && isOnDemandRevalidate && revalidateOnlyGenerated && !previousCacheEntry) { res.statusCode = 404; // on-demand revalidate always sets this header res.setHeader('x-nextjs-cache', 'REVALIDATED'); res.end('This page could not be found'); return null; } const response = await invokeRouteModule(currentSpan); req.fetchMetrics = context.renderOpts.fetchMetrics; let pendingWaitUntil = context.renderOpts.pendingWaitUntil; // Attempt using provided waitUntil if available // if it's not we fallback to sendResponse's handling if (pendingWaitUntil) { if (ctx.waitUntil) { ctx.waitUntil(pendingWaitUntil); pendingWaitUntil = undefined; } } const cacheTags = context.renderOpts.collectedTags; // If the request is for a static response, we can cache it so long // as it's not edge. if (isIsr) { const blob = await response.blob(); // Copy the headers from the response. const headers = (0,web_utils.toNodeOutgoingHttpHeaders)(response.headers); if (cacheTags) { headers[lib_constants.NEXT_CACHE_TAGS_HEADER] = cacheTags; } if (!headers['content-type'] && blob.type) { headers['content-type'] = blob.type; } const revalidate = typeof context.renderOpts.collectedRevalidate === 'undefined' || context.renderOpts.collectedRevalidate >= lib_constants.INFINITE_CACHE ? false : context.renderOpts.collectedRevalidate; const expire = typeof context.renderOpts.collectedExpire === 'undefined' || context.renderOpts.collectedExpire >= lib_constants.INFINITE_CACHE ? undefined : context.renderOpts.collectedExpire; // Create the cache entry for the response. const cacheEntry = { value: { kind: response_cache.CachedRouteKind.APP_ROUTE, status: response.status, body: Buffer.from(await blob.arrayBuffer()), headers }, cacheControl: { revalidate, expire } }; return cacheEntry; } else { // send response without caching if not ISR await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, response, context.renderOpts.pendingWaitUntil); return null; } } catch (err) { // if this is a background revalidate we need to report // the request error here as it won't be bubbled if (previousCacheEntry == null ? void 0 : previousCacheEntry.isStale) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: srcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }, routerServerContext); } throw err; } }; const cacheEntry = await routeModule.handleResponse({ req, nextConfig, cacheKey, routeKind: route_kind.RouteKind.APP_ROUTE, isFallback: false, prerenderManifest, isRoutePPREnabled: false, isOnDemandRevalidate, revalidateOnlyGenerated, responseGenerator, waitUntil: ctx.waitUntil }); // we don't create a cacheEntry for ISR if (!isIsr) { return null; } if ((cacheEntry == null ? void 0 : (_cacheEntry_value = cacheEntry.value) == null ? void 0 : _cacheEntry_value.kind) !== response_cache.CachedRouteKind.APP_ROUTE) { var _cacheEntry_value1; throw Object.defineProperty(new Error(`Invariant: app-route received invalid cache entry ${cacheEntry == null ? void 0 : (_cacheEntry_value1 = cacheEntry.value) == null ? void 0 : _cacheEntry_value1.kind}`), "__NEXT_ERROR_CODE", { value: "E701", enumerable: false, configurable: true }); } if (!(0,request_meta.getRequestMeta)(req, 'minimalMode')) { res.setHeader('x-nextjs-cache', isOnDemandRevalidate ? 'REVALIDATED' : cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT'); } // Draft mode should never be cached if (isDraftMode) { res.setHeader('Cache-Control', 'private, no-cache, no-store, max-age=0, must-revalidate'); } const headers = (0,web_utils.fromNodeOutgoingHttpHeaders)(cacheEntry.value.headers); if (!((0,request_meta.getRequestMeta)(req, 'minimalMode') && isIsr)) { headers.delete(lib_constants.NEXT_CACHE_TAGS_HEADER); } // If cache control is already set on the response we don't // override it to allow users to customize it via next.config if (cacheEntry.cacheControl && !res.getHeader('Cache-Control') && !headers.get('Cache-Control')) { headers.set('Cache-Control', (0,cache_control.getCacheControlHeader)(cacheEntry.cacheControl)); } await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(cacheEntry.value.body, { headers, status: cacheEntry.value.status || 200 })); return null; }; // TODO: activeSpan code path is for when wrapped by // next-server can be removed when this is no longer used if (activeSpan) { await handleResponse(activeSpan); } else { await tracer.withPropagatedContext(req.headers, ()=>tracer.trace(constants.BaseServerSpan.handleRequest, { spanName: `${method} ${req.url}`, kind: trace_tracer.SpanKind.SERVER, attributes: { 'http.method': method, 'http.target': req.url } }, handleResponse)); } } catch (err) { if (!(err instanceof no_fallback_error_external_.NoFallbackError)) { await routeModule.onRequestError(req, err, { routerKind: 'App Router', routePath: normalizedSrcPage, routeType: 'route', revalidateReason: (0,utils/* getRevalidateReason */.c)({ isRevalidate, isOnDemandRevalidate }) }); } // rethrow so that we can handle serving error page // If this is during static generation, throw the error again. if (isIsr) throw err; // Otherwise, send a 500 response. await (0,send_response/* sendResponse */.I)(nodeNextReq, nodeNextRes, new Response(null, { status: 500 })); return null; } } //# sourceMappingURL=app-route.js.map /***/ }), /***/ 86439: /***/ ((module) => { "use strict"; module.exports = require("next/dist/shared/lib/no-fallback-error.external"); /***/ }), /***/ 87032: /***/ (() => { /***/ }) }; ; // load runtime var __webpack_require__ = require("../../webpack-runtime.js"); __webpack_require__.C(exports); var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) var __webpack_exports__ = __webpack_require__.X(0, [901,825], () => (__webpack_exec__(83019))); module.exports = __webpack_exports__; })();    @b(() => { var exports = {}; exports.id = 475; exports.ids = [475]; exports.modules = { /***/ 261: 999999999999999999999999999, /***/ 83019: 6k86688888888var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId)) var __webpack_exports__ = __webpack_require__.X(0, [901,825], () => (__webpack_exec__(83019))); 7 "webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSource`7webpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceHexports.id = 892; exports.ids = [892]; exports.modules = { /***/ 1241: webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { /* (ignored) */  /***/ }) buffersourcesizemapshash)/***/ (() => { /* (ignored) */ /***/ }) {"finalSource":true}mapbufferedMap ConcatSourceRawSource/***/ (() => {  RawSource/* (ignored) */ /***/ }), /***/ 1697:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider) /* harmony export */ }); /* unused harmony export useLocation */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocationProvider = registerClientReference( function() { throw new Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "LocationProvider", );export const useLocation = registerClientReference( function() { throw new Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "useLocation", ); `=H4J(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)buffersourcesizemapshash/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider) /* harmony export */ }); /* unused harmony export useLocation */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const LocationProvider = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "LocationProvider", );const useLocation = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "useLocation", ); {"finalSource":true}mapbufferedMap ConcatSourceRawSource /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider) /* harmony export */ }); /* unused harmony export useLocation */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); ReplaceSourceRawSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocationProvider = registerClientReference( function() { throw new Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "LocationProvider", );export const useLocation = registerClientReference( function() { throw new Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "useLocation", );61134undefined136142undefined168190(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined537543undefined564586(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined /***/ }) 2/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider) /* harmony export */ }); /* unused harmony export useLocation */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const LocationProvider = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "LocationProvider", );const useLocation = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "useLocation", ); /***/ })   _/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict";  /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider) /* harmony export */ }); /* unused harmony export useLocation */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); ReplaceSourceRawSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocationProvider = registerClientReference( function() { throw new Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "LocationProvider", );export const useLocation = registerClientReference( function() { throw new Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "useLocation", );61134undefined136142undefined168190(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined537543undefined564586(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined, /***/ 12998:  ER webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource pwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ getTranslations), /* harmony export */ YZ: () => (/* binding */ LOCALES) /* harmony export */ }); /* unused harmony export translations */ webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcenexport const LOCALES = [ { code: 'el', label: 'Ελληνικά', flag: '🇬🇷' }, { code: 'en', label: 'English', flag: '🇬🇧' }, { code: 'ru', label: 'Русский', flag: '🇷🇺' } ]; export const translations = { el: { 'footer.slogan': 'Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.', 'footer.links': 'Σύνδεσμοι', 'footer.socials': 'Στα κοινωνικά δίκτυα', // Nav 'nav.home': 'Αρχική', 'nav.tasks': 'Εργασίες', 'nav.post': '+ Δημοσίευση', 'nav.dashboard': 'Πίνακας', 'nav.chat': 'Μηνύματα', 'nav.notifications': 'Ειδοποιήσεις', 'nav.profile': 'Προφίλ', 'nav.admin': 'Διαχείριση', 'nav.specialists': 'Ειδικοί', 'nav.new_task': 'Νέα εργασία', 'nav.login': 'Σύνδεση', 'nav.register': 'Εγγραφή', 'nav.logout': 'Έξοδος', // Hero 'hero.title': 'Βρες ειδικό για κάθε δουλειά', 'hero.subtitle': 'Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία', 'hero.cta.post': 'Δημοσίευσε εργασία', 'hero.cta.browse': 'Γίνε ειδικός', 'hero.search.placeholder': 'Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...', 'stats.specialists': 'ειδικοί', 'stats.tasks': 'εργασίες', 'stats.categories': 'κατηγορίες', 'stats.free': 'δωρεάν εγγραφή', // Sections 'section.categories': 'Δημιούργησε εργασία σε οποιαδήποτε κατηγορία', 'section.how': 'Πώς λειτουργεί', 'section.recent': 'Πρόσφατες εργασίες', 'section.all': 'Δες όλες →', 'section.more': 'ακόμα', 'section.cities': 'Πόλεις & Περιοχές', 'section.community': 'Ένα κοινοτικό έργο για όλους', 'community.subtitle': 'Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.', 'community.point1.title': 'Είσαι ειδικός σε κάτι;', 'community.point1.desc': 'Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.', 'community.point2.title': 'Χρειάζεσαι βοήθεια;', 'community.point2.desc': 'Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.', 'community.point3.title': 'Βοήθησε το έργο να αναπτυχθεί', 'community.point3.desc': 'Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.', 'community.share': 'Μοιράσου με φίλους', 'community.share.copied': 'Σύνδεσμος αντιγράφηκε!', // Referral section on home page 'section.referral': 'Πρόγραμμα παραπομπών', 'referral.home.subtitle': 'Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.', 'referral.home.step1.title': 'Εγγραφείσε και λάβε σύνδεσμο', 'referral.home.step1.desc': 'Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.', 'referral.home.step2.title': 'Μοιράσου με φίλους', 'referral.home.step2.desc': 'Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.', 'referral.home.step3.title': 'Κέρδισε ανταμοιβές', 'referral.home.step3.desc': 'Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.', 'referral.home.cta': 'Πάρε τον σύνδεσμό σου', 'referral.home.badge': 'Πρόγραμμα παραπομπών', // FAQ section 'section.faq': 'Συχνές Ερωτήσεις', 'faq.q1': 'Πώς λειτουργεί το CanHelp;', 'faq.a1': 'Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.', 'faq.q2': 'Πόσο κοστίζει η χρήση της πλατφόρμας;', 'faq.a2': 'Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.', 'faq.q3': 'Πώς μπορώ να γίνω ειδικός;', 'faq.a3': 'Κάνε εγγραφή, πήγαινε στο «Γίνε Ειδικός», συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.', 'faq.q4': 'Πώς επιλέγω τον κατάλληλο ειδικό;', 'faq.a4': 'Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q5': 'Τι γίνεται αν δεν είμαι ικανοποιημένος;', 'faq.a5': 'Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.', 'faq.q6': 'Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;', 'faq.a6': 'Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q7': 'Πόσος χρόνος χρειάζεται για να λάβω προσφορές;', 'faq.a7': 'Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.', 'faq.q8': 'Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;', 'faq.a8': 'Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.', 'faq.q9': 'Τι είδη εργασιών μπορώ να βρω στο CanHelp;', 'faq.a9': 'Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.', 'faq.q10': 'Υπάρχει εφαρμογή για κινητό;', 'faq.a10': 'Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.', // How it works 'how.step1.title': 'Δημοσίευσε εργασία', 'how.step1.desc': 'Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου', 'how.step2.title': 'Λάβε προσφορές', 'how.step2.desc': 'Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο', 'how.step3.title': 'Επίλεξε & ξεκίνα', 'how.step3.desc': 'Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία', // Tasks page 'tasks.title': 'εργασίες', 'tasks.filters': 'Φίλτρα', 'tasks.search': 'Αναζήτηση', 'tasks.search.placeholder': 'Τίτλος ή λέξη κλειδί...', 'tasks.search.btn': 'Αναζήτηση', 'tasks.publish': 'Δημοσίευση', 'tasks.category.all': 'Όλες', 'tasks.category.all_in': 'Όλα στην', 'tasks.category.label': 'Κατηγορία', 'tasks.location.label': 'Πόλη', 'tasks.location.placeholder': 'π.χ. Αθήνα', 'tasks.empty': 'Δεν βρέθηκαν εργασίες', 'tasks.empty.cta': 'Δημοσίευσε την πρώτη', // Task detail 'task.status.open': 'Ανοιχτή', 'task.status.in_progress': 'Σε εξέλιξη', 'task.status.completed': 'Ολοκληρωμένη', 'task.status.cancelled': 'Ακυρωμένη', 'task.status.draft': 'Πρόχειρο', 'task.budget': 'Προϋπολογισμός', 'task.location': 'Τοποθεσία', 'task.deadline': 'Ημερομηνία έναρξης', 'task.created_at': 'Δημιουργήθηκε', 'task.customer': 'Πελάτης', 'task.offer.btn': 'Υποβολή προσφοράς', 'task.invite.banner_title': 'Σας προσκαλούν σε αυτήν την εργασία', 'task.invite.banner_hint': 'Ο πελάτης σας πρόσκαλεσε προσωπικά', 'task.invite.accept': 'Αποστολή προσφοράς', 'task.invite.decline': 'Άρνηση', 'offer.accept': 'Αποδοχή', 'offer.decline': 'Απόρριψη', 'task.complete': 'Ολοκλήρωση εργασίας', 'task.complete.confirm': 'Να ολοκληρωθεί η εργασία;', 'task.edit': 'Επεξεργασία', 'task.status_label': 'Κατάσταση', 'task.yours': 'Η εργασία σου', 'task.offer.yours': 'Η προσφορά σου', 'review.leave': 'Άφησε αξιολόγηση', 'review.rating': 'Βαθμολογία', 'review.comment': 'Σχόλιο', 'review.comment.placeholder': 'Πες μας για την εμπειρία σου...', 'review.submit': 'Υποβολή αξιολόγησης', 'review.submitting': 'Αποστολή...', 'review.done': 'Η αξιολόγηση καταχωρήθηκε!', 'profile.reviews': 'Αξιολογήσεις', 'profile.no_reviews': 'Δεν υπάρχουν αξιολογήσεις ακόμα', 'profile.rating': 'Βαθμολογία', 'profile.skills.label': 'Δεξιότητες', 'profile.member_since': 'Μέλος από', 'task.offers': 'Προσφορές', 'task.offers.none': 'Δεν υπάρχουν ακόμα προσφορές', // Create task 'create.title': 'Δημοσίευση εργασίας', 'create.field.title': 'Τίτλος', 'create.field.description': 'Περιγραφή', 'create.field.category': 'Κατηγορία', 'create.field.category.select': 'Επιλέξτε...', 'create.field.location': 'Τοποθεσία', 'create.field.location.any': 'Οπουδήποτε', 'create.field.location.all': 'Ολόκληρη η πόλη', 'create.field.budget': 'Προϋπολογισμός (€)', 'create.field.deadline': 'Ημερομηνία έναρξης', 'create.field.budget_negotiable': 'Η τιμή είναι διαπραγματεύσιμη', 'create.field.time_slot': 'Χρόνος εκτέλεσης', 'create.field.time_slot.any': 'Οποιαδήποτε', 'create.field.time_slot.morning': 'Πρωινό (08:00–13:00)', 'create.field.time_slot.afternoon': 'Μεσημέρι (13:00–18:00)', 'create.field.time_slot.evening': 'Βράδυ (18:00–22:00)', 'create.field.time_slot.weekend': 'Σαββατοκύριακο', 'create.field.address': 'Διεύθυνση (προαιρετικά)', 'create.field.address.district': 'Συνοικία', 'create.field.address.street': 'Οδός', 'create.field.address.house': 'Αριθμός', 'create.field.confidential': 'Εμπιστευτική σημείωση', 'create.field.confidential.placeholder': 'Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...', 'create.field.confidential.hint': 'Δεν εμφανίζεται δημόσια', 'create.field.photos': 'Φωτογραφίες', 'create.field.photos.add': 'Προσθήκη φωτογραφίας', 'create.field.photos.uploading': 'Ανέβασμα...', 'task.budget_negotiable': 'Τιμή διαπραγματεύσιμη', 'task.time_slot': 'Χρόνος', 'task.confidential': 'Εμπιστευτική σημείωση', 'create.field.title.placeholder': 'π.χ. Καθαρισμός διαμερίσματος 80τμ', 'create.field.description.placeholder': 'Περίγραψε λεπτομερώς τι χρειάζεσαι...', 'create.field.location.placeholder': 'π.χ. Αθήνα, Κολωνάκι', 'create.field.budget.placeholder': 'π.χ. 100', 'create.submit': 'Δημοσίευση εργασίας', 'create.submitting': 'Δημοσίευση...', // Auth 'login.title': 'Καλωσόρισες', 'login.subtitle': 'Σύνδεση στο CanHelp', 'login.email': 'Email', 'login.password': 'Κωδικός', 'login.submit': 'Σύνδεση', 'login.submitting': 'Σύνδεση...', 'login.error': 'Λάθος email ή κωδικός', 'login.unverified.title': 'Επιβεβαιώστε το email σας', 'login.unverified.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.', 'login.unverified.resend': 'Αποστολή νέου email επαλήθευσης', 'login.unverified.sending': 'Αποστολή...', 'login.unverified.sent': '✓ Εστάλη — ελέγξτε τα εισερχόμενα', 'profile.email.verified': 'Email επαληθεύτηκε', 'profile.email.not_verified': 'Email δεν επαληθεύτηκε', 'login.no_account': 'Δεν έχεις λογαριασμό;', 'login.register_link': 'Εγγραφή', 'login.forgot_password': 'Ξέχασα τον κωδικό', 'login.or_continue_with': 'ή συνεχίστε με', 'login.continue_google': 'Σύνδεση με Google', 'forgot.title': 'Ξέχασα τον κωδικό', 'forgot.subtitle': 'Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης', 'forgot.email': 'Email', 'forgot.submit': 'Αποστολή', 'forgot.submitting': 'Αποστολή...', 'forgot.sent.title': 'Ελέγξτε τα εισερχόμενά σας', 'forgot.sent.desc': 'Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.', 'forgot.back_to_login': 'Επιστροφή στη σύνδεση', 'forgot.error': 'Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.', 'forgot.error.not_found': 'Δεν βρέθηκε λογαριασμός με αυτό το email.', 'forgot.error.send_failed': 'Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα', 'reset.title': 'Νέος κωδικός', 'reset.subtitle': 'Εισάγετε τον νέο σας κωδικό', 'reset.password': 'Νέος κωδικός', 'reset.confirm': 'Επιβεβαίωση κωδικού', 'reset.submit': 'Αλλαγή κωδικού', 'reset.submitting': 'Αποθήκευση...', 'reset.success': 'Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...', 'reset.back_to_login': 'Επιστροφή στη σύνδεση', 'reset.error.mismatch': 'Οι κωδικοί δεν ταιριάζουν', 'reset.error.invalid': 'Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.', 'register.title': 'Εγγραφή', 'register.subtitle': 'Δημιουργία λογαριασμού στο CanHelp', 'register.first_name': 'Όνομα', 'register.last_name': 'Επώνυμο', 'register.email': 'Email', 'register.password': 'Κωδικός (min 8 χαρακτήρες)', 'register.role': 'Ρόλος', 'register.role.customer': 'Χρήστης', 'register.role.customer.desc': 'Δημοσιεύω εργασίες', 'register.role.specialist': 'Ειδικός', 'register.role.specialist.desc': 'Αναλαμβάνω εργασίες', 'register.submit': 'Δημιουργία λογαριασμού', 'register.submitting': 'Εγγραφή...', 'register.has_account': 'Έχεις ήδη λογαριασμό;', 'register.login_link': 'Σύνδεση', 'register.continue_google': 'Εγγραφή με Google', 'register.check_email.title': 'Ελέγξτε το email σας', 'register.check_email.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.', 'register.check_email.login': 'Επιστροφή στη σύνδεση', // Dashboard 'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.new_task': '+ Νέα εργασία', 'dashboard.my_tasks': 'Οι εργασίες μου', 'dashboard.my_offers': 'Οι προσφορές μου', 'dashboard.invitations': 'Προσκλήσεις για εργασία', 'dashboard.offers_count': 'προσφορές', 'dashboard.declined_count': 'απορρίφθηκαν', 'dashboard.completed_tasks': 'Ολοκληρωμένες εργασίες', 'dashboard.completed_offers': 'Ολοκληρωμένες προσφορές', 'dashboard.review_pending': 'Η αξιολόγηση δεν έχει υποβληθεί ακόμα', 'tasks.new.top_specialists': 'Κορυφαίοι ειδικοί', 'tasks.new.select_category': 'Επιλέξτε κατηγορία για να δείτε ειδικούς', 'tasks.new.invite': 'Πρόσκληση', 'tasks.new.invited': 'Επιλέχθηκε ✓', 'reviews.count': 'αξιολογήσεις', 'filter.location': 'Τοποθεσία', 'filter.language': 'Γλώσσες', 'filter.language.any': 'Οποιαδήποτε γλώσσα', 'filter.category.all': 'Όλες οι κατηγορίες', 'user.categories': 'Κατηγορίες', 'user.work_area': 'Περιοχή εργασίας', 'dashboard.tasks.empty': 'Δεν έχεις δημοσιεύσει εργασίες', 'dashboard.tasks.empty.cta': 'Δημοσίευσε την πρώτη σου', 'dashboard.tasks.add_new': 'Πρόσθεσε νέα εργασία', 'dashboard.offers.empty': 'Δεν έχεις υποβάλλει προσφορές', 'dashboard.offers.empty.cta': 'Βρες εργασίες', 'dashboard.customer.specialists_title': 'Ψάχνεις εκτελεστή;', 'dashboard.customer.specialists_hint': 'Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου', 'dashboard.customer.specialists_cta': 'Βρες ειδικό', 'dashboard.customer.how_title': 'Πώς λειτουργεί', 'dashboard.customer.step1': 'Δημιούργησε εργασία με περιγραφή και προϋπολογισμό', 'dashboard.customer.step2': 'Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο', 'dashboard.customer.step3': 'Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία', // Notifications 'notif.title': 'Ειδοποιήσεις', 'notif.mark_all': 'Σήμανση όλων ως αναγνωσμένα', 'notif.empty': 'Δεν υπάρχουν ειδοποιήσεις', 'notif.type.new_offer': 'Νέα προσφορά', 'notif.type.offer_accepted': 'Η προσφορά σας έγινε δεκτή', 'notif.type.offer_declined': 'Η προσφορά σας απορρίφθηκε', 'notif.type.task_completed': 'Η εργασία ολοκληρώθηκε', 'notif.type.task_cancelled': 'Η εργασία ακυρώθηκε', 'notif.type.new_message': 'Νέο μήνυμα', 'notif.type.new_review': 'Νέα αξιολόγηση', 'notif.type.task_invite': 'Πρόσκληση σε εργασία', 'notif.body.new_offer': 'Νέα προσφορά για «{title}»', 'notif.body.offer_accepted': 'Η προσφορά σας για «{title}» έγινε δεκτή', 'notif.body.offer_declined': 'Η προσφορά σας για «{title}» απορρίφθηκε', 'notif.body.task_invite': 'Σας προσκαλούν για «{title}»', 'notif.body.new_review': 'Λάβατε αξιολόγηση {rating}★', // Offer status 'offer.status.pending': 'Εκκρεμεί', 'offer.status.accepted': 'Αποδεκτή', 'offer.status.declined': 'Απορρίφθηκε', 'offer.status.withdrawn': 'Αποσύρθηκε', 'offer.status.other_accepted': 'Επιλέχθηκε άλλος ειδικός', // Common 'common.loading': 'Φόρτωση...', 'common.error': 'Σφάλμα', 'common.save': 'Αποθήκευση', 'common.saving': 'Αποθήκευση...', 'common.cancel': 'Ακύρωση', 'common.add': 'Προσθήκη', 'common.close': 'Κλείσιμο', 'common.edit': 'Επεξεργασία', 'common.delete': 'Διαγραφή', 'common.from': 'από', 'common.currency': '€', 'common.greece': 'Ελλάδα', // Chat 'chat.connected': 'Συνδεδεμένος', 'chat.disconnected': 'Αποσυνδεδεμένος', 'chat.no_rooms': 'Δεν υπάρχουν συνομιλίες ακόμα', 'chat.task_fallback': 'Εργασία', 'chat.select': 'Επίλεξε συνομιλία', 'chat.no_messages': 'Δεν υπάρχουν μηνύματα', 'chat.placeholder': 'Γράψε μήνυμα... (Enter για αποστολή)', 'chat.conversation_fallback': 'Συνομιλία', 'chat.direct_chat': 'Απευθείας συνομιλία', 'chat.linked_task': 'Συνδεδεμένη εργασία', 'chat.write_btn': 'Μήνυμα', 'chat.just_now': 'μόλις τώρα', 'chat.min_ago': 'λ', 'chat.write_specialist': 'Γράψε στον ειδικό', 'chat.write_customer': 'Γράψε στον πελάτη', 'chat.notif_settings': 'Ρυθμίσεις ειδοποιήσεων', 'chat.notif_messages': 'Ειδοποιήσεις για νέα μηνύματα', 'chat.toast_title': 'Νέο μήνυμα', 'chat.toast_open': 'Άνοιγμα συνομιλίας', // Offer form 'offer.price': 'Τιμή', 'offer.price.placeholder': 'π.χ. 80', 'offer.customer_budget': 'Προϋπολογισμός πελάτη', 'offer.message': 'Μήνυμα', 'offer.optional': 'προαιρετικό', 'offer.message.placeholder': 'Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...', 'offer.submitting': 'Αποστολή...', // Profile 'profile.photo': 'Φωτογραφία προφίλ', 'profile.photo.change': 'Αλλαγή φωτογραφίας', 'profile.photo.hint': 'JPEG, PNG, WebP · έως 5MB', 'profile.basic_info': 'Βασικά στοιχεία', 'profile.phone': 'Τηλέφωνο', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Σύντομη περιγραφή', 'profile.bio.placeholder': 'Πες μας λίγα λόγια για εσένα...', 'profile.language': 'Γλώσσα', 'profile.language.hint': 'Γλώσσα διεπαφής και email ειδοποιήσεων', 'profile.languages': 'Γλώσσες επικοινωνίας', 'profile.languages.hint': 'Επιλέξτε όλες τις γλώσσες που μιλάτε', 'profile.skills': 'Δεξιότητες', 'profile.skills.subtitle': 'Προσθέσε τις υπηρεσίες που προσφέρεις', 'profile.skills.placeholder': 'π.χ. Καθαρισμός, IT, Μαθήματα...', 'profile.role': 'Ρόλος λογαριασμού', 'profile.role.specialist': '🔧 Ειδικός', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Χρήστης', 'profile.role.change': 'Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.', 'profile.become_specialist': 'Γίνε Ειδικός', 'profile.become_specialist.desc': 'Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.', 'become_specialist.hero.title': 'Κέρδισε χρήματα κάνοντας αυτό που ξέρεις', 'become_specialist.hero.subtitle': 'Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα', 'become_specialist.how.title': 'Πώς λειτουργεί', 'become_specialist.step1.title': 'Δημιούργησε κάρτα ειδικού', 'become_specialist.step1.desc': 'Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα', 'become_specialist.step2.title': 'Βρες εργασίες', 'become_specialist.step2.desc': 'Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα «Αναζήτηση εργασιών»', 'become_specialist.step3.title': 'Στείλε προσφορά & κέρδισε', 'become_specialist.step3.desc': 'Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες', 'become_specialist.benefits.title': 'Πλεονεκτήματα προφίλ ειδικού', 'become_specialist.benefit1': 'Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία', 'become_specialist.benefit2': 'Δημόσιο προφίλ με αξιολογήσεις πελατών', 'become_specialist.benefit3': 'Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες', 'become_specialist.benefit4': 'Προσθήκη σε αγαπημένα από πελάτες', 'become_specialist.cta': 'Περισσότερα', 'become_specialist.free_badge': 'Δωρεάν εγγραφή', 'profile.tab.notifications': 'Ειδοποιήσεις', 'profile.tab.reviews': 'Αξιολογήσεις', 'profile.tab.referral': 'Παραπομπές', 'profile.tab.auto_response': 'Αυτόματη απάντηση', 'profile.tab.site': 'Site', 'profile.site.title': 'Προσωπική σελίδα', 'profile.site.url_label': 'Προσωπικό site', 'profile.site.copy': 'Αντιγραφή', 'profile.site.copied': 'Αντιγράφηκε', 'profile.site.visible_title': 'Τι εμφανίζεται στη σελίδα σας', 'profile.site.visible.name': 'Όνομα και φωτογραφία', 'profile.site.visible.bio': 'Βιογραφικό', 'profile.site.visible.rating': 'Αξιολόγηση και κριτικές', 'profile.site.visible.portfolio': 'Χαρτοφυλάκιο / Κάρτες', 'profile.site.visible.contacts': 'Στοιχεία επικοινωνίας', 'profile.site.visible.full_last_name': 'Πλήρες επώνυμο', 'profile.site.visible.services': 'Κάρτες υπηρεσιών', 'profile.site.visible.reviews': 'Ενότητα κριτικών', 'profile.site.visible.status': 'Κατάσταση «Έτοιμος να βοηθήσω»', 'profile.site.theme': 'Θέμα εμφάνισης', 'profile.site.theme.dark': 'Σκοτεινό', 'profile.site.theme.light': 'Φωτεινό', 'profile.site.slug_taken': 'Αυτή η διεύθυνση είναι ήδη κατειλημμένη', 'profile.site.stats.title': 'Στατιστικά επισκεψιμότητας', 'profile.site.stats.days': 'τελευταίες 30 ημέρες', 'profile.site.stats.views': 'Προβολές', 'profile.site.stats.unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.messages': 'Μηνύματα', 'profile.site.stats.total_views': 'Συνολικές προβολές', 'profile.site.stats.total_unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.total_messages': 'Μηνύματα', 'profile.site.stats.empty': 'Δεν υπάρχουν δεδομένα ακόμη', 'profile.site.stats.loading': 'Φόρτωση στατιστικών...', 'profile.site.stats.no_slug': 'Ορίστε τη διεύθυνση του site για να δείτε στατιστικά', 'profile.site.edit_bio_hint': 'Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα «Βασικά».', 'status.can_help_now_hint': 'Η κάρτα σου εμφανίζεται ψηλότερα', 'status.need_help_hint': 'Οι ειδικοί μπορούν να σε βοηθήσουν', 'profile.referral.title': 'Πρόγραμμα παραπομπών', 'profile.referral.desc': 'Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.', 'profile.referral.link_label': 'Ο σύνδεσμος παραπομπής σου', 'profile.referral.copy': 'Αντιγραφή', 'profile.referral.copied': 'Αντιγράφηκε!', 'profile.referral.invited_count': 'επιτυχείς παραπομπές', 'profile.referral.no_code': 'Ο κωδικός παραπομπής δεν είναι διαθέσιμος.', 'notifications.title': 'Ρυθμίσεις ειδοποιήσεων', 'notifications.email.new_tasks': 'Email για νέες εργασίες', 'notifications.email.new_tasks.desc': 'Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου', 'notifications.messages.desc': 'Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα', 'notifications.saved': 'Ρυθμίσεις αποθηκεύτηκαν', 'notifications.plan_required': 'Συνδρομή απαιτείται για αυτή τη λειτουργία', 'profile.tab.info': 'Βασικά στοιχεία', 'profile.tab.finance': 'Οικονομικά', 'profile.tab.skills': 'Δεξιότητες', 'profile.tab.categories': 'Κατηγορίες', 'profile.tab.geography': 'Γεωγραφία', 'profile.specialist.categories': 'Κατηγορίες εργασιών', 'profile.specialist.categories.desc': 'Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι', 'profile.specialist.geography': 'Περιοχές κάλυψης', 'profile.specialist.geography.desc': 'Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι', 'profile.saving': 'Αποθήκευση...', 'profile.upload.error': 'Σφάλμα κατά την αναφόρτωση', 'profile.saved': 'Αποθηκεύτηκε', 'profile.tab.cards': 'Χαρτοφυλάκιο', 'profile.cards.count': 'Χαρτοφυλάκια', 'profile.cards.add': 'Νέο χαρτοφυλάκιο', 'profile.cards.new_title': 'Τίτλος νέου χαρτοφυλακίου', 'profile.cards.placeholder': 'π.χ. Υδραυλικά', 'profile.cards.create': 'Δημιουργία', 'profile.cards.cancel': 'Ακύρωση', 'profile.cards.empty': 'Δεν έχετε χαρτοφυλάκιο', 'profile.cards.create_first': 'Δημιουργήστε το πρώτο σας χαρτοφυλάκιο', 'profile.cards.delete_confirm': 'Διαγραφή χαρτοφυλακίου;', 'profile.card.tab.main': 'Γενικά', 'profile.card.tab.skills': 'Δεξιότητες', 'profile.card.tab.categories': 'Κατηγορίες', 'profile.card.tab.geography': 'Γεωγραφία', 'profile.card.tab.portfolio': 'Γκαλερί', 'profile.card.active': 'Ενεργή', 'profile.card.save': 'Αποθήκευση', 'profile.card.saved': 'Αποθηκεύτηκε', 'profile.card.delete': 'Διαγραφή', 'profile.card.skill.add': 'Προσθήκη δεξιότητας', 'profile.card.photo.add': 'Προσθήκη φωτογραφίας', 'profile.card.photo.uploading': 'Μεταφόρτωση...', 'profile.card.photo.empty': 'Δεν υπάρχουν φωτογραφίες', 'profile.card.item.title': 'Τίτλος', 'profile.card.item.desc': 'Περιγραφή', 'profile.card.item.save': 'Αποθήκευση', 'profile.card.item.cancel': 'Ακύρωση', 'profile.card.item.edit': 'Επεξεργασία', 'profile.upgrade.cards_limit': 'Όριο χαρτοφυλακίων εξαντλήθηκε', 'profile.upgrade.plan': 'Τρέχον πλάνο:', 'profile.upgrade.contact': 'Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου', 'profile.upgrade.ok': 'Εντάξει', 'profile.plan.title': 'Πλάνο συνδρομής', 'profile.balance': 'Υπόλοιπο', 'profile.balance.topup': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.amount': 'Ποσό (σε EUR)', 'profile.balance.topup.hint': 'Επιλέξτε ποσό ή εισαγάγετε μανούαλα', 'profile.balance.topup.submit': 'Πληρωμή', 'profile.balance.topup.loading': 'Ρεδιρεκτάρισμα...', 'profile.balance.topup.error': 'Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.', 'payment.success.title': 'Πληρωμή επιτυχής!', 'payment.success.desc': 'Το υπόλοιπό σας ενημερώθηκε.', 'payment.cancelled.title': 'Ακύρωση πληρωμής', 'payment.cancelled.desc': 'Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.', 'payment.pending.title': 'Σε εξέλιξη...', 'payment.pending.desc': 'Επεξεργαζόμαστε την πληρωμή σας.', 'payment.back_to_profile': 'Επιστροφή στο προφίλ', 'profile.plan.basic': 'Βασικό (δωρεάν)', 'profile.plan.contact_upgrade': 'Επικοινωνήστε με τον διαχειριστή για αναβάθμιση', 'profile.plan.cards_up_to': 'Χαρτοφυλάκια: έως', 'profile.plan.cards_unlimited': 'Χαρτοφυλάκια: απεριόριστα', 'profile.plan.tasks_up_to': 'Εργασίες: έως', 'profile.plan.offers_up_to': 'Προσφορές: έως', 'profile.plan.valid_until': 'Ισχύει έως', 'profile.plan.no_expiry': 'Δεν λήγει', // Create task 'create.error': 'Σφάλμα κατά τη δημοσίευση', // Tasks list extras 'tasks.category.general': 'Γενικά', 'tasks.budget.range': 'Εύρος:', 'tasks.budget.from': 'από', 'tasks.budget.to': 'έως', 'tasks.filter.reset': 'Εκκαθάριση φίλτρων', 'tasks.load_more': 'Φόρτωση ακόμα', 'tasks.showing': 'Αποτελέσματα:', 'tasks.field.budget': 'Προϋπολογισμός, €', // Admin 'admin.title': 'Πίνακας Διαχείρισης', 'admin.tab.stats': 'Στατιστικά', 'admin.tab.users': 'Χρήστες', 'admin.tab.tasks': 'Εργασίες', 'admin.tab.reports': 'Αναφορές', 'admin.stats.users': 'Χρήστες', 'admin.stats.tasks': 'Εργασίες', 'admin.stats.offers': 'Προσφορές', 'admin.stats.reviews': 'Αξιολογήσεις', 'admin.tasks.by_status': 'Εργασίες ανά κατάσταση', 'admin.col.user': 'Χρήστης', 'admin.col.email': 'Email', 'admin.col.role': 'Ρόλος', 'admin.col.registered': 'Εγγραφή', 'admin.col.status': 'Κατάσταση', 'admin.col.title': 'Τίτλος', 'admin.col.budget': 'Προϋπολογισμός', 'admin.col.created': 'Δημιουργία', 'admin.users.active': 'Ενεργός', 'admin.users.inactive': 'Ανενεργός', 'admin.users.deactivate': 'Απενεργοποίηση', 'admin.users.activate': 'Ενεργοποίηση', 'admin.tasks.cancel': 'Ακύρωση', 'admin.reports.none': 'Δεν υπάρχουν αναφορές', 'admin.reports.reviewed': 'Αναθεωρήθηκε', 'admin.reports.dismiss': 'Απόρριψη', 'admin.pagination.total': 'Σύνολο', 'admin.users.role.change': 'Αλλαγή ρόλου', 'admin.users.search.placeholder': 'Αναζήτηση ονόματος ή email...', 'admin.tasks.delete': 'Διαγραφή', 'admin.tasks.delete.confirm': 'Διαγραφή αυτής της εργασίας μόνιμα;', 'admin.tasks.search.placeholder': 'Αναζήτηση τίτλου...', 'admin.col.customer': 'Πελάτης', 'admin.col.reporter': 'Καταγγέλλων', 'admin.col.target': 'Στόχος', 'admin.filter.all_roles': 'Όλοι οι ρόλοι', 'admin.filter.all_statuses': 'Όλες οι καταστάσεις', 'admin.reports.target.task': 'Εργασία', 'admin.reports.target.user': 'Χρήστης', 'admin.tab.categories': 'Κατηγορίες', 'admin.tab.locations': 'Πόλεις & Περιοχές', 'admin.tab.logs': 'Αρχεία', 'admin.tab.plans': 'Πακέτα', 'admin.tab.settings': 'Ρυθμίσεις', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Δραστηριότητα', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Ειδοποιήσεις', 'admin.notif_logs.type': 'Τύπος', 'admin.notif_logs.title': 'Τίτλος', 'admin.notif_logs.read': 'Διαβασμένο', 'admin.notif_logs.empty': 'Δεν υπάρχουν αρχεία ειδοποιήσεων', 'admin.stats.notif_chart_title': 'Ειδοποιήσεις ανά ημέρα', 'admin.stats.notif_label': 'Ειδοποιήσεις', 'admin.stats.mail_chart_title': 'Emails ανά ημέρα', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Όλα', 'admin.stats.specialists': 'Ειδικοί', 'admin.col.plan': 'Πακέτο', 'admin.back_home': 'Αρχική', 'admin.plans.title': 'Πακέτα συνδρομής', 'admin.plans.add': '+ Νέο πακέτο', 'admin.plans.empty': 'Δεν υπάρχουν πακέτα', 'admin.plans.form.new': 'Νέο πακέτο', 'admin.plans.form.edit': 'Επεξεργασία πακέτου', 'admin.plans.form.name': 'Όνομα', 'admin.plans.form.price': 'Τιμή (EUR)', 'admin.plans.form.old_price': 'Παλιά τιμή (EUR, προαιρετικό)', 'admin.plans.form.max_offers': 'Μέγ. προσφορές (κενό = χωρίς όριο)', 'admin.plans.form.max_cards': 'Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)', 'admin.plans.form.duration_days': 'Διάρκεια (ημέρες, κενό = χωρίς λήξη)', 'admin.plans.form.description': 'Περιγραφή', 'admin.plans.form.features': 'Δυνατότητες (μία ανά γραμμή)', 'admin.plans.form.notify': 'Ειδοποιήσεις νέων εργασιών', 'admin.plans.form.default': 'Προεπιλογή', 'admin.plans.form.active': 'Ενεργό', 'admin.plans.form.order': 'Σειρά', 'admin.plans.form.role': 'Ρόλος', 'admin.plans.form.tier': 'Επίπεδο', 'admin.plans.form.role.customer': 'Πελάτης', 'admin.plans.form.role.specialist': 'Ειδικός', 'admin.plans.form.tier.free': 'Δωρεάν', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Όρια (κενό = χωρίς όριο)', 'admin.plans.form.max_messages_day': 'Μέγ. μηνύματα/ημέρα', 'admin.plans.form.max_orders_day': 'Μέγ. παραγγελίες/ημέρα', 'admin.plans.form.max_skills': 'Μέγ. δεξιότητες', 'admin.plans.form.max_profiles': 'Μέγ. προφίλ', 'admin.plans.form.max_portfolio': 'Μέγ. στοιχεία χαρτοφυλακίου', 'admin.plans.form.section.boost': 'Πολλαπλασιαστές & Ενίσχυση', 'admin.plans.form.search_boost': 'Ενίσχυση αναζήτησης', 'admin.plans.form.offers_multiplier': 'Πολλαπλασιαστής προσφορών', 'admin.plans.form.section.contact': 'Δικαιώματα επικοινωνίας', 'admin.plans.form.can_contact_free': 'Επικοινωνία με δωρεάν χρήστες', 'admin.plans.form.can_contact_pro': 'Επικοινωνία με Pro χρήστες', 'admin.plans.form.can_contact_all': 'Επικοινωνία με όλους', 'admin.plans.form.can_show_contact': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.plans.form.can_view_phone': 'Προβολή τηλεφώνου', 'admin.plans.form.section.features': 'Λειτουργίες', 'admin.plans.form.upload_video': 'Μεταφόρτωση βίντεο', 'admin.plans.form.favorites': 'Αγαπημένα', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Σήμα επαλήθευσης', 'admin.plans.form.highlighted_reviews': 'Προβεβλημένες κριτικές', 'admin.plans.form.personal_site': 'Προσωπική σελίδα', 'admin.plans.form.can_help_now': 'Κατάσταση «Μπορώ να βοηθήσω»', 'admin.plans.form.need_help': 'Κατάσταση «Χρειάζομαι βοήθεια»', 'admin.plans.form.auto_response': 'Αυτόματη απάντηση', 'admin.plans.form.auto_match': 'Αυτόματη αντιστοίχιση', 'admin.plans.form.instant_dispatch_free': 'Άμεση αποστολή (δωρεάν)', 'admin.plans.form.instant_dispatch_pro': 'Άμεση αποστολή (Pro)', 'admin.plans.badge.default': 'Προεπιλογή', 'admin.plans.badge.inactive': 'Ανενεργό', 'admin.plans.make_default': 'Ορισμός ως προεπιλογή', 'admin.plans.tasks': 'Εργασίες', 'admin.plans.offers': 'Προσφορές', 'admin.plans.cards': 'Χαρτοφυλάκιο', 'admin.plans.notify_tasks': 'Ειδοποιήσεις εργασιών', 'admin.plans.delete.confirm': 'Διαγραφή πακέτου', 'admin.activity.title': 'Αρχείο δραστηριότητας', 'admin.activity.event': 'Γεγονός', 'admin.activity.all_events': 'Όλα τα γεγονότα', 'admin.activity.from': 'Από', 'admin.activity.to': 'Έως', 'admin.activity.reset': 'Επαναφορά', 'admin.activity.total': 'Σύνολο', 'admin.activity.empty': 'Δεν υπάρχουν εγγραφές', 'admin.mail.event': 'Συμβάν email', 'admin.mail.all_events': 'Όλα τα email συμβάντα', 'admin.mail.from': 'Από', 'admin.mail.to': 'Έως', 'admin.mail.reset': 'Επαναφορά', 'admin.mail.total': 'Σύνολο', 'admin.mail.empty': 'Δεν υπάρχουν email logs', 'admin.mail.recipient': 'Παραλήπτης', 'admin.mail.provider': 'Πάροχος', 'admin.mail.details': 'Λεπτομέρειες', 'admin.mail.status': 'Κατάσταση', 'admin.mail.success': 'Επιτυχία', 'admin.mail.failed': 'Σφάλμα', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'Δεν υπάρχουν εγγραφές', 'admin.logs.date': 'Ημερομηνία', 'admin.logs.provider': 'Πάροχος', 'admin.logs.model': 'Μοντέλο', 'admin.logs.action': 'Ενέργεια', 'admin.logs.langs': 'Γλώσσες', 'admin.logs.in': 'Είσοδος', 'admin.logs.out': 'Έξοδος', 'admin.logs.total': 'Σύνολο', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Κατάσταση', 'admin.stats.activity_30d': 'Δραστηριότητα 30 ημερών', 'admin.stats.tasks_label': 'Εργασίες', 'admin.stats.users_label': 'Χρήστες', 'admin.stats.specialists_label': 'Ειδικοί', 'admin.stats.tokens_title': 'Χρήση tokens (ανά μήνα)', 'admin.stats.tokens_out': 'Εξερχόμενα', 'admin.stats.tokens_in': 'Εισερχόμενα', 'admin.stats.tokens_out_label': 'Εξερχόμενα tokens', 'admin.stats.tokens_in_label': 'Εισερχόμενα tokens', 'admin.stats.cost_label': 'Κόστος (USD)', 'admin.stats.tasks_by_status': 'Εργασίες ανά κατάσταση', 'admin.task_status.open': 'Ανοιχτές', 'admin.task_status.in_progress': 'Σε εξέλιξη', 'admin.task_status.completed': 'Ολοκληρωμένες', 'admin.task_status.cancelled': 'Ακυρωμένες', 'admin.task_status.draft': 'Προσχέδια', 'admin.settings.tab.general': 'Γενικά', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Ειδοποιήσεις', 'admin.settings.tab.payment': 'Πληρωμή', 'admin.settings.tab.referral': 'Παραπομπές', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Κοινωνικά δίκτυα', 'admin.settings.socials.title': 'Σύνδεσμοι κοινωνικών δικτύων', 'admin.settings.socials.hint': 'Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο', 'admin.settings.seo.maintenance_label': 'Λειτουργία συντήρησης', 'admin.settings.seo.maintenance_hint': 'Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες', 'admin.settings.seo.indexing_label': 'Ευρετηρίαση από μηχανές αναζήτησης', 'admin.settings.seo.indexing_hint': 'Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο', 'admin.settings.seo.head_scripts_label': 'Scripts στο (JS)', 'admin.settings.seo.head_scripts_hint': 'Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)', 'admin.settings.seo.site_title_label': 'Τίτλος ιστότοπου', 'admin.settings.seo.site_description_label': 'Περιγραφή ιστότοπου (meta description)', 'admin.settings.referral.title': 'Πρόγραμμα παραπομπών', 'admin.settings.referral.hint': 'Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.', 'admin.settings.referral.enabled_label': 'Ενεργό', 'admin.settings.referral.enabled_hint': 'Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών', 'admin.settings.referral.customer_section': 'Για πελάτες', 'admin.settings.referral.specialist_section': 'Για ειδικούς', 'admin.settings.referral.plan_label': 'Πλάνο ανταμοιβής', 'admin.settings.referral.no_plan': '— χωρίς πλάνο —', 'admin.settings.referral.plan_hint': 'Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.', 'admin.settings.referral.days_label': 'Ημέρες ανταμοιβής', 'admin.settings.referral.days_hint': 'Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.', 'admin.settings.general.title': 'Γενικές ρυθμίσεις', 'admin.settings.general.site_name': 'Όνομα ιστότοπου', 'admin.settings.general.site_url': 'URL ιστότοπου', 'admin.settings.general.contact_email': 'Email επικοινωνίας', 'admin.settings.general.support_phone': 'Τηλέφωνο υποστήριξης', 'admin.settings.smtp.title': 'Ρυθμίσεις SMTP', 'admin.settings.smtp.hint': 'Χρησιμοποιείται για αποστολή ειδοποιήσεων email.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Θύρα', 'admin.settings.smtp.encryption': 'Κρυπτογράφηση', 'admin.settings.smtp.enc.none': 'Χωρίς', 'admin.settings.smtp.enc.tls': 'STARTTLS (θύρα 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (θύρα 465)', 'admin.settings.smtp.username': 'Όνομα χρήστη', 'admin.settings.smtp.password': 'Κωδικός / App Password', 'admin.settings.smtp.from_name': 'Όνομα αποστολέα', 'admin.settings.smtp.from_email': 'Email αποστολέα', 'admin.settings.smtp.test': 'Αποστολή δοκιμαστικού email', 'admin.settings.smtp.sending': 'Αποστολή...', 'admin.settings.payment.hint': 'Τα στοιχεία για ePay Piraeus Bank.', 'admin.settings.env.test': 'Δοκιμαστικό (sandbox)', 'admin.settings.env.prod': 'Παραγωγή', 'admin.settings.env.label': 'Περιβάλλον', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Ενεργό', 'admin.settings.saving': 'Αποθήκευση...', 'admin.settings.saved': '✓ Αποθηκεύτηκε', 'admin.notif.vars_hint': 'Διαθέσιμες μεταβλητές στα πρότυπα', 'admin.notif.tmpl.not_set': 'Πρότυπο δεν έχει οριστεί', 'admin.notif.tmpl.subject_label': 'Θέμα email', 'admin.notif.tmpl.body_label': 'Κείμενο email (HTML)', 'admin.notif.tmpl.save': 'Αποθήκευση', 'admin.notif.tmpl.close': 'Κλείσιμο', 'admin.notif.tmpl.translate': 'Αυτόματη μετάφραση', 'admin.notif.tmpl.translating': 'Μετάφραση...', 'admin.notif.tmpl.saving': 'Αποθήκευση...', 'admin.notif.email_verification': 'Επαλήθευση email', 'admin.notif.registration_success': 'Επιτυχής εγγραφή', 'admin.notif.password_reset': 'Επαναφορά κωδικού', 'admin.notif.new_offer': 'Νέα προσφορά', 'admin.notif.new_task': 'Νέα εργασία', 'admin.notif.offer_accepted': 'Προσφορά αποδεκτή', 'admin.notif.new_message': 'Νέο μήνυμα', 'admin.notif.offer_declined': 'Απόρριψη προσφοράς', 'admin.notif.offer_other_accepted': 'Επιλέχθηκε άλλος ειδικός', 'admin.notif.task_updated': 'Ενημέρωση εργασίας', 'admin.notif.deadline_reminder': 'Υπενθύμιση προθεσμίας', 'admin.notif.task_archived': 'Αυτόματη απόσυρση εργασίας', 'admin.notif.referral_reward': 'Ανταμοιβή παραπομπής', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Τιμολόγιο — ενεργοποίηση πλάνου', 'admin.email_template.plan_upgraded': 'Τιμολόγιο — αναβάθμιση πλάνου', 'admin.email_template.plan_downgrade_scheduled': 'Τιμολόγιο — προγραμματισμένη υποβάθμιση', 'admin.email_template.plan_downgrade_applied': 'Τιμολόγιο — εφαρμογή υποβάθμισης', 'admin.email_template.plan_renewal_reminder': 'Τιμολόγιο — υπενθύμιση ανανέωσης', 'admin.email_template.plan_insufficient_funds': 'Τιμολόγιο — ανεπαρκές υπόλοιπο', // Pricing confirm modal 'pricing.confirm.title': 'Επιβεβαίωση επιλογής πλάνου', 'pricing.confirm.plan': 'Πλάνο', 'pricing.confirm.prorated': 'Αναλογική έκπτωση', 'pricing.confirm.effective_price': 'Προς πληρωμή', 'pricing.confirm.your_balance': 'Το υπόλοιπό σας', 'pricing.confirm.downgrade_info': 'Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.', 'pricing.confirm.insufficient': 'Ανεπαρκές υπόλοιπο.', 'pricing.confirm.top_up': 'Ανανέωση', 'pricing.confirm.schedule_downgrade': 'Προγραμματισμός μετάβασης', 'pricing.confirm.pay': 'Πληρωμή', 'admin.user_edit.title': 'Επεξεργασία χρήστη', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Διευθυνση email επαληθεύτηκε', 'admin.user_edit.email_not_verified': 'Email δεν έχει επαληθευτεί', 'admin.user_edit.verify_email_btn': 'Χειροκίνητη επαλήθευση', 'admin.user_edit.verify_email_done': 'Email επαληθεύτηκε!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Εγγραφή', 'admin.user_edit.last_seen': 'Τελευταία σύνδεση', 'admin.user_edit.lang': 'Γλώσσα', 'admin.user_edit.first_name': 'Όνομα', 'admin.user_edit.last_name': 'Επώνυμο', 'admin.user_edit.phone': 'Τηλέφωνο', 'admin.user_edit.bio': 'Βιογραφικό', 'admin.user_edit.role': 'Ρόλος', 'admin.user_edit.plan': 'Πακέτο', 'admin.user_edit.no_plan': '— Χωρίς πακέτο —', 'admin.user_edit.active': 'Ενεργός λογαριασμός', 'admin.user_edit.balance': 'Υπόλοιπο (EUR)', 'admin.user_edit.skills': 'Δεξιότητες', 'admin.user_edit.tab.profile': 'Προφίλ', 'admin.user_edit.tab.account': 'Λογαριασμός', 'admin.user_edit.tab.balance': 'Υπόλοιπο', 'admin.user_edit.tab.settings': 'Ρυθμίσεις', 'admin.user_edit.tab.specialist': 'Χαρτοφυλάκιο', 'admin.user_edit.tab.site': 'Ιστοσελίδα', 'admin.user_edit.plan_expires': 'Λήξη πλάνου', 'admin.user_edit.interface_lang': 'Γλώσσα διεπαφής', 'admin.user_edit.comm_languages': 'Γλώσσες επικοινωνίας', 'admin.user_edit.personal_site_slug': 'Προσωπική σελίδα', 'admin.user_edit.show_contact_info': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.user_edit.show_contact_info.hint': 'Ορατό στους πελάτες', 'admin.user_edit.notify_new_tasks': 'Ειδοποίηση για νέες εργασίες', 'admin.user_edit.notify_new_tasks.hint': 'Push και email ειδοποιήσεις', 'admin.user_edit.notif_messages': 'Ειδοποιήσεις μηνυμάτων', 'admin.user_edit.notif_messages.hint': 'Νέα μηνύματα στη συνομιλία', 'admin.user_edit.site_settings': 'Ρυθμίσεις προσωπικής σελίδας', 'admin.user_edit.categories': 'Κατηγορίες υπηρεσιών', 'admin.user_edit.locations': 'Περιοχές εξυπηρέτησης', 'admin.user_edit.skill_placeholder': 'Νέα δεξιότητα...', 'admin.user_edit.add_category': '— Επιλέξτε κατηγορία —', 'admin.user_edit.add_location': '— Επιλέξτε περιοχή —', 'admin.user_edit.specialist_cards': 'Χαρτοφυλάκιο ειδικού', 'admin.user_edit.no_cards': 'Δεν βρέθηκαν στοιχεία χαρτοφυλακίου', 'admin.user_edit.card_title': 'Τίτλος χαρτοφυλακίου', 'admin.user_edit.card_description': 'Περιγραφή', 'admin.balance.topup.btn': 'Αναπλήρωση', 'admin.balance.withdraw.btn': 'Αφαίρεση', 'admin.balance.modal_hint': 'Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό', 'admin.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'admin.balance.topup.amount': 'Ποσό', 'admin.balance.topup.description': 'Σχόλιο', 'admin.balance.topup.description.placeholder': 'Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση', 'admin.balance.topup.submit': 'Αναπλήρωση υπολοίπου', 'admin.balance.withdraw.title': 'Αφαίρεση υπολοίπου', 'admin.balance.withdraw.amount': 'Ποσό', 'admin.balance.withdraw.description': 'Σχόλιο', 'admin.balance.withdraw.description.placeholder': 'Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση', 'admin.balance.withdraw.submit': 'Αφαίρεση από το υπόλοιπο', 'admin.user_edit.role.customer': 'Πελάτης', 'admin.user_edit.role.specialist': 'Ειδικός', 'admin.user_edit.role.admin': 'Διαχειριστής', 'common.refresh': 'Ανανέωση', 'common.back_home': 'Αρχική', 'admin.loc.hint': 'Διαχείριση πόλεων και συνοικιών', 'admin.loc.add_city': 'Νέα πόλη', 'admin.loc.add_district': 'Προσθήκη συνοικίας', 'admin.loc.new': 'Νέα τοποθεσία', 'admin.loc.edit': 'Επεξεργασία τοποθεσίας', 'admin.loc.district': 'συνοικία', 'admin.loc.empty': 'Δεν υπάρχουν τοποθεσίες', 'admin.loc.delete.confirm': 'Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.', 'admin.cat.add_root': 'Νέα κατηγορία', 'admin.cat.add_sub': 'Υποκατηγορία', 'admin.cat.edit': 'Επεξεργασία', 'admin.cat.delete': 'Διαγραφή', 'admin.cat.delete.confirm': 'Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Εικονίδιο', 'admin.cat.name_el': 'Ελληνικά', 'admin.cat.name_en': 'Αγγλικά', 'admin.cat.name_ru': 'Ρωσικά', 'admin.cat.order': 'Σειρά', 'admin.cat.active': 'Ενεργή', 'admin.cat.parent': 'Γονική κατηγορία', 'admin.cat.no_parent': 'Κορυφαίο επίπεδο', 'admin.cat.save': 'Αποθήκευση', 'admin.cat.cancel': 'Ακύρωση', 'admin.cat.empty': 'Δεν υπάρχουν κατηγορίες', 'admin.cat.hint': 'Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία', 'admin.cat.new': 'Νέα κατηγορία', 'admin.cat.subcategory': 'υποκατηγορία', 'admin.cat.add_child': 'Προσθήκη υποκατηγορίας', 'admin.cat.inactive': 'Ανενεργή', 'admin.event.user_login': 'Σύνδεση', 'admin.event.user_register': 'Εγγραφή', 'admin.event.admin_user_deactivate': 'Αποκλεισμός χρήστη', 'admin.event.admin_user_activate': 'Ενεργοποίηση χρήστη', 'admin.event.admin_user_role_changed': 'Αλλαγή ρόλου', 'admin.event.admin_task_cancelled': 'Ακύρωση εργασίας', 'admin.event.admin_task_deleted': 'Διαγραφή εργασίας', 'admin.event.admin_report_reviewed': 'Αναφορά εξετάστηκε', 'admin.event.admin_report_dismissed': 'Αναφορά απορρίφθηκε', 'admin.event.task_created': 'Δημιουργία εργασίας', 'user.online': 'Σε σύνδεση', 'user.seen_minutes': 'ήταν εδώ πριν {n} λεπτά', 'user.seen_hours': 'ήταν εδώ πριν {n} ώρες', 'user.seen_yesterday': 'ήταν εδώ χθες', 'user.seen_days': 'ήταν εδώ πριν {n} μέρες', // Specialists 'specialists.title': 'Ειδικοί', 'specialists.search': 'Αναζήτηση ειδικού...', 'specialists.search.btn': 'Αναζήτηση', 'specialists.empty': 'Δεν βρέθηκαν ειδικοί', 'specialists.no_bio': 'Χωρίς περιγραφή', 'specialists.view': 'Προβολή προφίλ', 'specialists.reviews': 'αξιολογήσεις', 'specialist.favorite': 'Προσθήκη στα αγαπημένα', 'specialist.unfavorite': 'Αφαίρεση από αγαπημένα', 'specialist.site_link': 'Προσωπικό site', 'favorites.specialists.title': 'Αγαπημένοι ειδικοί', 'favorites.specialists.empty': 'Δεν έχετε αγαπημένους ειδικούς', 'nav.favorites': 'Αγαπημένα', 'nav.schedule': 'Πρόγραμμα', 'nav.find_tasks': 'Αναζήτηση εργασιών', 'schedule.title': 'Το πρόγραμμά μου', 'schedule.subtitle': 'Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας', 'schedule.available': 'Ελεύθερος', 'schedule.busy': 'Απασχολημένος', 'schedule.unset': 'Μη ορισμένο', 'schedule.click_hint': '← κλικ για εναλλαγή κατάστασης', 'schedule.range_mode': 'Επιλογή εύρους', 'schedule.range_from': 'Από {date} — επιλέξτε τελική ημερομηνία', 'schedule.click_to_set': 'Κλικ για ορισμό', 'schedule.free': 'ελεύθερα', 'schedule.busy_count': 'απασχολημένα', 'schedule.free_days': 'ελεύθερες ημέρες', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Σύνδεση με Google Calendar', 'schedule.disconnectGoogle': 'Αποσύνδεση', 'schedule.connectedAs': 'Συνδεδεμένο ως', 'schedule.importFromGoogle': 'Συγχρονισμός από Google', 'schedule.gcalConnected': '✓ Google Calendar συνδέθηκε', 'schedule.gcalError': 'Σφάλμα σύνδεσης Google Calendar', 'schedule.gcalImportDone': 'Εισήχθησαν {n} ημερ. από Google Calendar', 'schedule.gcalAutoSyncNote': 'Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar', 'schedule.gcalConnectDesc': 'Συνδέστε το Google Calendar για αυτόματο συγχρονισμό', 'schedule.gcalDisconnectConfirm': 'Αποσύνδεση Google Calendar;', 'find_tasks.title': 'Αναζήτηση εργασιών', 'find_tasks.for_me': 'Για μένα', 'find_tasks.all': 'Όλες οι εργασίες', 'find_tasks.by_category': 'Ανά κατηγορία', 'find_tasks.list': 'Λίστα', 'find_tasks.already_offered': 'Προσφορά υποβλήθηκε', 'find_tasks.offer_now': 'Υποβολή προσφοράς', 'find_tasks.empty_for_me': 'Δεν βρέθηκαν εργασίες στις κατηγορίες σας', 'find_tasks.banner_hint': 'Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας', 'find_tasks.no_cards': 'Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς', 'find_tasks.add_card': 'Δημιουργία χαρτοφυλακίου', 'find_tasks.search': 'Αναζήτηση εργασιών...', 'find_tasks.tasks_count': 'εργασίες', // Footer 'footer.tagline': 'Η πλατφόρμα εργασιών για την Ελλάδα', 'footer.rights': 'Όλα τα δικαιώματα διατηρούνται.', // App download section 'app.download_title': 'Κατεβάστε την εφαρμογή CanHelp', 'app.download_desc': 'Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.', // Nav 'nav.pricing': 'Τιμές', // Pricing page 'pricing.title': 'Τιμολόγηση', 'pricing.subtitle': 'Επιλέξτε το κατάλληλο πρόγραμμα', 'pricing.role.customer': 'Πελάτης', 'pricing.role.specialist': 'Ειδικός', 'pricing.free': 'Δωρεάν', 'pricing.per_month': 'μήνα', 'pricing.duration': 'Διάρκεια', 'pricing.days': 'ημ.', 'pricing.current_plan': 'Το πρόγραμμά σας', 'pricing.popular': 'Δημοφιλές', 'pricing.choose': 'Επιλογή', 'pricing.your_plan': 'Ενεργό πρόγραμμα', 'pricing.free_default': 'Προεπιλογή', 'pricing.compare': 'Σύγκριση λειτουργιών', 'pricing.feature': 'Λειτουργία', 'pricing.faq_note': 'Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.', 'pricing.feat.messages': 'Μηνύματα / ημέρα', 'pricing.feat.orders': 'Παραγγελίες / ημέρα', 'pricing.feat.contact_all': 'Επικοινωνία με όλους', 'pricing.feat.view_phone': 'Εμφάνιση τηλεφώνου', 'pricing.feat.show_contact': 'Εμφάνιση στοιχείων επαφής', 'pricing.feat.favorites': 'Αγαπημένα', 'pricing.feat.verified_badge': 'Επαληθευμένο badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Προσωπικό site', 'pricing.feat.auto_response': 'Αυτόματη απάντηση', 'pricing.feat.auto_match': 'Αυτόματη αντιστοίχιση', 'pricing.feat.highlighted_reviews': 'Επισημασμένες αξιολογήσεις', 'pricing.feat.portfolio': 'Στοιχεία χαρτοφυλακίου', 'pricing.feat.cards': 'Κάρτες ειδικού', 'pricing.feat.notify_tasks': 'Ειδοποιήσεις νέων εργασιών', 'pricing.feat.video': 'Βίντεο στο χαρτοφυλάκιο', // Upgrade prompt 'upgrade.available_in': 'Διαθέσιμο στο', 'upgrade.cta': 'Αναβάθμιση', // Dashboard plan block 'dashboard.plan.title': 'Το πρόγραμμά μου', 'dashboard.plan.expires': 'Λήγει σε {n} ημέρες', 'dashboard.plan.upgrade': 'Αναβάθμιση προγράμματος', 'dashboard.plan.no_plan': 'Δωρεάν πρόγραμμα', 'dashboard.plan.messages': 'Μηνύματα σήμερα', 'dashboard.plan.orders': 'Παραγγελίες σήμερα', 'dashboard.plan.limits': 'Ημερήσια όρια', 'dashboard.plan.features': 'Λειτουργίες', 'dashboard.plan.stats': 'Στατιστικά', 'dashboard.stats.cards': 'Χαρτοφυλάκια', 'dashboard.stats.maxCards': 'Μέγ. χαρτοφυλάκια', 'dashboard.stats.portfolioItems': 'Στοιχεία portfolio', 'dashboard.stats.maxPortfolioItems': 'Μέγ. στοιχεία', 'dashboard.stats.activeOffers': 'Ενεργές προσφορές', 'dashboard.stats.reviewsReceived': 'Αξιολογήσεις', 'dashboard.stats.activeTasks': 'Ενεργές εργασίες', 'dashboard.stats.completedTasks': 'Ολοκληρωμένες', 'status.can_help_now': 'Είμαι διαθέσιμος τώρα', 'status.need_help': 'Χρειάζομαι βοήθεια', 'status.active': 'Ενεργό', 'status.toggle_on': 'Ενεργοποίηση', 'status.toggle_off': 'Απενεργοποίηση', // FOMO 'fomo.missed_orders': 'Χάσατε {n} παραγγελίες', 'fomo.missed_value': 'Αξία €{v}', 'fomo.upgrade_hint': 'Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες', 'fomo.conversion': 'Μετατροπές εργασιών', 'fomo.active': 'Ενεργές', 'fomo.with_offers': 'Με προσφορές', 'fomo.completed': 'Ολοκληρωμένες', 'fomo.already_offered': '{n} ειδικοί έχουν ήδη απαντήσει', 'fomo.specialist_missed': 'Χάσατε {n} παραγγελίες', 'fomo.top_categories': 'Κατηγορίες', 'fomo.offers_received': 'προσφορές ελήφθησαν', 'fomo.avg_offers': 'Μέσο {n}/εργασία', 'fomo.completion_rate': 'ολοκληρωμένες', // Task auto-match 'task.auto_match': 'Αυτόματη αντιστοίχιση', 'task.auto_match_results': 'Κορυφαίοι ειδικοί', 'task.no_offer_yet': 'Δεν έχετε στείλει προσφορά ακόμα', 'task.make_offer': 'Αποστολή προσφοράς', 'auto_response.title': 'Αυτόματη Απάντηση', 'auto_response.enabled': 'Ενεργοποίηση αυτόματης απάντησης', 'auto_response.min_budget': 'Ελάχ. προϋπολογισμός', 'auto_response.max_budget': 'Μέγ. προϋπολογισμός', 'auto_response.default_price': 'Προεπιλεγμένη τιμή', 'auto_response.default_message': 'Προεπιλεγμένο μήνυμα', 'auto_response.max_per_day': 'Μέγ. αυτόματες προσφορές/ημέρα', 'auto_response.save': 'Αποθήκευση', 'auto_response.saved': 'Αποθηκεύτηκε', 'auto_response.categories': 'Κατηγορίες', 'auto_response.locations': 'Τοποθεσίες', // Personal site 'profile.personal_site': 'Προσωπικό Site', 'profile.site_slug': 'Slug URL', 'profile.site_slug_hint': 'Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _', 'profile.site_open': 'Άνοιγμα site', 'profile.site_preview': 'Το site σας', 'profile.show_contact': 'Εμφάνιση στοιχείων επαφής', 'profile.show_contact_hint': 'Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας', // Google Calendar plan gate 'gcal.upgrade_required': 'Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα', // Chat limits 'chat.limit_warning': 'Απομένουν {n} μηνύματα σήμερα', 'chat.limit_reached': 'Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας', 'chat.upgrade': 'Αναβάθμιση', // Site page 'site.member_since': 'Μαζί μας από', 'site.rating': 'Βαθμολογία', 'site.completed_tasks': 'Ολοκληρώθηκαν', 'site.languages': 'Γλώσσες', 'site.photos': 'φωτ.', 'site.contact_form': 'Επικοινωνία', 'site.contact_sent': 'Το μήνυμα στάλθηκε!', 'site.contact_sent_desc': 'Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα', 'site.contact_name': 'Όνομα', 'site.contact_name_ph': 'Το όνομά σας', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Μήνυμα', 'site.contact_message_ph': 'Περιγράψτε την εργασία σας...', 'site.contact_send': 'Αποστολή', 'site.share': 'Κοινοποίηση', 'site.speaks_languages': 'Μιλάει', 'site.message_sent': 'Το μήνυμα εστάλη!', 'site.message_sent_desc': 'Ο ειδικός θα το λάβει στη συνομιλία', 'site.message_placeholder': 'Γράψτε το μήνυμά σας...', 'site.write_to_chat': 'Γράψτε στο chat', 'site.auth_required_title': 'Απαιτείται σύνδεση', 'site.auth_required_desc': 'Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.', 'site.auth_login_btn': 'Σύνδεση', 'site.auth_contact_form_btn': 'Επικοινωνία μέσω φόρμας', 'specialist.services': 'Υπηρεσίες', 'portfolio.title': 'Χαρτοφυλάκιο', 'common.not_found': 'Η σελίδα δεν βρέθηκε', 'common.anonymous': 'Ανώνυμα', 'specialist_setup.page_title': 'Ρύθμιση προφίλ ειδικού', 'specialist_setup.step_of': 'Βήμα {current} από {total}', 'specialist_setup.next': 'Επόμενο', 'specialist_setup.back': 'Πίσω', 'specialist_setup.skip': 'Παράλειψη', 'specialist_setup.finish': 'Ολοκλήρωση', 'specialist_setup.go_to_profile': 'Μεταβείτε στο προφίλ', 'specialist_setup.browse_tasks': 'Εξερεύνηση εργασιών', 'specialist_setup.step1.title': 'Καλωσήλθατε!', 'specialist_setup.step1.subtitle': 'Ας ρυθμίσουμε το προφίλ σας', 'specialist_setup.step1.desc': 'Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.', 'specialist_setup.step1.what_next': 'Τι θα κάνουμε:', 'specialist_setup.step1.item1': 'Συμπλήρωση βασικών πληροφοριών', 'specialist_setup.step1.item2': 'Δημιουργία κάρτας υπηρεσίας', 'specialist_setup.step1.item3': 'Προσθήκη δεξιοτήτων και κατηγοριών', 'specialist_setup.step1.item4': 'Επιλογή γεωγραφικής περιοχής', 'specialist_setup.step1.item5': 'Μεταφόρτωση φωτογραφιών χαρτοφυλακίου', 'specialist_setup.step2.title': 'Βασικό προφίλ', 'specialist_setup.step2.subtitle': 'Πείτε μας για σας', 'specialist_setup.step2.bio_label': 'Σχετικά με εμένα', 'specialist_setup.step2.bio_placeholder': 'Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...', 'specialist_setup.step2.phone_label': 'Τηλέφωνο', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Φωτογραφία προφίλ', 'specialist_setup.step2.photo_btn': 'Μεταφόρτωση φωτογραφίας', 'specialist_setup.step2.photo_uploading': 'Μεταφόρτωση...', 'specialist_setup.step2.photo_hint': 'Εμφανίζεται στο προφίλ σας', 'specialist_setup.step3.title': 'Κάρτα υπηρεσίας', 'specialist_setup.step3.subtitle': 'Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας', 'specialist_setup.step3.title_label': 'Τίτλος κάρτας', 'specialist_setup.step3.title_placeholder': 'Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...', 'specialist_setup.step3.desc_label': 'Περιγραφή', 'specialist_setup.step3.desc_placeholder': 'Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...', 'specialist_setup.step3.title_required': 'Απαιτείται τίτλος', 'specialist_setup.step4.title': 'Δεξιότητες & Κατηγορίες', 'specialist_setup.step4.subtitle': 'Προσθέστε δεξιότητες και επιλέξτε κατηγορίες', 'specialist_setup.step4.skills_label': 'Δεξιότητες', 'specialist_setup.step4.skills_placeholder': 'Π.χ. Εγκατάσταση σωληνώσεων...', 'specialist_setup.step4.skills_add': 'Προσθήκη', 'specialist_setup.step4.categories_label': 'Κατηγορίες', 'specialist_setup.step5.title': 'Γεωγραφική περιοχή', 'specialist_setup.step5.subtitle': 'Πού παρέχετε υπηρεσίες;', 'specialist_setup.step5.hint': 'Επιλέξτε πόλεις ή συγκεκριμένες περιοχές', 'specialist_setup.done.title': 'Το προφίλ σας είναι έτοιμο!', 'specialist_setup.done.subtitle': 'Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί', 'specialist_setup.done.desc': 'Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας.' }, en: { 'footer.slogan': 'Your task — our care! We solve any issue quickly and easily.', 'footer.links': 'Links', 'footer.socials': 'Socials', 'nav.home': 'Home', 'nav.tasks': 'Tasks', 'nav.post': '+ Post task', 'nav.dashboard': 'Dashboard', 'nav.chat': 'Messages', 'nav.notifications': 'Notifications', 'nav.profile': 'Profile', 'nav.admin': 'Admin Panel', 'nav.specialists': 'Specialists', 'nav.new_task': 'New task', 'nav.login': 'Login', 'nav.register': 'Register', 'nav.logout': 'Logout', 'hero.title': 'Find a specialist for any job', 'hero.subtitle': 'Post a task, receive offers and choose the best professional', 'hero.cta.post': 'Post a task', 'hero.cta.browse': 'Become a specialist', 'hero.search.placeholder': 'What do you need? e.g. electrician, cleaning...', 'stats.specialists': 'specialists', 'stats.tasks': 'tasks', 'stats.categories': 'categories', 'stats.free': 'free sign-up', 'section.categories': 'Create a task in any category', 'section.how': 'How it works', 'section.recent': 'Recent tasks', 'section.all': 'See all →', 'section.more': 'more', 'section.cities': 'Cities & Districts', 'section.community': 'A community project for everyone', 'community.subtitle': 'CanHelp is not just a marketplace — it\'s a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.', 'community.point1.title': 'Are you good at something?', 'community.point1.desc': 'Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.', 'community.point2.title': 'Need help with something?', 'community.point2.desc': 'Post a task in under a minute and receive offers from verified specialists in your city.', 'community.point3.title': 'Help the project grow', 'community.point3.desc': 'CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.', 'community.share': 'Share with friends', 'community.share.copied': 'Link copied!', // Referral section on home page 'section.referral': 'Referral Program', 'referral.home.subtitle': 'Share your link — every new user who signs up through it earns you a reward.', 'referral.home.step1.title': 'Sign up and get your link', 'referral.home.step1.desc': 'Create an account and find your unique referral link in your profile.', 'referral.home.step2.title': 'Share with friends', 'referral.home.step2.desc': 'Send the link to friends, acquaintances, or post it on social media.', 'referral.home.step3.title': 'Earn rewards', 'referral.home.step3.desc': 'Once your friend verifies their email, you automatically receive your reward.', 'referral.home.cta': 'Get your link', 'referral.home.badge': 'Referral Program', // FAQ section 'section.faq': 'Frequently Asked Questions', 'faq.q1': 'How does CanHelp work?', 'faq.a1': 'Post a task, receive offers from specialists, choose the best one and start working together. It\'s fast, simple and free for customers.', 'faq.q2': 'How much does it cost to use the platform?', 'faq.a2': 'Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.', 'faq.q3': 'How can I become a specialist?', 'faq.a3': 'Register, go to «Become a Specialist», fill in your profile with skills and categories, and start receiving tasks.', 'faq.q4': 'How do I choose the right specialist?', 'faq.a4': 'Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.', 'faq.q5': 'What if I am not satisfied?', 'faq.a5': 'You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.', 'faq.q6': 'Can I contact a specialist before accepting their offer?', 'faq.a6': 'Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.', 'faq.q7': 'How long does it take to receive offers?', 'faq.a7': 'Usually within a few hours. Specialists get notified about new tasks and can respond quickly.', 'faq.q8': 'Can I post a task in any city in Greece?', 'faq.a8': 'Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.', 'faq.q9': 'What types of tasks can I find on CanHelp?', 'faq.a9': 'Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.', 'faq.q10': 'Is there a mobile app?', 'faq.a10': 'Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.', 'how.step1.title': 'Post a task', 'how.step1.desc': 'Describe what you need and set your budget', 'how.step2.title': 'Receive offers', 'how.step2.desc': 'Specialists will send you offers with price and timeline', 'how.step3.title': 'Choose & start', 'how.step3.desc': 'Pick the best professional and start the collaboration', 'tasks.title': 'tasks', 'tasks.filters': 'Filters', 'tasks.search': 'Search', 'tasks.search.placeholder': 'Title or keyword...', 'tasks.search.btn': 'Search', 'tasks.publish': 'Post', 'tasks.category.all': 'All', 'tasks.category.all_in': 'All in', 'tasks.category.label': 'Category', 'tasks.location.label': 'City', 'tasks.location.placeholder': 'e.g. Athens', 'tasks.empty': 'No tasks found', 'tasks.empty.cta': 'Post the first one', 'task.status.open': 'Open', 'task.status.in_progress': 'In progress', 'task.status.completed': 'Completed', 'task.status.cancelled': 'Cancelled', 'task.status.draft': 'Draft', 'task.budget': 'Budget', 'task.location': 'Location', 'task.deadline': 'Start date', 'task.created_at': 'Created', 'task.customer': 'Customer', 'task.offer.btn': 'Submit offer', 'task.invite.banner_title': "You've been invited to this task", 'task.invite.banner_hint': 'The customer personally invited you', 'task.invite.accept': 'Send offer', 'task.invite.decline': 'Decline', 'offer.accept': 'Accept', 'offer.decline': 'Decline', 'task.complete': 'Complete task', 'task.complete.confirm': 'Mark this task as complete?', 'task.edit': 'Edit', 'task.status_label': 'Status', 'task.yours': 'Your task', 'task.offer.yours': 'Your offer', 'review.leave': 'Leave a review', 'review.rating': 'Rating', 'review.comment': 'Comment', 'review.comment.placeholder': 'Tell us about your experience...', 'review.submit': 'Submit review', 'review.submitting': 'Submitting...', 'review.done': 'Review submitted!', 'profile.reviews': 'Reviews', 'profile.no_reviews': 'No reviews yet', 'profile.rating': 'Rating', 'profile.skills.label': 'Skills', 'profile.member_since': 'Member since', 'task.offers': 'Offers', 'task.offers.none': 'No offers yet', 'create.title': 'Post a task', 'create.field.title': 'Title', 'create.field.description': 'Description', 'create.field.category': 'Category', 'create.field.category.select': 'Select...', 'create.field.location': 'Location', 'create.field.location.any': 'Anywhere', 'create.field.location.all': 'Entire city', 'create.field.budget': 'Budget (€)', 'create.field.deadline': 'Start date', 'create.field.budget_negotiable': 'Price is negotiable', 'create.field.time_slot': 'Time slot', 'create.field.time_slot.any': 'Anytime', 'create.field.time_slot.morning': 'Morning (08:00–13:00)', 'create.field.time_slot.afternoon': 'Afternoon (13:00–18:00)', 'create.field.time_slot.evening': 'Evening (18:00–22:00)', 'create.field.time_slot.weekend': 'Weekend', 'create.field.address': 'Address (optional)', 'create.field.address.district': 'District', 'create.field.address.street': 'Street', 'create.field.address.house': 'Number', 'create.field.confidential': 'Confidential note', 'create.field.confidential.placeholder': 'Details visible only to the assigned specialist...', 'create.field.confidential.hint': 'Not shown publicly', 'create.field.photos': 'Photos', 'create.field.photos.add': 'Add photo', 'create.field.photos.uploading': 'Uploading...', 'task.budget_negotiable': 'Price negotiable', 'task.time_slot': 'Time slot', 'task.confidential': 'Confidential note', 'create.field.title.placeholder': 'e.g. Clean 80sqm apartment', 'create.field.description.placeholder': 'Describe in detail what you need...', 'create.field.location.placeholder': 'e.g. Athens, Kolonaki', 'create.field.budget.placeholder': 'e.g. 100', 'create.submit': 'Post task', 'create.submitting': 'Posting...', 'login.title': 'Welcome back', 'login.subtitle': 'Sign in to CanHelp', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.submitting': 'Signing in...', 'login.error': 'Invalid email or password', 'login.unverified.title': 'Verify your email address', 'login.unverified.desc': 'We sent a verification link to your email. Check your inbox (or spam) and click the link.', 'login.unverified.resend': 'Resend verification email', 'login.unverified.sending': 'Sending...', 'login.unverified.sent': '✓ Sent — check your inbox', 'profile.email.verified': 'Email verified', 'profile.email.not_verified': 'Email not verified', 'login.no_account': "Don't have an account?", 'login.register_link': 'Register', 'login.forgot_password': 'Forgot password?', 'login.or_continue_with': 'or continue with', 'login.continue_google': 'Continue with Google', 'forgot.title': 'Forgot password', 'forgot.subtitle': 'Enter your email to receive a reset link', 'forgot.email': 'Email', 'forgot.submit': 'Send reset link', 'forgot.submitting': 'Sending...', 'forgot.sent.title': 'Check your inbox', 'forgot.sent.desc': 'If an account exists with that email, we\'ll send you a password reset link.', 'forgot.back_to_login': 'Back to sign in', 'forgot.error': 'Could not send reset link. Check the email address and try again.', 'forgot.error.not_found': 'No account found with this email address.', 'forgot.error.send_failed': 'Failed to send email. Please try again later.', 'reset.title': 'New password', 'reset.subtitle': 'Enter your new password', 'reset.password': 'New password', 'reset.confirm': 'Confirm password', 'reset.submit': 'Change password', 'reset.submitting': 'Saving...', 'reset.success': 'Password changed successfully. Redirecting to sign in...', 'reset.back_to_login': 'Back to sign in', 'reset.error.mismatch': 'Passwords do not match', 'reset.error.invalid': 'Invalid or expired link. Please request a new one.', 'register.title': 'Register', 'register.subtitle': 'Create a CanHelp account', 'register.first_name': 'First name', 'register.last_name': 'Last name', 'register.email': 'Email', 'register.password': 'Password (min 8 characters)', 'register.role': 'Role', 'register.role.customer': 'User', 'register.role.customer.desc': 'I post tasks', 'register.role.specialist': 'Specialist', 'register.role.specialist.desc': 'I take on tasks', 'register.submit': 'Create account', 'register.submitting': 'Registering...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Sign in', 'register.continue_google': 'Continue with Google', 'register.check_email.title': 'Check your email', 'register.check_email.desc': 'We sent a verification link to your email address. Check your inbox (or spam) and click the link.', 'register.check_email.login': 'Back to sign in', 'dashboard.title': 'Dashboard', 'dashboard.new_task': '+ New task', 'dashboard.my_tasks': 'My tasks', 'dashboard.my_offers': 'My offers', 'dashboard.invitations': 'Job invitations', 'dashboard.offers_count': 'offers', 'dashboard.declined_count': 'declined', 'dashboard.completed_tasks': 'Completed tasks', 'dashboard.completed_offers': 'Completed offers', 'dashboard.review_pending': 'Review not yet submitted', 'tasks.new.top_specialists': 'Top specialists', 'tasks.new.select_category': 'Select a category to see matching specialists', 'tasks.new.invite': 'Offer work', 'tasks.new.invited': 'Selected ✓', 'reviews.count': 'reviews', 'filter.location': 'Location', 'filter.language': 'Languages', 'filter.language.any': 'Any language', 'filter.category.all': 'All categories', 'user.categories': 'Categories', 'user.work_area': 'Work area', 'dashboard.tasks.empty': "You haven't posted any tasks", 'dashboard.tasks.empty.cta': 'Post your first one', 'dashboard.tasks.add_new': 'Add a new task', 'dashboard.offers.empty': "You haven't submitted any offers", 'dashboard.offers.empty.cta': 'Find tasks', 'dashboard.customer.specialists_title': 'Looking for a specialist?', 'dashboard.customer.specialists_hint': 'Browse specialist profiles, read reviews and invite them to your tasks', 'dashboard.customer.specialists_cta': 'Find a specialist', 'dashboard.customer.how_title': 'How it works', 'dashboard.customer.step1': 'Create a task with a description and budget', 'dashboard.customer.step2': 'Specialists will send offers with price and timeline', 'dashboard.customer.step3': 'Choose the right one and start working', 'notif.title': 'Notifications', 'notif.mark_all': 'Mark all as read', 'notif.empty': 'No notifications', 'notif.type.new_offer': 'New offer', 'notif.type.offer_accepted': 'Your offer was accepted', 'notif.type.offer_declined': 'Your offer was declined', 'notif.type.task_completed': 'Task completed', 'notif.type.task_cancelled': 'Task cancelled', 'notif.type.new_message': 'New message', 'notif.type.new_review': 'New review', 'notif.type.task_invite': 'Job invitation', 'notif.body.new_offer': 'New offer for «{title}»', 'notif.body.offer_accepted': 'Your offer for «{title}» was accepted', 'notif.body.offer_declined': 'Your offer for «{title}» was declined', 'notif.body.task_invite': 'You\'ve been invited for «{title}»', 'notif.body.new_review': 'You received a {rating}★ review', 'offer.status.pending': 'Pending', 'offer.status.accepted': 'Accepted', 'offer.status.declined': 'Declined', 'offer.status.withdrawn': 'Withdrawn', 'offer.status.other_accepted': 'Another specialist was chosen', 'common.loading': 'Loading...', 'common.error': 'Error', 'common.save': 'Save', 'common.saving': 'Saving...', 'common.cancel': 'Cancel', 'common.add': 'Add', 'common.close': 'Close', 'common.edit': 'Edit', 'common.delete': 'Delete', 'common.from': 'by', 'common.currency': '€', 'common.greece': 'Greece', // Chat 'chat.connected': 'Connected', 'chat.disconnected': 'Disconnected', 'chat.no_rooms': 'No conversations yet', 'chat.task_fallback': 'Task', 'chat.select': 'Select a conversation', 'chat.no_messages': 'No messages yet', 'chat.placeholder': 'Write a message... (Enter to send)', 'chat.conversation_fallback': 'Conversation', 'chat.direct_chat': 'Direct chat', 'chat.linked_task': 'Linked task', 'chat.write_btn': 'Message', 'chat.just_now': 'just now', 'chat.min_ago': 'm', 'chat.write_specialist': 'Write to specialist', 'chat.write_customer': 'Write to customer', 'chat.notif_settings': 'Notification settings', 'chat.notif_messages': 'Notifications for new messages', 'chat.toast_title': 'New message', 'chat.toast_open': 'Open chat', // Offer form 'offer.price': 'Price', 'offer.price.placeholder': 'e.g. 80', 'offer.customer_budget': 'Client budget', 'offer.message': 'Message', 'offer.optional': 'optional', 'offer.message.placeholder': 'Introduce yourself, your experience and why you are the best choice...', 'offer.submitting': 'Sending...', // Profile 'profile.photo': 'Profile photo', 'profile.photo.change': 'Change photo', 'profile.photo.hint': 'JPEG, PNG, WebP · up to 5MB', 'profile.basic_info': 'Basic info', 'profile.phone': 'Phone', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Short bio', 'profile.bio.placeholder': 'Tell us a bit about yourself...', 'profile.language': 'Language', 'profile.language.hint': 'App interface and email notification language', 'profile.languages': 'Languages spoken', 'profile.languages.hint': 'Select all languages you speak', 'profile.skills': 'Skills', 'profile.skills.subtitle': 'Add the services you offer', 'profile.skills.placeholder': 'e.g. Cleaning, IT, Tutoring...', 'profile.role': 'Account role', 'profile.role.specialist': '🔧 Specialist', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 User', 'profile.role.change': 'To change your role please contact support.', 'profile.become_specialist': 'Become a Specialist', 'profile.become_specialist.desc': 'Upgrade to Specialist to take on tasks and build your profile.', 'become_specialist.hero.title': 'Earn money doing what you do best', 'become_specialist.hero.subtitle': 'Create a specialist profile and receive orders from clients across Greece', 'become_specialist.how.title': 'How it works', 'become_specialist.step1.title': 'Create a specialist portfolio', 'become_specialist.step1.desc': 'Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks', 'become_specialist.step2.title': 'Find tasks', 'become_specialist.step2.desc': 'Discover tasks in your categories in the "Find Orders" section', 'become_specialist.step3.title': 'Send an offer & earn', 'become_specialist.step3.desc': 'Submit offers with price and timeline, chat with clients and complete tasks', 'become_specialist.benefits.title': 'Specialist profile advantages', 'become_specialist.benefit1': 'Task search filtered by your categories and location', 'become_specialist.benefit2': 'Public profile with client reviews', 'become_specialist.benefit3': 'Availability schedule visible to clients', 'become_specialist.benefit4': 'Saved to favourites by clients', 'become_specialist.cta': 'Learn more', 'become_specialist.free_badge': 'Free registration', 'profile.tab.notifications': 'Notifications', 'profile.tab.reviews': 'Reviews', 'profile.tab.referral': 'Referrals', 'profile.tab.auto_response': 'Auto-response', 'profile.tab.site': 'Site', 'profile.site.title': 'Personal page', 'profile.site.url_label': 'Personal site', 'profile.site.copy': 'Copy', 'profile.site.copied': 'Copied', 'profile.site.visible_title': "What's on your page", 'profile.site.visible.name': 'Name and photo', 'profile.site.visible.bio': 'Bio', 'profile.site.visible.rating': 'Rating and reviews', 'profile.site.visible.portfolio': 'Portfolio / Cards', 'profile.site.visible.contacts': 'Contact info', 'profile.site.visible.full_last_name': 'Full last name', 'profile.site.visible.services': 'Service cards', 'profile.site.visible.reviews': 'Reviews section', 'profile.site.visible.status': '"Ready to help" status', 'profile.site.theme': 'Appearance theme', 'profile.site.theme.dark': 'Dark', 'profile.site.theme.light': 'Light', 'profile.site.slug_taken': 'This address is already taken', 'profile.site.stats.title': 'Site analytics', 'profile.site.stats.days': 'last 30 days', 'profile.site.stats.views': 'Views', 'profile.site.stats.unique': 'Unique visitors', 'profile.site.stats.messages': 'Messages', 'profile.site.stats.total_views': 'Total views', 'profile.site.stats.total_unique': 'Unique visitors', 'profile.site.stats.total_messages': 'Messages', 'profile.site.stats.empty': 'No data yet', 'profile.site.stats.loading': 'Loading analytics...', 'profile.site.stats.no_slug': 'Set your site URL to see analytics', 'profile.site.edit_bio_hint': 'Bio and photo are edited in the "Basic info" tab.', 'status.title': 'Status', 'status.can_help_now_hint': 'Your card is shown higher in search', 'status.need_help_hint': 'Specialists can offer you help', 'profile.referral.title': 'Referral program', 'profile.referral.desc': 'Share your link and earn rewards for every new user you invite.', 'profile.referral.link_label': 'Your referral link', 'profile.referral.copy': 'Copy', 'profile.referral.copied': 'Copied!', 'profile.referral.invited_count': 'successful referrals', 'profile.referral.no_code': 'Referral code is not available.', 'notifications.title': 'Notification settings', 'notifications.email.new_tasks': 'Email for new tasks', 'notifications.email.new_tasks.desc': 'Receive an email when a new task is posted in your categories', 'notifications.messages.desc': 'Receive a notification when a new message arrives', 'notifications.saved': 'Settings saved', 'notifications.plan_required': 'Not available in your plan', 'profile.tab.info': 'Basic info', 'profile.tab.finance': 'Finance', 'profile.tab.skills': 'Skills', 'profile.tab.categories': 'Categories', 'profile.tab.geography': 'Geography', 'profile.specialist.categories': 'Work categories', 'profile.specialist.categories.desc': 'Select the categories you work in', 'profile.specialist.geography': 'Coverage areas', 'profile.specialist.geography.desc': 'Select the cities / districts where you are active', 'profile.saving': 'Saving...', 'profile.upload.error': 'Error uploading photo', 'profile.saved': 'Saved', 'profile.tab.cards': 'Portfolio', 'profile.cards.count': 'Portfolio', 'profile.cards.add': 'Add portfolio', 'profile.cards.new_title': 'New portfolio title', 'profile.cards.placeholder': 'e.g. Plumbing', 'profile.cards.create': 'Create', 'profile.cards.cancel': 'Cancel', 'profile.cards.empty': 'No portfolio yet', 'profile.cards.create_first': 'Create your first portfolio', 'profile.cards.delete_confirm': 'Delete portfolio?', 'profile.card.tab.main': 'General', 'profile.card.tab.skills': 'Skills', 'profile.card.tab.categories': 'Categories', 'profile.card.tab.geography': 'Geography', 'profile.card.tab.portfolio': 'Portfolio', 'profile.card.active': 'Active', 'profile.card.save': 'Save', 'profile.card.saved': 'Saved', 'profile.card.delete': 'Delete', 'profile.card.skill.add': 'Add skill', 'profile.card.photo.add': 'Add photo', 'profile.card.photo.uploading': 'Uploading...', 'profile.card.photo.empty': 'No photos yet', 'profile.card.item.title': 'Title', 'profile.card.item.desc': 'Description', 'profile.card.item.save': 'Save', 'profile.card.item.cancel': 'Cancel', 'profile.card.item.edit': 'Edit', 'profile.upgrade.cards_limit': 'Portfolio limit reached', 'profile.upgrade.plan': 'Current plan:', 'profile.upgrade.contact': 'Contact the administrator to change your plan', 'profile.upgrade.ok': 'Got it', 'profile.plan.title': 'Subscription plan', 'profile.balance': 'Balance', 'profile.balance.topup': 'Top Up Balance', 'profile.balance.topup.title': 'Top Up Balance', 'profile.balance.topup.amount': 'Amount (EUR)', 'profile.balance.topup.hint': 'Choose a preset or enter a custom amount', 'profile.balance.topup.submit': 'Proceed to Payment', 'profile.balance.topup.loading': 'Redirecting...', 'profile.balance.topup.error': 'Payment initiation failed. Please try again.', 'payment.success.title': 'Payment Successful!', 'payment.success.desc': 'Your balance has been updated.', 'payment.cancelled.title': 'Payment Cancelled', 'payment.cancelled.desc': 'Payment was cancelled. No charges were made.', 'payment.pending.title': 'Processing...', 'payment.pending.desc': 'Your payment is being processed.', 'payment.back_to_profile': 'Back to Profile', 'profile.plan.basic': 'Basic (free)', 'profile.plan.contact_upgrade': 'Contact admin to upgrade your plan', 'profile.plan.cards_up_to': 'Portfolio: up to', 'profile.plan.cards_unlimited': 'Portfolio: unlimited', 'profile.plan.tasks_up_to': 'Tasks: up to', 'profile.plan.offers_up_to': 'Offers: up to', 'profile.plan.valid_until': 'Valid until', 'profile.plan.no_expiry': 'No expiry', // Create task 'create.error': 'Error posting task', // Tasks list extras 'tasks.category.general': 'General', 'tasks.budget.range': 'Range:', 'tasks.budget.from': 'from', 'tasks.budget.to': 'to', 'tasks.filter.reset': 'Reset filters', 'tasks.load_more': 'Load more', 'tasks.showing': 'Results:', 'tasks.field.budget': 'Budget, €', // Admin 'admin.title': 'Admin Panel', 'admin.tab.stats': 'Statistics', 'admin.tab.users': 'Users', 'admin.tab.tasks': 'Tasks', 'admin.tab.reports': 'Reports', 'admin.stats.users': 'Users', 'admin.stats.tasks': 'Tasks', 'admin.stats.offers': 'Offers', 'admin.stats.reviews': 'Reviews', 'admin.tasks.by_status': 'Tasks by status', 'admin.col.user': 'User', 'admin.col.email': 'Email', 'admin.col.role': 'Role', 'admin.col.registered': 'Registered', 'admin.col.status': 'Status', 'admin.col.title': 'Title', 'admin.col.budget': 'Budget', 'admin.col.created': 'Created', 'admin.users.active': 'Active', 'admin.users.inactive': 'Inactive', 'admin.users.deactivate': 'Deactivate', 'admin.users.activate': 'Activate', 'admin.tasks.cancel': 'Cancel', 'admin.reports.none': 'No reports', 'admin.reports.reviewed': 'Reviewed', 'admin.reports.dismiss': 'Dismiss', 'admin.pagination.total': 'Total', 'admin.users.role.change': 'Change role', 'admin.users.search.placeholder': 'Search name or email...', 'admin.tasks.delete': 'Delete', 'admin.tasks.delete.confirm': 'Permanently delete this task?', 'admin.tasks.search.placeholder': 'Search title...', 'admin.col.customer': 'Customer', 'admin.col.reporter': 'Reporter', 'admin.col.target': 'Target', 'admin.filter.all_roles': 'All roles', 'admin.filter.all_statuses': 'All statuses', 'admin.reports.target.task': 'Task', 'admin.reports.target.user': 'User', 'admin.tab.categories': 'Categories', 'admin.tab.locations': 'Cities & Districts', 'admin.tab.logs': 'Logs', 'admin.tab.plans': 'Plans', 'admin.tab.settings': 'Settings', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Activity', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Notifications', 'admin.notif_logs.type': 'Type', 'admin.notif_logs.title': 'Title', 'admin.notif_logs.read': 'Read', 'admin.notif_logs.empty': 'No notification logs', 'admin.stats.notif_chart_title': 'Notifications per day', 'admin.stats.notif_label': 'Notifications', 'admin.stats.mail_chart_title': 'Emails per day', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'All', 'admin.stats.specialists': 'Specialists', 'admin.col.plan': 'Plan', 'admin.back_home': 'Home', 'admin.plans.title': 'Subscription plans', 'admin.plans.add': '+ New plan', 'admin.plans.empty': 'No plans created', 'admin.plans.form.new': 'New plan', 'admin.plans.form.edit': 'Edit plan', 'admin.plans.form.name': 'Name', 'admin.plans.form.price': 'Price (EUR)', 'admin.plans.form.old_price': 'Old price (EUR, optional)', 'admin.plans.form.max_offers': 'Max offers (empty = no limit)', 'admin.plans.form.max_cards': 'Max portfolio (empty = no limit)', 'admin.plans.form.duration_days': 'Duration (days, empty = no expiry)', 'admin.plans.form.description': 'Description', 'admin.plans.form.features': 'Features (one per line)', 'admin.plans.form.notify': 'Notify about new tasks', 'admin.plans.form.default': 'Default', 'admin.plans.form.active': 'Active', 'admin.plans.form.order': 'Order', 'admin.plans.form.role': 'Role', 'admin.plans.form.tier': 'Tier', 'admin.plans.form.role.customer': 'Customer', 'admin.plans.form.role.specialist': 'Specialist', 'admin.plans.form.tier.free': 'Free', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Limits (empty = unlimited)', 'admin.plans.form.max_messages_day': 'Max Messages/Day', 'admin.plans.form.max_orders_day': 'Max Orders/Day', 'admin.plans.form.max_skills': 'Max Skills', 'admin.plans.form.max_profiles': 'Max Profiles', 'admin.plans.form.max_portfolio': 'Max Portfolio Items', 'admin.plans.form.section.boost': 'Multipliers & Boost', 'admin.plans.form.search_boost': 'Search Boost', 'admin.plans.form.offers_multiplier': 'Offers Multiplier', 'admin.plans.form.section.contact': 'Contact Permissions', 'admin.plans.form.can_contact_free': 'Contact Free Plan users', 'admin.plans.form.can_contact_pro': 'Contact Pro Plan users', 'admin.plans.form.can_contact_all': 'Contact All users', 'admin.plans.form.can_show_contact': 'Show Contact Info', 'admin.plans.form.can_view_phone': 'View Phone', 'admin.plans.form.section.features': 'Feature Flags', 'admin.plans.form.upload_video': 'Upload Video', 'admin.plans.form.favorites': 'Favorites', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Verified Badge', 'admin.plans.form.highlighted_reviews': 'Highlighted Reviews', 'admin.plans.form.personal_site': 'Personal Site', 'admin.plans.form.can_help_now': 'Can Help Now Status', 'admin.plans.form.need_help': 'Need Help Status', 'admin.plans.form.auto_response': 'Auto Response', 'admin.plans.form.auto_match': 'Auto Match', 'admin.plans.form.instant_dispatch_free': 'Instant Dispatch (Free)', 'admin.plans.form.instant_dispatch_pro': 'Instant Dispatch (Pro)', 'admin.plans.badge.default': 'Default', 'admin.plans.badge.inactive': 'Inactive', 'admin.plans.make_default': 'Set as default', 'admin.plans.tasks': 'Tasks', 'admin.plans.offers': 'Offers', 'admin.plans.cards': 'Portfolio', 'admin.plans.notify_tasks': 'Task notifications', 'admin.plans.delete.confirm': 'Delete plan', 'admin.activity.title': 'Activity log', 'admin.activity.event': 'Event', 'admin.activity.all_events': 'All events', 'admin.activity.from': 'From', 'admin.activity.to': 'To', 'admin.activity.reset': 'Reset', 'admin.activity.total': 'Total', 'admin.activity.empty': 'No records', 'admin.mail.event': 'Email event', 'admin.mail.all_events': 'All email events', 'admin.mail.from': 'From', 'admin.mail.to': 'To', 'admin.mail.reset': 'Reset', 'admin.mail.total': 'Total', 'admin.mail.empty': 'No email logs', 'admin.mail.recipient': 'Recipient', 'admin.mail.provider': 'Provider', 'admin.mail.details': 'Details', 'admin.mail.status': 'Status', 'admin.mail.success': 'Success', 'admin.mail.failed': 'Failed', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'No records', 'admin.logs.date': 'Date', 'admin.logs.provider': 'Provider', 'admin.logs.model': 'Model', 'admin.logs.action': 'Action', 'admin.logs.langs': 'Languages', 'admin.logs.in': 'In', 'admin.logs.out': 'Out', 'admin.logs.total': 'Total', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Status', 'admin.stats.activity_30d': 'Activity over 30 days', 'admin.stats.tasks_label': 'Tasks', 'admin.stats.users_label': 'Users', 'admin.stats.specialists_label': 'Specialists', 'admin.stats.tokens_title': 'Token usage (by month)', 'admin.stats.tokens_out': 'Output', 'admin.stats.tokens_in': 'Input', 'admin.stats.tokens_out_label': 'Output tokens', 'admin.stats.tokens_in_label': 'Input tokens', 'admin.stats.cost_label': 'Cost (USD)', 'admin.stats.tasks_by_status': 'Tasks by status', 'admin.task_status.open': 'Open', 'admin.task_status.in_progress': 'In progress', 'admin.task_status.completed': 'Completed', 'admin.task_status.cancelled': 'Cancelled', 'admin.task_status.draft': 'Drafts', 'admin.settings.tab.general': 'General', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Notifications', 'admin.settings.tab.payment': 'Payment', 'admin.settings.tab.referral': 'Referrals', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Socials', 'admin.settings.socials.title': 'Social Network Links', 'admin.settings.socials.hint': 'Filled links are displayed in the site footer', 'admin.settings.seo.maintenance_label': 'Maintenance Mode', 'admin.settings.seo.maintenance_hint': 'Show a maintenance page to all visitors', 'admin.settings.seo.indexing_label': 'Search Engine Indexing', 'admin.settings.seo.indexing_hint': 'Allow search engines to index the site', 'admin.settings.seo.head_scripts_label': ' Scripts (JS)', 'admin.settings.seo.head_scripts_hint': 'Runs on every page (Google Tag Manager, analytics, etc.)', 'admin.settings.seo.site_title_label': 'Site Title', 'admin.settings.seo.site_description_label': 'Site Description (meta description)', 'admin.settings.referral.title': 'Referral program', 'admin.settings.referral.hint': 'Reward users who bring new registrations.', 'admin.settings.referral.enabled_label': 'Enabled', 'admin.settings.referral.enabled_hint': 'Enable / disable reward application', 'admin.settings.referral.customer_section': 'For customers', 'admin.settings.referral.specialist_section': 'For specialists', 'admin.settings.referral.plan_label': 'Reward plan', 'admin.settings.referral.no_plan': '— no plan —', 'admin.settings.referral.plan_hint': 'This plan will be assigned to the referrer. If their current plan is higher, only days will be added.', 'admin.settings.referral.days_label': 'Reward days', 'admin.settings.referral.days_hint': 'Number of days added to the plan expiry.', 'admin.settings.general.title': 'General settings', 'admin.settings.general.site_name': 'Site name', 'admin.settings.general.site_url': 'Site URL', 'admin.settings.general.contact_email': 'Contact email', 'admin.settings.general.support_phone': 'Support phone', 'admin.settings.smtp.title': 'SMTP settings', 'admin.settings.smtp.hint': 'Used to send email notifications.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Port', 'admin.settings.smtp.encryption': 'Encryption', 'admin.settings.smtp.enc.none': 'None', 'admin.settings.smtp.enc.tls': 'STARTTLS (port 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (port 465)', 'admin.settings.smtp.username': 'Username', 'admin.settings.smtp.password': 'Password / App Password', 'admin.settings.smtp.from_name': 'Sender name', 'admin.settings.smtp.from_email': 'Sender email', 'admin.settings.smtp.test': 'Send test email', 'admin.settings.smtp.sending': 'Sending...', 'admin.settings.payment.hint': 'ePay Piraeus Bank credentials.', 'admin.settings.env.test': 'Test (sandbox)', 'admin.settings.env.prod': 'Production', 'admin.settings.env.label': 'Environment', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Active', 'admin.settings.saving': 'Saving...', 'admin.settings.saved': 'Saved', 'admin.notif.vars_hint': 'Available variables in templates', 'admin.notif.tmpl.not_set': 'Template not configured', 'admin.notif.tmpl.subject_label': 'Email subject', 'admin.notif.tmpl.body_label': 'Email body (HTML)', 'admin.notif.tmpl.save': 'Save', 'admin.notif.tmpl.close': 'Close', 'admin.notif.tmpl.translate': 'Auto-translate to other languages', 'admin.notif.tmpl.translating': 'Translating...', 'admin.notif.tmpl.saving': 'Saving...', 'admin.notif.email_verification': 'Email verification', 'admin.notif.registration_success': 'Successful registration', 'admin.notif.password_reset': 'Password reset', 'admin.notif.new_offer': 'New offer', 'admin.notif.new_task': 'New task', 'admin.notif.offer_accepted': 'Offer accepted', 'admin.notif.new_message': 'New message', 'admin.notif.offer_declined': 'Offer declined', 'admin.notif.offer_other_accepted': 'Another specialist chosen', 'admin.notif.task_updated': 'Task updated', 'admin.notif.deadline_reminder': 'Deadline reminder', 'admin.notif.task_archived': 'Task unpublished automatically', 'admin.notif.referral_reward': 'Referral reward', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Plan activated', 'admin.email_template.plan_upgraded': 'Plan upgraded', 'admin.email_template.plan_downgrade_scheduled': 'Downgrade scheduled', 'admin.email_template.plan_downgrade_applied': 'Downgrade applied', 'admin.email_template.plan_renewal_reminder': 'Renewal reminder', 'admin.email_template.plan_insufficient_funds': 'Insufficient funds warning', // Pricing confirm modal 'pricing.confirm.title': 'Confirm plan selection', 'pricing.confirm.plan': 'Plan', 'pricing.confirm.prorated': 'Prorated credit', 'pricing.confirm.effective_price': 'Amount due', 'pricing.confirm.your_balance': 'Your balance', 'pricing.confirm.downgrade_info': 'The switch to the new plan will happen automatically after the current period ends.', 'pricing.confirm.insufficient': 'Insufficient balance.', 'pricing.confirm.top_up': 'Top up', 'pricing.confirm.schedule_downgrade': 'Schedule downgrade', 'pricing.confirm.pay': 'Pay', 'admin.user_edit.title': 'Edit user', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email verified', 'admin.user_edit.email_not_verified': 'Email not verified', 'admin.user_edit.verify_email_btn': 'Verify manually', 'admin.user_edit.verify_email_done': 'Email verified!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Registered', 'admin.user_edit.last_seen': 'Last seen', 'admin.user_edit.lang': 'Language', 'admin.user_edit.first_name': 'First name', 'admin.user_edit.last_name': 'Last name', 'admin.user_edit.phone': 'Phone', 'admin.user_edit.bio': 'Bio', 'admin.user_edit.role': 'Role', 'admin.user_edit.plan': 'Plan', 'admin.user_edit.no_plan': '— No plan —', 'admin.user_edit.active': 'Active account', 'admin.user_edit.balance': 'Balance (EUR)', 'admin.user_edit.skills': 'Skills', 'admin.user_edit.tab.profile': 'Profile', 'admin.user_edit.tab.account': 'Account', 'admin.user_edit.tab.balance': 'Balance', 'admin.user_edit.tab.settings': 'Settings', 'admin.user_edit.tab.specialist': 'Portfolio', 'admin.user_edit.tab.site': 'Website', 'admin.user_edit.plan_expires': 'Plan expires', 'admin.user_edit.interface_lang': 'Interface language', 'admin.user_edit.comm_languages': 'Communication languages', 'admin.user_edit.personal_site_slug': 'Personal page', 'admin.user_edit.show_contact_info': 'Show contact info', 'admin.user_edit.show_contact_info.hint': 'Visible to customers', 'admin.user_edit.notify_new_tasks': 'Notify about new tasks', 'admin.user_edit.notify_new_tasks.hint': 'Push and email notifications', 'admin.user_edit.notif_messages': 'Message notifications', 'admin.user_edit.notif_messages.hint': 'New messages in chat', 'admin.user_edit.site_settings': 'Personal page settings', 'admin.user_edit.categories': 'Service categories', 'admin.user_edit.locations': 'Service areas', 'admin.user_edit.skill_placeholder': 'New skill...', 'admin.user_edit.add_category': '— Select category —', 'admin.user_edit.add_location': '— Select location —', 'admin.user_edit.specialist_cards': 'Portfolio', 'admin.user_edit.no_cards': 'No portfolio found', 'admin.user_edit.card_title': 'Portfolio title', 'admin.user_edit.card_description': 'Description', 'admin.balance.topup.btn': 'Top up', 'admin.balance.withdraw.btn': 'Withdraw', 'admin.balance.modal_hint': 'Changes take effect immediately and are recorded in history', 'admin.balance.topup.title': 'Top up balance', 'admin.balance.topup.amount': 'Amount', 'admin.balance.topup.description': 'Comment', 'admin.balance.topup.description.placeholder': 'For example: bonus or manual top-up', 'admin.balance.topup.submit': 'Top up balance', 'admin.balance.withdraw.title': 'Withdraw balance', 'admin.balance.withdraw.amount': 'Amount', 'admin.balance.withdraw.description': 'Comment', 'admin.balance.withdraw.description.placeholder': 'For example: refund or manual debit', 'admin.balance.withdraw.submit': 'Withdraw from balance', 'admin.user_edit.role.customer': 'Customer', 'admin.user_edit.role.specialist': 'Specialist', 'admin.user_edit.role.admin': 'Administrator', 'common.refresh': 'Refresh', 'common.back_home': 'Home', 'admin.loc.hint': 'Manage cities and districts', 'admin.loc.add_city': 'New city', 'admin.loc.add_district': 'Add district', 'admin.loc.new': 'New location', 'admin.loc.edit': 'Edit location', 'admin.loc.district': 'district', 'admin.loc.empty': 'No locations', 'admin.loc.delete.confirm': 'Delete location? All districts will also be deleted.', 'admin.cat.add_root': 'New category', 'admin.cat.add_sub': 'Subcategory', 'admin.cat.edit': 'Edit', 'admin.cat.delete': 'Delete', 'admin.cat.delete.confirm': 'Delete category? All subcategories will also be deleted.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Icon', 'admin.cat.name_el': 'Greek', 'admin.cat.name_en': 'English', 'admin.cat.name_ru': 'Russian', 'admin.cat.order': 'Order', 'admin.cat.active': 'Active', 'admin.cat.parent': 'Parent category', 'admin.cat.no_parent': 'Top level', 'admin.cat.save': 'Save', 'admin.cat.cancel': 'Cancel', 'admin.cat.empty': 'No categories', 'admin.cat.hint': 'Manage categories with multi-level hierarchy', 'admin.cat.new': 'New category', 'admin.cat.subcategory': 'subcategory', 'admin.cat.add_child': 'Add subcategory', 'admin.cat.inactive': 'Inactive', 'admin.event.user_login': 'Login', 'admin.event.user_register': 'Registration', 'admin.event.admin_user_deactivate': 'User blocked', 'admin.event.admin_user_activate': 'User activated', 'admin.event.admin_user_role_changed': 'Role changed', 'admin.event.admin_task_cancelled': 'Task cancelled', 'admin.event.admin_task_deleted': 'Task deleted', 'admin.event.admin_report_reviewed': 'Report reviewed', 'admin.event.admin_report_dismissed': 'Report dismissed', 'admin.event.task_created': 'Task created', // User status 'user.online': 'Online', 'user.seen_minutes': 'was here {n} min ago', 'user.seen_hours': 'was here {n} hr ago', 'user.seen_yesterday': 'was here yesterday', 'user.seen_days': 'was here {n} days ago', // Specialists 'specialists.title': 'Specialists', 'specialists.search': 'Search specialist...', 'specialists.search.btn': 'Search', 'specialists.empty': 'No specialists found', 'specialists.no_bio': 'No description', 'specialists.view': 'View profile', 'specialists.reviews': 'reviews', 'specialist.favorite': 'Add to favorites', 'specialist.unfavorite': 'Remove from favorites', 'specialist.site_link': 'Personal site', 'favorites.specialists.title': 'Favourite specialists', 'favorites.specialists.empty': 'No favourite specialists yet', 'nav.favorites': 'Favourites', 'nav.schedule': 'Schedule', 'nav.find_tasks': 'Find Orders', 'schedule.title': 'My Schedule', 'schedule.subtitle': 'Mark the days when you are free or busy — clients will see your availability', 'schedule.available': 'Available', 'schedule.busy': 'Busy', 'schedule.unset': 'Not set', 'schedule.click_hint': '← click to cycle status', 'schedule.range_mode': 'Select range', 'schedule.range_from': 'From {date} — select end date', 'schedule.click_to_set': 'Click to set', 'schedule.free': 'free', 'schedule.busy_count': 'busy', 'schedule.free_days': 'free days', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Connect Google Calendar', 'schedule.disconnectGoogle': 'Disconnect', 'schedule.connectedAs': 'Connected as', 'schedule.importFromGoogle': 'Sync from Google', 'schedule.gcalConnected': '\u2713 Google Calendar connected', 'schedule.gcalError': 'Google Calendar connection error', 'schedule.gcalImportDone': 'Imported {n} days from Google Calendar', 'schedule.gcalAutoSyncNote': 'Availability changes are automatically synced to Google Calendar', 'schedule.gcalConnectDesc': 'Connect Google Calendar to automatically sync your availability', 'schedule.gcalDisconnectConfirm': 'Disconnect Google Calendar?', 'find_tasks.title': 'Find Orders', 'find_tasks.for_me': 'For me', 'find_tasks.all': 'All orders', 'find_tasks.by_category': 'By category', 'find_tasks.list': 'List', 'find_tasks.already_offered': 'Offer sent', 'find_tasks.offer_now': 'Make an offer', 'find_tasks.empty_for_me': 'No tasks found in your categories', 'find_tasks.banner_hint': 'Find tasks matching your portfolio categories', 'find_tasks.no_cards': 'Create a specialist portfolio to see tasks matched to you', 'find_tasks.add_card': 'Create portfolio', 'find_tasks.search': 'Search tasks...', 'find_tasks.tasks_count': 'tasks', 'footer.tagline': 'The task platform for Greece', 'footer.rights': 'All rights reserved.', // App download section 'app.download_title': 'Download the CanHelp mobile app', 'app.download_desc': 'All of CanHelp — always at your fingertips. Available for Android and iOS.', // Nav 'nav.pricing': 'Pricing', // Pricing page 'pricing.title': 'Pricing', 'pricing.subtitle': 'Choose the right plan for you', 'pricing.role.customer': 'Customer', 'pricing.role.specialist': 'Specialist', 'pricing.free': 'Free', 'pricing.per_month': 'mo', 'pricing.duration': 'Duration', 'pricing.days': 'days', 'pricing.current_plan': 'Your plan', 'pricing.popular': 'Popular', 'pricing.choose': 'Choose', 'pricing.your_plan': 'Active plan', 'pricing.free_default': 'Default', 'pricing.compare': 'Compare features', 'pricing.feature': 'Feature', 'pricing.faq_note': 'Payment is deducted from your CanHelp balance. Top up available in Payments.', 'pricing.feat.messages': 'Messages / day', 'pricing.feat.orders': 'Orders / day', 'pricing.feat.contact_all': 'Contact everyone', 'pricing.feat.view_phone': 'View phone number', 'pricing.feat.show_contact': 'Show contact info', 'pricing.feat.favorites': 'Favorites', 'pricing.feat.verified_badge': 'Verified badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Personal site', 'pricing.feat.auto_response': 'Auto-response', 'pricing.feat.auto_match': 'Auto-match', 'pricing.feat.highlighted_reviews': 'Highlighted reviews', 'pricing.feat.portfolio': 'Portfolio items', 'pricing.feat.cards': 'Specialist cards', 'pricing.feat.notify_tasks': 'New task notifications', 'pricing.feat.video': 'Video in portfolio', // Upgrade prompt 'upgrade.available_in': 'Available in', 'upgrade.cta': 'Upgrade', // Dashboard plan block 'dashboard.plan.title': 'My Plan', 'dashboard.plan.expires': 'Expires in {n} days', 'dashboard.plan.upgrade': 'Upgrade plan', 'dashboard.plan.no_plan': 'Free plan', 'dashboard.plan.messages': 'Messages today', 'dashboard.plan.orders': 'Orders today', 'dashboard.plan.limits': 'Daily limits', 'dashboard.plan.features': 'Features', 'dashboard.plan.stats': 'Stats', 'dashboard.stats.cards': 'Portfolios', 'dashboard.stats.maxCards': 'Max portfolios', 'dashboard.stats.portfolioItems': 'Portfolio items', 'dashboard.stats.maxPortfolioItems': 'Max items', 'dashboard.stats.activeOffers': 'Active offers', 'dashboard.stats.reviewsReceived': 'Reviews', 'dashboard.stats.activeTasks': 'Active tasks', 'dashboard.stats.completedTasks': 'Completed', 'status.need_help': 'I need help', 'status.active': 'Active', 'status.toggle_on': 'Enable', 'status.toggle_off': 'Disable', // FOMO 'fomo.missed_orders': 'Missed {n} orders', 'fomo.missed_value': 'Worth €{v}', 'fomo.upgrade_hint': 'Upgrade to receive more orders', 'fomo.conversion': 'Task conversion', 'fomo.active': 'Active', 'fomo.with_offers': 'With offers', 'fomo.completed': 'Completed', 'fomo.already_offered': '{n} specialists have already responded', 'fomo.specialist_missed': 'You missed {n} orders', 'fomo.top_categories': 'Categories', 'fomo.offers_received': 'offers received', 'fomo.avg_offers': 'Avg {n}/task', 'fomo.completion_rate': 'completed', // Task auto-match 'task.auto_match': 'Auto-match', 'task.auto_match_results': 'Top specialists', 'task.no_offer_yet': 'You haven\'t sent an offer yet', 'task.make_offer': 'Send offer', 'auto_response.title': 'Auto-Response', 'auto_response.enabled': 'Enable auto-response', 'auto_response.min_budget': 'Min budget', 'auto_response.max_budget': 'Max budget', 'auto_response.default_price': 'Default price', 'auto_response.default_message': 'Default message', 'auto_response.max_per_day': 'Max auto-offers per day', 'auto_response.save': 'Save', 'auto_response.saved': 'Saved', 'auto_response.categories': 'Categories', 'auto_response.locations': 'Locations', // Personal site 'profile.personal_site': 'Personal Site', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Only latin letters, numbers, - and _', 'profile.site_open': 'Open site', 'profile.site_preview': 'Your site', 'profile.show_contact': 'Show contact info', 'profile.show_contact_hint': 'Customers with Pro/Ultimate plans will see your phone number', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Calendar requires a Pro or Ultimate plan', // Chat limits 'chat.limit_warning': '{n} messages left today', 'chat.limit_reached': 'Message limit reached. Upgrade your plan', 'chat.upgrade': 'Upgrade', // Site page 'site.member_since': 'Member since', 'site.rating': 'Rating', 'site.completed_tasks': 'Completed', 'site.languages': 'Languages', 'site.photos': 'photos', 'site.contact_form': 'Get in touch', 'site.contact_sent': 'Message sent!', 'site.contact_sent_desc': 'The specialist will contact you soon', 'site.contact_name': 'Name', 'site.contact_name_ph': 'Your name', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Message', 'site.contact_message_ph': 'Describe your task...', 'site.contact_send': 'Send', 'site.share': 'Share', 'site.speaks_languages': 'Speaks', 'site.message_sent': 'Message sent!', 'site.message_sent_desc': 'The specialist will receive it in the chat', 'site.message_placeholder': 'Write your message...', 'site.write_to_chat': 'Write to chat', 'site.auth_required_title': 'Sign in required', 'site.auth_required_desc': 'To write in the chat, you need to sign in to your CanHelp account.', 'site.auth_login_btn': 'Sign in', 'site.auth_contact_form_btn': 'Contact via feedback form', 'specialist.services': 'Services', 'portfolio.title': 'Portfolio', 'status.can_help_now': 'Available now', 'common.not_found': 'Page not found', 'common.anonymous': 'Anonymous', 'specialist_setup.page_title': 'Specialist profile setup', 'specialist_setup.step_of': 'Step {current} of {total}', 'specialist_setup.next': 'Next', 'specialist_setup.back': 'Back', 'specialist_setup.skip': 'Skip', 'specialist_setup.finish': 'Finish', 'specialist_setup.go_to_profile': 'Go to profile', 'specialist_setup.browse_tasks': 'Browse tasks', 'specialist_setup.step1.title': 'Welcome!', 'specialist_setup.step1.subtitle': "Let's set up your profile", 'specialist_setup.step1.desc': 'A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.', 'specialist_setup.step1.what_next': 'What we will do:', 'specialist_setup.step1.item1': 'Fill in basic information', 'specialist_setup.step1.item2': 'Create a service card', 'specialist_setup.step1.item3': 'Add skills and categories', 'specialist_setup.step1.item4': 'Select service area', 'specialist_setup.step1.item5': 'Upload portfolio photos', 'specialist_setup.step2.title': 'Basic profile', 'specialist_setup.step2.subtitle': 'Tell us about yourself', 'specialist_setup.step2.bio_label': 'About me', 'specialist_setup.step2.bio_placeholder': 'Describe your experience, services you offer...', 'specialist_setup.step2.phone_label': 'Phone', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Profile photo', 'specialist_setup.step2.photo_btn': 'Upload photo', 'specialist_setup.step2.photo_uploading': 'Uploading...', 'specialist_setup.step2.photo_hint': 'Shown on your profile', 'specialist_setup.step3.title': 'Service card', 'specialist_setup.step3.subtitle': 'Create your first service card', 'specialist_setup.step3.title_label': 'Card title', 'specialist_setup.step3.title_placeholder': 'E.g. Plumber, Electrician, Cleaning...', 'specialist_setup.step3.desc_label': 'Description', 'specialist_setup.step3.desc_placeholder': 'Describe in detail what you offer, your experience, advantages...', 'specialist_setup.step3.title_required': 'Title is required', 'specialist_setup.step4.title': 'Skills & Categories', 'specialist_setup.step4.subtitle': 'Add skills and select categories', 'specialist_setup.step4.skills_label': 'Skills', 'specialist_setup.step4.skills_placeholder': 'E.g. Pipe installation...', 'specialist_setup.step4.skills_add': 'Add', 'specialist_setup.step4.categories_label': 'Categories', 'specialist_setup.step5.title': 'Service area', 'specialist_setup.step5.subtitle': 'Where do you provide services?', 'specialist_setup.step5.hint': 'Select cities or specific areas', 'specialist_setup.done.title': 'Your profile is ready!', 'specialist_setup.done.subtitle': 'Congratulations! Your profile has been set up', 'specialist_setup.done.desc': 'You can now receive orders from clients. Browse tasks that match your skills.' }, ru: { 'footer.slogan': 'Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.', 'footer.links': 'Ссылки', 'footer.socials': 'Мы в соцсетях', 'nav.home': 'Главная', 'nav.tasks': 'Задачи', 'nav.post': '+ Опубликовать', 'nav.dashboard': 'Панель управления', 'nav.chat': 'Сообщения', 'nav.notifications': 'Уведомления', 'nav.profile': 'Профиль', 'nav.admin': 'Админка', 'nav.specialists': 'Специалисты', 'nav.new_task': 'Новая задача', 'nav.login': 'Войти', 'nav.register': 'Регистрация', 'nav.logout': 'Выйти', 'hero.title': 'Найди специалиста для любой работы', 'hero.subtitle': 'Опубликуй задачу, получи предложения и выбери лучшего профессионала', 'hero.cta.post': 'Опубликовать задачу', 'hero.cta.browse': 'Стать специалистом', 'hero.search.placeholder': 'Что нужно? напр. электрик, уборка...', 'stats.specialists': 'специалистов', 'stats.tasks': 'задач', 'stats.categories': 'категорий', 'stats.free': 'бесплатная регистрация', 'section.categories': 'Создай задачу в любой категории', 'section.how': 'Как это работает', 'section.recent': 'Последние задачи', 'section.all': 'Смотреть все →', 'section.more': 'ещё', 'section.cities': 'Города и районы', 'section.community': 'Общественный проект для всех', 'community.subtitle': 'CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.', 'community.point1.title': 'Умеете что-то делать?', 'community.point1.desc': 'Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.', 'community.point2.title': 'Нужна помощь?', 'community.point2.desc': 'Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.', 'community.point3.title': 'Помогите проекту расти', 'community.point3.desc': 'CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.', 'community.share': 'Поделиться с друзьями', 'community.share.copied': 'Ссылка скопирована!', // Referral section on home page 'section.referral': 'Реферальная программа', 'referral.home.subtitle': 'Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.', 'referral.home.step1.title': 'Зарегистрируйтесь и получите ссылку', 'referral.home.step1.desc': 'Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.', 'referral.home.step2.title': 'Поделитесь с друзьями', 'referral.home.step2.desc': 'Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.', 'referral.home.step3.title': 'Получайте награды', 'referral.home.step3.desc': 'Как только друг подтвердит email, вы автоматически получите свою награду.', 'referral.home.cta': 'Получить ссылку', 'referral.home.badge': 'Реферальная программа', // FAQ section 'section.faq': 'Частые вопросы', 'faq.q1': 'Как работает CanHelp?', 'faq.a1': 'Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.', 'faq.q2': 'Сколько стоит использование платформы?', 'faq.a2': 'Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.', 'faq.q3': 'Как стать специалистом?', 'faq.a3': 'Зарегистрируйтесь, перейдите в «Стать специалистом», заполните профиль навыками и категориями и начните получать задачи.', 'faq.q4': 'Как выбрать подходящего специалиста?', 'faq.a4': 'Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.', 'faq.q5': 'Что если я не доволен результатом?', 'faq.a5': 'Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.', 'faq.q6': 'Можно ли связаться со специалистом до принятия предложения?', 'faq.a6': 'Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.', 'faq.q7': 'Сколько времени ждать предложений?', 'faq.a7': 'Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.', 'faq.q8': 'Можно ли разместить задачу в любом городе Греции?', 'faq.a8': 'Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.', 'faq.q9': 'Какие виды задач есть на CanHelp?', 'faq.a9': 'Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.', 'faq.q10': 'Есть ли мобильное приложение?', 'faq.a10': 'Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.', 'how.step1.title': 'Опубликуй задачу', 'how.step1.desc': 'Опиши что нужно и установи бюджет', 'how.step2.title': 'Получи предложения', 'how.step2.desc': 'Специалисты пришлют предложения с ценой и сроками', 'how.step3.title': 'Выбери и начни', 'how.step3.desc': 'Выбери лучшего профессионала и начни сотрудничество', 'tasks.title': 'задач', 'tasks.filters': 'Фильтры', 'tasks.search': 'Поиск', 'tasks.search.placeholder': 'Название или ключевое слово...', 'tasks.search.btn': 'Поиск', 'tasks.publish': 'Опубликовать', 'tasks.category.all': 'Все', 'tasks.category.all_in': 'Все в', 'tasks.category.label': 'Категория', 'tasks.location.label': 'Город', 'tasks.location.placeholder': 'напр. Афины', 'tasks.empty': 'Задачи не найдены', 'tasks.empty.cta': 'Опубликуй первую', 'task.status.open': 'Открыта', 'task.status.in_progress': 'В работе', 'task.status.completed': 'Завершена', 'task.status.cancelled': 'Отменена', 'task.status.draft': 'Черновик', 'task.budget': 'Бюджет', 'task.location': 'Местоположение', 'task.deadline': 'Дата начала', 'task.created_at': 'Создано', 'task.customer': 'Заказчик', 'task.offer.btn': 'Отправить предложение', 'task.invite.banner_title': 'Вас пригласили на это задание', 'task.invite.banner_hint': 'Заказчик лично пригласил вас', 'task.invite.accept': 'Отправить предложение', 'task.invite.decline': 'Отказаться', 'offer.accept': 'Принять', 'offer.decline': 'Отклонить', 'task.complete': 'Завершить задачу', 'task.complete.confirm': 'Отметить задачу как выполненную?', 'task.edit': 'Редактировать', 'task.status_label': 'Статус', 'task.yours': 'Ваша задача', 'task.offer.yours': 'Ваше предложение', 'review.leave': 'Оставить отзыв', 'review.rating': 'Оценка', 'review.comment': 'Комментарий', 'review.comment.placeholder': 'Расскажите о своём опыте...', 'review.submit': 'Отправить отзыв', 'review.submitting': 'Отправка...', 'review.done': 'Отзыв отправлен!', 'profile.reviews': 'Отзывы', 'profile.no_reviews': 'Отзывов пока нет', 'profile.rating': 'Рейтинг', 'profile.skills.label': 'Навыки', 'profile.member_since': 'Участник с', 'task.offers': 'Предложения', 'task.offers.none': 'Предложений пока нет', 'create.title': 'Опубликовать задачу', 'create.field.title': 'Название', 'create.field.description': 'Описание', 'create.field.category': 'Категория', 'create.field.category.select': 'Выберите...', 'create.field.location': 'Местоположение', 'create.field.location.any': 'Где угодно', 'create.field.location.all': 'Весь город', 'create.field.budget': 'Бюджет (€)', 'create.field.deadline': 'Дата начала', 'create.field.budget_negotiable': 'Цена обсуждается', 'create.field.time_slot': 'Время выполнения', 'create.field.time_slot.any': 'В любое время', 'create.field.time_slot.morning': 'Утром (08:00–13:00)', 'create.field.time_slot.afternoon': 'Днём (13:00–18:00)', 'create.field.time_slot.evening': 'Вечером (18:00–22:00)', 'create.field.time_slot.weekend': 'Выходной', 'create.field.address': 'Адрес (необязательно)', 'create.field.address.district': 'Квартал', 'create.field.address.street': 'Улица', 'create.field.address.house': 'Дом', 'create.field.confidential': 'Конфиденциальная заметка', 'create.field.confidential.placeholder': 'Детали, видные только назначенному специалисту...', 'create.field.confidential.hint': 'Не отображается публично', 'create.field.photos': 'Фотографии', 'create.field.photos.add': 'Добавить фото', 'create.field.photos.uploading': 'Загрузка...', 'task.budget_negotiable': 'Цена обсуждается', 'task.time_slot': 'Время', 'task.confidential': 'Конфид. заметка', 'create.field.title.placeholder': 'напр. Уборка квартиры 80кв', 'create.field.description.placeholder': 'Подробно опишите что нужно...', 'create.field.location.placeholder': 'напр. Афины, Колонаки', 'create.field.budget.placeholder': 'напр. 100', 'create.submit': 'Опубликовать задачу', 'create.submitting': 'Публикация...', 'login.title': 'Добро пожаловать', 'login.subtitle': 'Вход в CanHelp', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.submitting': 'Вход...', 'login.error': 'Неверный email или пароль', 'login.unverified.title': 'Подтвердите ваш email', 'login.unverified.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'login.unverified.resend': 'Отправить письмо повторно', 'login.unverified.sending': 'Отправка...', 'login.unverified.sent': '✓ Отправлено — проверьте входящие', 'profile.email.verified': 'Email подтверждён', 'profile.email.not_verified': 'Email не подтверждён', 'login.no_account': 'Нет аккаунта?', 'login.register_link': 'Зарегистрироваться', 'login.forgot_password': 'Забыл пароль?', 'login.or_continue_with': 'или продолжите через', 'login.continue_google': 'Войти через Google', 'forgot.title': 'Забыл пароль', 'forgot.subtitle': 'Введите email для получения ссылки восстановления', 'forgot.email': 'Email', 'forgot.submit': 'Отправить ссылку', 'forgot.submitting': 'Отправка...', 'forgot.sent.title': 'Проверьте входящие', 'forgot.sent.desc': 'Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.', 'forgot.back_to_login': 'Вернуться ко входу', 'forgot.error': 'Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.', 'forgot.error.not_found': 'Аккаунт с таким email не найден.', 'forgot.error.send_failed': 'Ошибка отправки письма. Попробуйте позже.', 'reset.title': 'Новый пароль', 'reset.subtitle': 'Введите новый пароль', 'reset.password': 'Новый пароль', 'reset.confirm': 'Подтвердите пароль', 'reset.submit': 'Изменить пароль', 'reset.submitting': 'Сохранение...', 'reset.success': 'Пароль успешно изменён. Перенаправление ко входу...', 'reset.back_to_login': 'Вернуться ко входу', 'reset.error.mismatch': 'Пароли не совпадают', 'reset.error.invalid': 'Недействительная или устаревшая ссылка. Запросите новую.', 'register.title': 'Регистрация', 'register.subtitle': 'Создать аккаунт в CanHelp', 'register.first_name': 'Имя', 'register.last_name': 'Фамилия', 'register.email': 'Email', 'register.password': 'Пароль (мин. 8 символов)', 'register.role': 'Роль', 'register.role.customer': 'Пользователь', 'register.role.customer.desc': 'Публикую задачи', 'register.role.specialist': 'Специалист', 'register.role.specialist.desc': 'Беру задачи', 'register.submit': 'Создать аккаунт', 'register.submitting': 'Регистрация...', 'register.has_account': 'Уже есть аккаунт?', 'register.login_link': 'Войти', 'register.continue_google': 'Зарегистрироваться через Google', 'register.check_email.title': 'Проверьте почту', 'register.check_email.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'register.check_email.login': 'Вернуться к входу', 'dashboard.title': 'Панель управления', 'dashboard.new_task': '+ Новая задача', 'dashboard.my_tasks': 'Мои задачи', 'dashboard.my_offers': 'Мои предложения', 'dashboard.invitations': 'Приглашения на задания', 'dashboard.offers_count': 'предл.', 'dashboard.declined_count': 'откл.', 'dashboard.completed_tasks': 'Завершённые задачи', 'dashboard.completed_offers': 'Завершённые предложения', 'dashboard.review_pending': 'Оценка ещё не оставлена', 'tasks.new.top_specialists': 'Топ специалисты', 'tasks.new.select_category': 'Выберите категорию, чтобы увидеть специалистов', 'tasks.new.invite': 'Предложить работу', 'tasks.new.invited': 'Выбран ✓', 'reviews.count': 'отзывов', 'filter.location': 'Локация', 'filter.language': 'Языки', 'filter.language.any': 'Любой язык', 'filter.category.all': 'Все категории', 'user.categories': 'Категории', 'user.work_area': 'Район работы', 'dashboard.tasks.empty': 'Вы не публиковали задачи', 'dashboard.tasks.empty.cta': 'Опубликуйте первую', 'dashboard.tasks.add_new': 'Добавить новую задачу', 'dashboard.offers.empty': 'Вы не отправляли предложений', 'dashboard.offers.empty.cta': 'Найти задачи', 'dashboard.customer.specialists_title': 'Ищете исполнителя?', 'dashboard.customer.specialists_hint': 'Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи', 'dashboard.customer.specialists_cta': 'Найти исполнителя', 'dashboard.customer.how_title': 'Как это работает', 'dashboard.customer.step1': 'Создайте задачу с описанием и бюджетом', 'dashboard.customer.step2': 'Специалисты пришлют предложения с ценой и сроками', 'dashboard.customer.step3': 'Выберите подходящего и начните работу', 'notif.title': 'Уведомления', 'notif.mark_all': 'Отметить все как прочитанные', 'notif.empty': 'Нет уведомлений', 'notif.type.new_offer': 'Новое предложение', 'notif.type.offer_accepted': 'Ваше предложение принято', 'notif.type.offer_declined': 'Ваше предложение отклонено', 'notif.type.task_completed': 'Задание выполнено', 'notif.type.task_cancelled': 'Задание отменено', 'notif.type.new_message': 'Новое сообщение', 'notif.type.new_review': 'Новый отзыв', 'notif.type.task_invite': 'Приглашение на задание', 'notif.body.new_offer': 'Новое предложение на «{title}»', 'notif.body.offer_accepted': 'Ваше предложение на «{title}» принято', 'notif.body.offer_declined': 'Ваше предложение на «{title}» отклонено', 'notif.body.task_invite': 'Вас приглашают на «{title}»', 'notif.body.new_review': 'Вы получили оценку {rating}★', 'offer.status.pending': 'Ожидает', 'offer.status.accepted': 'Принято', 'offer.status.declined': 'Отклонено', 'offer.status.withdrawn': 'Отозвано', 'offer.status.other_accepted': 'Выбран другой исполнитель', 'common.loading': 'Загрузка...', 'common.error': 'Ошибка', 'common.save': 'Сохранить', 'common.saving': 'Сохранение...', 'common.cancel': 'Отмена', 'common.add': 'Добавить', 'common.close': 'Закрыть', 'common.edit': 'Редактировать', 'common.delete': 'Удалить', 'common.from': 'от', 'common.currency': '€', 'common.greece': 'Греция', // Chat 'chat.connected': 'Подключено', 'chat.disconnected': 'Отключено', 'chat.no_rooms': 'Переписок пока нет', 'chat.task_fallback': 'Задача', 'chat.select': 'Выберите переписку', 'chat.no_messages': 'Сообщений пока нет', 'chat.placeholder': 'Напишите сообщение... (Enter для отправки)', 'chat.conversation_fallback': 'Переписка', 'chat.direct_chat': 'Личный чат', 'chat.linked_task': 'Прикреплённый заказ', 'chat.write_btn': 'Написать', 'chat.just_now': 'только что', 'chat.min_ago': 'м', 'chat.write_specialist': 'Написать специалисту', 'chat.write_customer': 'Написать заказчику', 'chat.notif_settings': 'Настройки уведомлений', 'chat.notif_messages': 'Уведомления о новых сообщениях', 'chat.toast_title': 'Новое сообщение', 'chat.toast_open': 'Открыть чат', // Offer form 'offer.price': 'Цена', 'offer.price.placeholder': 'напр. 80', 'offer.customer_budget': 'Бюджет заказчика', 'offer.message': 'Сообщение', 'offer.optional': 'необязательно', 'offer.message.placeholder': 'Представьтесь, расскажите об опыте и почему вы лучший выбор...', 'offer.submitting': 'Отправка...', // Profile 'profile.photo': 'Фото профиля', 'profile.photo.change': 'Изменить фото', 'profile.photo.hint': 'JPEG, PNG, WebP · до 5MB', 'profile.basic_info': 'Основная информация', 'profile.phone': 'Телефон', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Краткое описание', 'profile.bio.placeholder': 'Расскажите немного о себе...', 'profile.language': 'Язык', 'profile.language.hint': 'Язык интерфейса и email-уведомлений', 'profile.languages': 'Языки общения', 'profile.languages.hint': 'Выберите все языки, на которых вы общаетесь', 'profile.skills': 'Навыки', 'profile.skills.subtitle': 'Добавьте услуги, которые вы предлагаете', 'profile.skills.placeholder': 'напр. Уборка, IT, Репетиторство...', 'profile.role': 'Роль аккаунта', 'profile.role.specialist': '🔧 Специалист', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Пользователь', 'profile.role.change': 'Для смены роли обратитесь в службу поддержки.', 'profile.become_specialist': 'Стать специалистом', 'profile.become_specialist.desc': 'Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.', 'become_specialist.hero.title': 'Зарабатывай, делая то, что умеешь', 'become_specialist.hero.subtitle': 'Создай профиль специалиста и получай заказы от клиентов по всей Греции', 'become_specialist.how.title': 'Как это работает', 'become_specialist.step1.title': 'Создай портфолио специалиста', 'become_specialist.step1.desc': 'Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы', 'become_specialist.step2.title': 'Ищи заказы', 'become_specialist.step2.desc': 'Просматривай задачи по своим категориям в разделе «Поиск заказов»', 'become_specialist.step3.title': 'Откликайся и зарабатывай', 'become_specialist.step3.desc': 'Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы', 'become_specialist.benefits.title': 'Преимущества профиля специалиста', 'become_specialist.benefit1': 'Поиск заказов по вашим категориям и локации', 'become_specialist.benefit2': 'Публичный профиль с отзывами клиентов', 'become_specialist.benefit3': 'Расписание доступности, видимое клиентам', 'become_specialist.benefit4': 'Добавление в избранное клиентами', 'become_specialist.cta': 'Подробнее', 'become_specialist.free_badge': 'Бесплатная регистрация', 'profile.tab.notifications': 'Уведомления', 'profile.tab.reviews': 'Отзывы', 'profile.tab.referral': 'Рефералы', 'profile.tab.auto_response': 'Авто-ответ', 'profile.tab.site': 'Сайт', 'profile.site.title': 'Персональная страница', 'profile.site.url_label': 'Личный сайт', 'profile.site.copy': 'Копировать', 'profile.site.copied': 'Скопировано', 'profile.site.visible_title': 'Что отображается на вашей странице', 'profile.site.visible.name': 'Имя и фото', 'profile.site.visible.bio': 'Биография', 'profile.site.visible.rating': 'Рейтинг и отзывы', 'profile.site.visible.portfolio': 'Портфолио / Карточки', 'profile.site.visible.contacts': 'Контактные данные', 'profile.site.visible.full_last_name': 'Фамилия полностью', 'profile.site.visible.services': 'Карточки услуг', 'profile.site.visible.reviews': 'Раздел с отзывами', 'profile.site.visible.status': 'Статус «Готов помочь»', 'profile.site.theme': 'Тема оформления', 'profile.site.theme.dark': 'Тёмная', 'profile.site.theme.light': 'Светлая', 'profile.site.slug_taken': 'Этот адрес уже занят', 'profile.site.stats.title': 'Аналитика сайта', 'profile.site.stats.days': 'последние 30 дней', 'profile.site.stats.views': 'Просмотры', 'profile.site.stats.unique': 'Уникальные посетители', 'profile.site.stats.messages': 'Сообщения', 'profile.site.stats.total_views': 'Просмотры', 'profile.site.stats.total_unique': 'Уник. посетители', 'profile.site.stats.total_messages': 'Сообщения', 'profile.site.stats.empty': 'Данных пока нет', 'profile.site.stats.loading': 'Загрузка аналитики...', 'profile.site.stats.no_slug': 'Укажите адрес сайта, чтобы видеть статистику', 'profile.site.edit_bio_hint': 'Биография и фото настраиваются во вкладке «Основное».', 'status.title': 'Статус', 'status.can_help_now_hint': 'Ваша карточка показывается выше в поиске', 'status.need_help_hint': 'Специалисты могут предложить вам помощь', 'profile.referral.title': 'Партнёрская программа', 'profile.referral.desc': 'Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.', 'profile.referral.link_label': 'Ваша реферальная ссылка', 'profile.referral.copy': 'Копировать', 'profile.referral.copied': 'Скопировано!', 'profile.referral.invited_count': 'успешных приглашений', 'profile.referral.no_code': 'Реферальный код недоступен.', 'notifications.title': 'Настройки уведомлений', 'notifications.email.new_tasks': 'Email о новых заказах', 'notifications.email.new_tasks.desc': 'Получать email, когда в ваших категориях публикуется новый заказ', 'notifications.messages.desc': 'Получать уведомление при новом входящем сообщении', 'notifications.saved': 'Настройки сохранены', 'notifications.plan_required': 'Недоступно в вашем тарифе', 'profile.tab.info': 'Основное', 'profile.tab.finance': 'Финансы', 'profile.tab.skills': 'Навыки', 'profile.tab.categories': 'Категории', 'profile.tab.geography': 'География', 'profile.specialist.categories': 'Категории работ', 'profile.specialist.categories.desc': 'Выберите категории, в которых вы работаете', 'profile.specialist.geography': 'Города покрытия', 'profile.specialist.geography.desc': 'Выберите города / районы, где вы работаете', 'profile.saving': 'Сохранение...', 'profile.upload.error': 'Ошибка загрузки фото', 'profile.saved': 'Сохранено', 'profile.tab.cards': 'Портфолио', 'profile.cards.count': 'Портфолио', 'profile.cards.add': 'Добавить портфолио', 'profile.cards.new_title': 'Название нового портфолио', 'profile.cards.placeholder': 'Например: Сантехника', 'profile.cards.create': 'Создать', 'profile.cards.cancel': 'Отмена', 'profile.cards.empty': 'У вас нет портфолио', 'profile.cards.create_first': 'Создать первое портфолио', 'profile.cards.delete_confirm': 'Удалить портфолио?', 'profile.card.tab.main': 'Основное', 'profile.card.tab.skills': 'Навыки', 'profile.card.tab.categories': 'Категории', 'profile.card.tab.geography': 'География', 'profile.card.tab.portfolio': 'Галерея', 'profile.card.active': 'Активна', 'profile.card.save': 'Сохранить', 'profile.card.saved': 'Сохранено', 'profile.card.delete': 'Удалить', 'profile.card.skill.add': 'Добавить навык', 'profile.card.photo.add': 'Добавить фото', 'profile.card.photo.uploading': 'Загрузка...', 'profile.card.photo.empty': 'Нет фотографий', 'profile.card.item.title': 'Заголовок', 'profile.card.item.desc': 'Описание', 'profile.card.item.save': 'Сохранить', 'profile.card.item.cancel': 'Отмена', 'profile.card.item.edit': 'Описание работы', 'profile.upgrade.cards_limit': 'Лимит портфолио исчерпан', 'profile.upgrade.plan': 'Текущий тариф:', 'profile.upgrade.contact': 'Обратитесь к администратору для смены тарифа', 'profile.upgrade.ok': 'Понятно', 'profile.plan.title': 'Тарифный план', 'profile.balance': 'Баланс', 'profile.balance.topup': 'Пополнить баланс', 'profile.balance.topup.title': 'Пополнить баланс', 'profile.balance.topup.amount': 'Сумма (в EUR)', 'profile.balance.topup.hint': 'Выберите сумму или введите вручную', 'profile.balance.topup.submit': 'Перейти к оплате', 'profile.balance.topup.loading': 'Перенаправление...', 'profile.balance.topup.error': 'Ошибка инициализации платежа. Попробуйте снова.', 'payment.success.title': 'Оплата прошла успешно!', 'payment.success.desc': 'Ваш баланс обновлён.', 'payment.cancelled.title': 'Оплата отменена', 'payment.cancelled.desc': 'Оплата была отменена. Средства не списаны.', 'payment.pending.title': 'Обрабатывается...', 'payment.pending.desc': 'Ваш платёж в обработке.', 'payment.back_to_profile': 'Вернуться в профиль', 'profile.plan.basic': 'Базовый (бесплатный)', 'profile.plan.contact_upgrade': 'Обратитесь к администратору для подключения тарифа', 'profile.plan.cards_up_to': 'Портфолио: до', 'profile.plan.cards_unlimited': 'Портфолио: безлимитно', 'profile.plan.tasks_up_to': 'Задач: до', 'profile.plan.offers_up_to': 'Откликов: до', 'profile.plan.valid_until': 'Действителен до', 'profile.plan.no_expiry': 'Бессрочно', // Create task 'create.error': 'Ошибка при публикации', // Tasks list extras 'tasks.category.general': 'Общее', 'tasks.budget.range': 'Диапазон:', 'tasks.budget.from': 'от', 'tasks.budget.to': 'до', 'tasks.filter.reset': 'Сбросить фильтры', 'tasks.load_more': 'Загрузить ещё', 'tasks.showing': 'Результатов:', 'tasks.field.budget': 'Бюджет, €', // Admin 'admin.title': 'Панель администратора', 'admin.tab.stats': 'Статистика', 'admin.tab.users': 'Пользователи', 'admin.tab.tasks': 'Задачи', 'admin.tab.reports': 'Жалобы', 'admin.stats.users': 'Пользователи', 'admin.stats.tasks': 'Задачи', 'admin.stats.offers': 'Предложения', 'admin.stats.reviews': 'Отзывы', 'admin.tasks.by_status': 'Задачи по статусу', 'admin.col.user': 'Пользователь', 'admin.col.email': 'Email', 'admin.col.role': 'Роль', 'admin.col.registered': 'Регистрация', 'admin.col.status': 'Статус', 'admin.col.title': 'Название', 'admin.col.budget': 'Бюджет', 'admin.col.created': 'Создано', 'admin.users.active': 'Активен', 'admin.users.inactive': 'Неактивен', 'admin.users.deactivate': 'Деактивировать', 'admin.users.activate': 'Активировать', 'admin.tasks.cancel': 'Отменить', 'admin.reports.none': 'Жалоб нет', 'admin.reports.reviewed': 'Рассмотрено', 'admin.reports.dismiss': 'Отклонить', 'admin.pagination.total': 'Всего', 'admin.users.role.change': 'Изменить роль', 'admin.users.search.placeholder': 'Поиск по имени или email...', 'admin.tasks.delete': 'Удалить', 'admin.tasks.delete.confirm': 'Удалить эту задачу навсегда?', 'admin.tasks.search.placeholder': 'Поиск по названию...', 'admin.col.customer': 'Заказчик', 'admin.col.reporter': 'Жалобщик', 'admin.col.target': 'Цель', 'admin.filter.all_roles': 'Все роли', 'admin.filter.all_statuses': 'Все статусы', 'admin.reports.target.task': 'Задача', 'admin.reports.target.user': 'Пользователь', 'admin.tab.categories': 'Категории', 'admin.tab.locations': 'Города и районы', 'admin.tab.logs': 'Логи', 'admin.tab.plans': 'Тарифы', 'admin.tab.settings': 'Настройки', 'admin.logs.subtab.ai': 'AI логи', 'admin.logs.subtab.activity': 'Активность', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Уведомления', 'admin.notif_logs.type': 'Тип', 'admin.notif_logs.title': 'Заголовок', 'admin.notif_logs.read': 'Прочитано', 'admin.notif_logs.empty': 'Логи уведомлений пусты', 'admin.stats.notif_chart_title': 'Уведомления по дням', 'admin.stats.notif_label': 'Уведомления', 'admin.stats.mail_chart_title': 'Email по дням', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Все', 'admin.stats.specialists': 'Исполнители', 'admin.col.plan': 'Тариф', 'admin.back_home': 'На главную', 'admin.plans.title': 'Тарифные пакеты', 'admin.plans.add': '+ Добавить тариф', 'admin.plans.empty': 'Тарифы не созданы', 'admin.plans.form.new': 'Новый тариф', 'admin.plans.form.edit': 'Редактировать тариф', 'admin.plans.form.name': 'Название', 'admin.plans.form.price': 'Цена (EUR)', 'admin.plans.form.old_price': 'Старая цена (EUR, необязательно)', 'admin.plans.form.max_offers': 'Макс. откликов (пусто = без лимита)', 'admin.plans.form.max_cards': 'Макс. портфолио (пусто = без лимита)', 'admin.plans.form.duration_days': 'Срок (дней, пусто = без истечения)', 'admin.plans.form.description': 'Описание', 'admin.plans.form.features': 'Возможности (по одной на строку)', 'admin.plans.form.notify': 'Уведомления о новых заказах', 'admin.plans.form.default': 'По умолчанию', 'admin.plans.form.active': 'Активен', 'admin.plans.form.order': 'Порядок', 'admin.plans.form.role': 'Роль', 'admin.plans.form.tier': 'Уровень', 'admin.plans.form.role.customer': 'Заказчик', 'admin.plans.form.role.specialist': 'Специалист', 'admin.plans.form.tier.free': 'Бесплатный', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Лимиты (пусто = без ограничений)', 'admin.plans.form.max_messages_day': 'Макс. сообщений/день', 'admin.plans.form.max_orders_day': 'Макс. заказов/день', 'admin.plans.form.max_skills': 'Макс. навыков', 'admin.plans.form.max_profiles': 'Макс. профилей', 'admin.plans.form.max_portfolio': 'Макс. элементов портфолио', 'admin.plans.form.section.boost': 'Множители & Буст', 'admin.plans.form.search_boost': 'Буст в поиске', 'admin.plans.form.offers_multiplier': 'Множитель откликов', 'admin.plans.form.section.contact': 'Права контактов', 'admin.plans.form.can_contact_free': 'Контакт с бесплатными пользователями', 'admin.plans.form.can_contact_pro': 'Контакт с Pro пользователями', 'admin.plans.form.can_contact_all': 'Контакт со всеми', 'admin.plans.form.can_show_contact': 'Показывать контакты', 'admin.plans.form.can_view_phone': 'Просмотр телефона', 'admin.plans.form.section.features': 'Возможности', 'admin.plans.form.upload_video': 'Загрузка видео', 'admin.plans.form.favorites': 'Избранное', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Знак верификации', 'admin.plans.form.highlighted_reviews': 'Выделенные отзывы', 'admin.plans.form.personal_site': 'Личный сайт', 'admin.plans.form.can_help_now': 'Статус «Могу помочь»', 'admin.plans.form.need_help': 'Статус «Нужна помощь»', 'admin.plans.form.auto_response': 'Автоответ', 'admin.plans.form.auto_match': 'Автоподбор', 'admin.plans.form.instant_dispatch_free': 'Мгновенная рассылка (бесплатно)', 'admin.plans.form.instant_dispatch_pro': 'Мгновенная рассылка (Pro)', 'admin.plans.badge.default': 'По умолчанию', 'admin.plans.badge.inactive': 'Неактивен', 'admin.plans.make_default': 'Сделать по умолчанию', 'admin.plans.tasks': 'Задач', 'admin.plans.offers': 'Откликов', 'admin.plans.cards': 'Портфолио', 'admin.plans.notify_tasks': 'Уведомления о заказах', 'admin.plans.delete.confirm': 'Удалить тариф', 'admin.activity.title': 'Журнал активности', 'admin.activity.event': 'Событие', 'admin.activity.all_events': 'Все события', 'admin.activity.from': 'От', 'admin.activity.to': 'До', 'admin.activity.reset': 'Сбросить', 'admin.activity.total': 'Всего', 'admin.activity.empty': 'Нет записей', 'admin.mail.event': 'Email событие', 'admin.mail.all_events': 'Все email события', 'admin.mail.from': 'От', 'admin.mail.to': 'До', 'admin.mail.reset': 'Сбросить', 'admin.mail.total': 'Всего', 'admin.mail.empty': 'Нет email логов', 'admin.mail.recipient': 'Получатель', 'admin.mail.provider': 'Провайдер', 'admin.mail.details': 'Детали', 'admin.mail.status': 'Статус', 'admin.mail.success': 'Успешно', 'admin.mail.failed': 'Ошибка', 'admin.event.email_sent': 'Email отправлен', 'admin.event.email_failed': 'Email не отправлен', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Тестовый email отправлен', 'admin.event.admin_email_test_failed': 'Тестовый email не отправлен', 'admin.logs.empty': 'Нет записей', 'admin.logs.date': 'Дата', 'admin.logs.provider': 'Провайдер', 'admin.logs.model': 'Модель', 'admin.logs.action': 'Действие', 'admin.logs.langs': 'Языки', 'admin.logs.in': 'Вход', 'admin.logs.out': 'Выход', 'admin.logs.total': 'Итого', 'admin.logs.ms': 'мс', 'admin.logs.status': 'Статус', 'admin.stats.activity_30d': 'Активность за 30 дней', 'admin.stats.tasks_label': 'Заявки', 'admin.stats.users_label': 'Пользователи', 'admin.stats.specialists_label': 'Исполнители', 'admin.stats.tokens_title': 'Расход токенов (по месяцам)', 'admin.stats.tokens_out': 'Исходящие', 'admin.stats.tokens_in': 'Входящие', 'admin.stats.tokens_out_label': 'Исходящие токены', 'admin.stats.tokens_in_label': 'Входящие токены', 'admin.stats.cost_label': 'Стоимость (USD)', 'admin.stats.tasks_by_status': 'Заявки по статусам', 'admin.task_status.open': 'Открытые', 'admin.task_status.in_progress': 'В работе', 'admin.task_status.completed': 'Завершённые', 'admin.task_status.cancelled': 'Отменённые', 'admin.task_status.draft': 'Черновики', 'admin.settings.tab.general': 'Общие', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Уведомления', 'admin.settings.tab.payment': 'Оплата', 'admin.settings.tab.referral': 'Реферальная', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Соцсети', 'admin.settings.socials.title': 'Ссылки на социальные сети', 'admin.settings.socials.hint': 'Заполненные ссылки отображаются в подвале сайта', 'admin.settings.seo.maintenance_label': 'Режим обслуживания', 'admin.settings.seo.maintenance_hint': 'Показывать страницу обслуживания всем посетителям', 'admin.settings.seo.indexing_label': 'Индексация поисковыми системами', 'admin.settings.seo.indexing_hint': 'Разрешить поисковым системам индексировать сайт', 'admin.settings.seo.head_scripts_label': 'Скрипты в (JS)', 'admin.settings.seo.head_scripts_hint': 'Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)', 'admin.settings.seo.site_title_label': 'Заголовок сайта', 'admin.settings.seo.site_description_label': 'Описание сайта (meta description)', 'admin.settings.referral.title': 'Партнёрская программа', 'admin.settings.referral.hint': 'Награждайте пользователей, приводящих новых участников.', 'admin.settings.referral.enabled_label': 'Включено', 'admin.settings.referral.enabled_hint': 'Включить / отключить выдачу наград', 'admin.settings.referral.customer_section': 'Для клиентов', 'admin.settings.referral.specialist_section': 'Для специалистов', 'admin.settings.referral.plan_label': 'Тарифный план за реферала', 'admin.settings.referral.no_plan': '— без плана —', 'admin.settings.referral.plan_hint': 'Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.', 'admin.settings.referral.days_label': 'Дней награды', 'admin.settings.referral.days_hint': 'Количество дней, добавляемых к сроку действия плана.', 'admin.settings.general.title': 'Общие настройки', 'admin.settings.general.site_name': 'Название сайта', 'admin.settings.general.site_url': 'URL сайта', 'admin.settings.general.contact_email': 'Email для связи', 'admin.settings.general.support_phone': 'Телефон поддержки', 'admin.settings.smtp.title': 'Настройки SMTP сервера', 'admin.settings.smtp.hint': 'Используется для отправки email-уведомлений.', 'admin.settings.smtp.host': 'SMTP Хост', 'admin.settings.smtp.port': 'Порт', 'admin.settings.smtp.encryption': 'Шифрование', 'admin.settings.smtp.enc.none': 'Нет', 'admin.settings.smtp.enc.tls': 'STARTTLS (порт 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (порт 465)', 'admin.settings.smtp.username': 'Имя пользователя', 'admin.settings.smtp.password': 'Пароль / App Password', 'admin.settings.smtp.from_name': 'Имя отправителя', 'admin.settings.smtp.from_email': 'Email отправителя', 'admin.settings.smtp.test': 'Отправить тестовый email', 'admin.settings.smtp.sending': 'Отправка...', 'admin.settings.payment.hint': 'Данные для подключения к ePay Piraeus Bank.', 'admin.settings.env.test': 'Тест (sandbox)', 'admin.settings.env.prod': 'Боевой режим', 'admin.settings.env.label': 'Среда', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Активен', 'admin.settings.saving': 'Сохранение...', 'admin.settings.saved': 'Сохранено', 'admin.notif.vars_hint': 'Доступные переменные в шаблонах', 'admin.notif.tmpl.not_set': 'Шаблон не настроен', 'admin.notif.tmpl.subject_label': 'Тема письма', 'admin.notif.tmpl.body_label': 'Текст письма (HTML)', 'admin.notif.tmpl.save': 'Сохранить', 'admin.notif.tmpl.close': 'Закрыть', 'admin.notif.tmpl.translate': 'Авто-перевод на другие языки', 'admin.notif.tmpl.translating': 'Перевод...', 'admin.notif.tmpl.saving': 'Сохранение...', 'admin.notif.email_verification': 'Подтверждение email адреса', 'admin.notif.registration_success': 'Успешная регистрация', 'admin.notif.password_reset': 'Восстановление пароля', 'admin.notif.new_offer': 'Новое предложение', 'admin.notif.new_task': 'Новая задача', 'admin.notif.offer_accepted': 'Предложение принято', 'admin.notif.new_message': 'Новое сообщение', 'admin.notif.offer_declined': 'Отклонение предложения', 'admin.notif.offer_other_accepted': 'Выбран другой исполнитель', 'admin.notif.task_updated': 'Изменение задания', 'admin.notif.deadline_reminder': 'Напоминание о дедлайне', 'admin.notif.task_archived': 'Автоснятие задания', 'admin.notif.referral_reward': 'Реферальная награда', // Шаблоны email для тарифов 'admin.email_template.plan_activated': 'Тарифы — активация тарифа', 'admin.email_template.plan_upgraded': 'Тарифы — повышение тарифа', 'admin.email_template.plan_downgrade_scheduled': 'Тарифы — запланированное понижение', 'admin.email_template.plan_downgrade_applied': 'Тарифы — применение понижения', 'admin.email_template.plan_renewal_reminder': 'Тарифы — напоминание о продлении', 'admin.email_template.plan_insufficient_funds': 'Тарифы — нехватка средств', // Модальное окно подтверждения тарифа 'pricing.confirm.title': 'Подтвердите выбор тарифа', 'pricing.confirm.plan': 'Тариф', 'pricing.confirm.prorated': 'Зачёт остатка', 'pricing.confirm.effective_price': 'К оплате', 'pricing.confirm.your_balance': 'Ваш баланс', 'pricing.confirm.downgrade_info': 'Переход на новый тариф произойдёт автоматически после окончания текущего периода.', 'pricing.confirm.insufficient': 'Недостаточно средств на балансе.', 'pricing.confirm.top_up': 'Пополнить', 'pricing.confirm.schedule_downgrade': 'Запланировать переход', 'pricing.confirm.pay': 'Оплатить', 'admin.user_edit.title': 'Редактирование пользователя', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email подтверждён', 'admin.user_edit.email_not_verified': 'Email не подтверждён', 'admin.user_edit.verify_email_btn': 'Подтвердить вручную', 'admin.user_edit.verify_email_done': 'Email подтверждён!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Регистрация', 'admin.user_edit.last_seen': 'Последний визит', 'admin.user_edit.lang': 'Язык', 'admin.user_edit.first_name': 'Имя', 'admin.user_edit.last_name': 'Фамилия', 'admin.user_edit.phone': 'Телефон', 'admin.user_edit.bio': 'О себе', 'admin.user_edit.role': 'Роль', 'admin.user_edit.plan': 'Тариф', 'admin.user_edit.no_plan': '— Без тарифа —', 'admin.user_edit.active': 'Активный аккаунт', 'admin.user_edit.balance': 'Баланс (EUR)', 'admin.user_edit.skills': 'Навыки', 'admin.user_edit.tab.profile': 'Профиль', 'admin.user_edit.tab.account': 'Аккаунт', 'admin.user_edit.tab.balance': 'Баланс', 'admin.user_edit.tab.settings': 'Настройки', 'admin.user_edit.tab.specialist': 'Портфолио', 'admin.user_edit.tab.site': 'Сайт', 'admin.user_edit.plan_expires': 'Тариф истекает', 'admin.user_edit.interface_lang': 'Язык интерфейса', 'admin.user_edit.comm_languages': 'Языки общения', 'admin.user_edit.personal_site_slug': 'Персональная страница', 'admin.user_edit.show_contact_info': 'Показывать контакты', 'admin.user_edit.show_contact_info.hint': 'Видно заказчикам', 'admin.user_edit.notify_new_tasks': 'Уведомлять о новых задачах', 'admin.user_edit.notify_new_tasks.hint': 'Push и email уведомления', 'admin.user_edit.notif_messages': 'Уведомления о сообщениях', 'admin.user_edit.notif_messages.hint': 'Новые сообщения в чате', 'admin.user_edit.site_settings': 'Настройки персональной страницы', 'admin.user_edit.categories': 'Категории услуг', 'admin.user_edit.locations': 'Районы обслуживания', 'admin.user_edit.skill_placeholder': 'Новый навык...', 'admin.user_edit.add_category': '— Выберите категорию —', 'admin.user_edit.add_location': '— Выберите район —', 'admin.user_edit.specialist_cards': 'Портфолио специалиста', 'admin.user_edit.no_cards': 'Портфолио не найдено', 'admin.user_edit.card_title': 'Заголовок портфолио', 'admin.user_edit.card_description': 'Описание', 'admin.balance.topup.btn': 'Пополнить', 'admin.balance.withdraw.btn': 'Списать', 'admin.balance.modal_hint': 'Изменения применяются сразу и фиксируются в истории', 'admin.balance.topup.title': 'Пополнение баланса', 'admin.balance.topup.amount': 'Сумма', 'admin.balance.topup.description': 'Комментарий', 'admin.balance.topup.description.placeholder': 'Например: бонус или ручное пополнение', 'admin.balance.topup.submit': 'Пополнить баланс', 'admin.balance.withdraw.title': 'Снятие баланса', 'admin.balance.withdraw.amount': 'Сумма', 'admin.balance.withdraw.description': 'Комментарий', 'admin.balance.withdraw.description.placeholder': 'Например: возврат или ручное списание', 'admin.balance.withdraw.submit': 'Списать баланс', 'admin.user_edit.role.customer': 'Заказчик', 'admin.user_edit.role.specialist': 'Исполнитель', 'admin.user_edit.role.admin': 'Администратор', 'common.refresh': 'Обновить', 'common.back_home': 'На главную', 'admin.loc.hint': 'Управление городами и районами', 'admin.loc.add_city': 'Новый город', 'admin.loc.add_district': 'Добавить район', 'admin.loc.new': 'Новая локация', 'admin.loc.edit': 'Редактировать локацию', 'admin.loc.district': 'район', 'admin.loc.empty': 'Нет локаций', 'admin.loc.delete.confirm': 'Удалить локацию? Все районы также будут удалены.', 'admin.cat.add_root': 'Новая категория', 'admin.cat.add_sub': 'Подкатегория', 'admin.cat.edit': 'Редактировать', 'admin.cat.delete': 'Удалить', 'admin.cat.delete.confirm': 'Удалить категорию? Все подкатегории также будут удалены.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Иконка', 'admin.cat.name_el': 'Греческий', 'admin.cat.name_en': 'Английский', 'admin.cat.name_ru': 'Русский', 'admin.cat.order': 'Порядок', 'admin.cat.active': 'Активна', 'admin.cat.parent': 'Родительская категория', 'admin.cat.no_parent': 'Верхний уровень', 'admin.cat.save': 'Сохранить', 'admin.cat.cancel': 'Отмена', 'admin.cat.empty': 'Нет категорий', 'admin.cat.hint': 'Управление категориями с многоуровневой иерархией', 'admin.cat.new': 'Новая категория', 'admin.cat.subcategory': 'подкатегория', 'admin.cat.add_child': 'Добавить подкатегорию', 'admin.cat.inactive': 'Неактивна', 'admin.event.user_login': 'Вход', 'admin.event.user_register': 'Регистрация', 'admin.event.admin_user_deactivate': 'Блокировка юзера', 'admin.event.admin_user_activate': 'Разблокировка юзера', 'admin.event.admin_user_role_changed': 'Смена роли', 'admin.event.admin_task_cancelled': 'Отмена задачи', 'admin.event.admin_task_deleted': 'Удаление задачи', 'admin.event.admin_report_reviewed': 'Жалоба рассмотрена', 'admin.event.admin_report_dismissed': 'Жалоба отклонена', 'admin.event.task_created': 'Создана задача', // User status 'user.online': 'Онлайн', 'user.seen_minutes': 'был здесь {n} мин назад', 'user.seen_hours': 'был здесь {n} ч назад', 'user.seen_yesterday': 'был здесь вчера', 'user.seen_days': 'был здесь {n} дн назад', // Specialists 'specialists.title': 'Специалисты', 'specialists.search': 'Поиск специалиста...', 'specialists.search.btn': 'Поиск', 'specialists.empty': 'Специалисты не найдены', 'specialists.no_bio': 'Без описания', 'specialists.view': 'Смотреть профиль', 'specialists.reviews': 'отзывов', 'specialist.favorite': 'Добавить в избранное', 'specialist.unfavorite': 'Убрать из избранного', 'specialist.site_link': 'Личный сайт', 'favorites.specialists.title': 'Избранные специалисты', 'favorites.specialists.empty': 'Вы ещё не добавили специалистов в избранное', 'nav.favorites': 'Избранное', 'nav.schedule': 'Расписание', 'nav.find_tasks': 'Поиск заказов', 'schedule.title': 'Моё расписание', 'schedule.subtitle': 'Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность', 'schedule.available': 'Свободен', 'schedule.busy': 'Занят', 'schedule.unset': 'Не указано', 'schedule.click_hint': '← клик меняет статус по кругу', 'schedule.range_mode': 'Выделить диапазон', 'schedule.range_from': 'С {date} — выберите конечную дату', 'schedule.click_to_set': 'Нажмите чтобы отметить', 'schedule.free': 'свободно', 'schedule.busy_count': 'занято', 'schedule.free_days': 'свободных дней', 'schedule.googleCalendar': 'Google Календарь', 'schedule.connectGoogle': 'Подключить Google Календарь', 'schedule.disconnectGoogle': 'Отключить', 'schedule.connectedAs': 'Подключено как', 'schedule.importFromGoogle': 'Синхр. из Google', 'schedule.gcalConnected': '\u2713 Google Календарь подключён', 'schedule.gcalError': 'Ошибка подключения Google Календарь', 'schedule.gcalImportDone': 'Импортировано {n} дней из Google Календарь', 'schedule.gcalAutoSyncNote': 'Изменения доступности автоматически отправляются в Google Календарь', 'schedule.gcalConnectDesc': 'Подключите Google Календарь для автоматической синхронизации расписания', 'schedule.gcalDisconnectConfirm': 'Отключить Google Календарь?', 'find_tasks.title': 'Поиск заказов', 'find_tasks.for_me': 'Для меня', 'find_tasks.all': 'Все заказы', 'find_tasks.by_category': 'По категориям', 'find_tasks.list': 'Списком', 'find_tasks.already_offered': 'Предложение отправлено', 'find_tasks.offer_now': 'Откликнуться', 'find_tasks.empty_for_me': 'Нет заказов в ваших категориях', 'find_tasks.banner_hint': 'Найдите заказы по категориям вашего портфолио', 'find_tasks.no_cards': 'Создайте портфолио специалиста, чтобы видеть подходящие заказы', 'find_tasks.add_card': 'Создать портфолио', 'find_tasks.search': 'Поиск заказов...', 'find_tasks.tasks_count': 'заданий', 'footer.tagline': 'Платформа задач для Греции', 'footer.rights': 'Все права защищены.', // App download section 'app.download_title': 'Скачайте мобильное приложение CanHelp', 'app.download_desc': 'Всё CanHelp — всегда под рукой. Доступно для Android и iOS.', // Nav 'nav.pricing': 'Тарифы', // Pricing page 'pricing.title': 'Тарифы', 'pricing.subtitle': 'Выберите подходящий план', 'pricing.role.customer': 'Заказчик', 'pricing.role.specialist': 'Специалист', 'pricing.free': 'Бесплатно', 'pricing.per_month': 'мес', 'pricing.duration': 'Срок', 'pricing.days': 'дн.', 'pricing.current_plan': 'Ваш план', 'pricing.popular': 'Популярный', 'pricing.choose': 'Выбрать', 'pricing.your_plan': 'Активный план', 'pricing.free_default': 'По умолчанию', 'pricing.compare': 'Сравнение функций', 'pricing.feature': 'Функция', 'pricing.faq_note': 'Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.', 'pricing.feat.messages': 'Сообщений / день', 'pricing.feat.orders': 'Заказов / день', 'pricing.feat.contact_all': 'Связь со всеми', 'pricing.feat.view_phone': 'Просмотр телефона', 'pricing.feat.show_contact': 'Показывать контакты', 'pricing.feat.favorites': 'Избранное', 'pricing.feat.verified_badge': 'Верифицированный бейдж', 'pricing.feat.google_calendar': 'Google Календарь', 'pricing.feat.personal_site': 'Персональный сайт', 'pricing.feat.auto_response': 'Авто-ответ', 'pricing.feat.auto_match': 'Авто-подбор', 'pricing.feat.highlighted_reviews': 'Выделенные отзывы', 'pricing.feat.portfolio': 'Элементов портфолио', 'pricing.feat.cards': 'Карточки специалиста', 'pricing.feat.notify_tasks': 'Уведомления о новых задачах', 'pricing.feat.video': 'Видео в портфолио', // Upgrade prompt 'upgrade.available_in': 'Доступно в', 'upgrade.cta': 'Улучшить', // Dashboard plan block 'dashboard.plan.title': 'Мой план', 'dashboard.plan.expires': 'Истекает через {n} дней', 'dashboard.plan.upgrade': 'Улучшить план', 'dashboard.plan.no_plan': 'Бесплатный план', 'dashboard.plan.messages': 'Сообщений сегодня', 'dashboard.plan.orders': 'Заказов сегодня', 'dashboard.plan.limits': 'Дневные лимиты', 'dashboard.plan.features': 'Функции', 'dashboard.plan.stats': 'Статистика', 'dashboard.stats.cards': 'Портфолио', 'dashboard.stats.maxCards': 'Макс. портфолио', 'dashboard.stats.portfolioItems': 'Элементы портфолио', 'dashboard.stats.maxPortfolioItems': 'Макс. элементы', 'dashboard.stats.activeOffers': 'Активные отклики', 'dashboard.stats.reviewsReceived': 'Отзывы', 'dashboard.stats.activeTasks': 'Активные задачи', 'dashboard.stats.completedTasks': 'Завершённые', 'status.need_help': 'Нужна помощь', 'status.active': 'Активен', 'status.toggle_on': 'Включить', 'status.toggle_off': 'Выключить', // FOMO 'fomo.missed_orders': 'Пропущено {n} заказов', 'fomo.missed_value': 'На сумму €{v}', 'fomo.upgrade_hint': 'Улучшите план — получайте больше заказов', 'fomo.conversion': 'Конверсия задач', 'fomo.active': 'Активные', 'fomo.with_offers': 'С офертами', 'fomo.completed': 'Завершённые', 'fomo.already_offered': '{n} специалистов уже откликнулись', 'fomo.specialist_missed': 'Вы пропустили {n} заказов', 'fomo.top_categories': 'Категории', 'fomo.offers_received': 'предложений получено', 'fomo.avg_offers': 'В среднем {n}/задача', 'fomo.completion_rate': 'завершено', // Task auto-match 'task.auto_match': 'Авто-матч', 'task.auto_match_results': 'Топ специалисты', 'task.no_offer_yet': 'Вы ещё не отправили предложение', 'task.make_offer': 'Отправить предложение', 'auto_response.title': 'Авто-ответ', 'auto_response.enabled': 'Включить авто-ответ', 'auto_response.min_budget': 'Мин. бюджет', 'auto_response.max_budget': 'Макс. бюджет', 'auto_response.default_price': 'Цена по умолчанию', 'auto_response.default_message': 'Сообщение по умолчанию', 'auto_response.max_per_day': 'Макс. авто-офертов в день', 'auto_response.save': 'Сохранить', 'auto_response.saved': 'Сохранено', 'auto_response.categories': 'Категории', 'auto_response.locations': 'Локации', // Personal site 'profile.personal_site': 'Персональный сайт', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Только латинские буквы, цифры, - и _', 'profile.site_open': 'Открыть сайт', 'profile.site_preview': 'Ваш сайт', 'profile.show_contact': 'Показывать контакты', 'profile.show_contact_hint': 'Заказчики с Pro/Ultimate-планом увидят ваш телефон', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Календарь требует план Pro или Ultimate', // Chat limits 'chat.limit_warning': 'Осталось {n} сообщений сегодня', 'chat.limit_reached': 'Лимит сообщений исчерпан. Улучшите план', 'chat.upgrade': 'Улучшить', // Site page 'site.member_since': 'С нами с', 'site.rating': 'Рейтинг', 'site.completed_tasks': 'Выполнено', 'site.languages': 'Языков', 'site.photos': 'фото', 'site.contact_form': 'Связаться', 'site.contact_sent': 'Сообщение отправлено!', 'site.contact_sent_desc': 'Специалист свяжется с вами в ближайшее время', 'site.contact_name': 'Имя', 'site.contact_name_ph': 'Ваше имя', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Сообщение', 'site.contact_message_ph': 'Опишите вашу задачу...', 'site.contact_send': 'Отправить', 'site.share': 'Поделиться', 'site.speaks_languages': 'Говорит на языках', 'site.message_sent': 'Сообщение отправлено!', 'site.message_sent_desc': 'Специалист получит его в чате', 'site.message_placeholder': 'Напишите сообщение...', 'site.write_to_chat': 'Написать в чат', 'site.auth_required_title': 'Нужна авторизация', 'site.auth_required_desc': 'Чтобы написать в чат, необходимо войти в аккаунт CanHelp.', 'site.auth_login_btn': 'Войти в аккаунт', 'site.auth_contact_form_btn': 'Написать через форму обратной связи', 'specialist.services': 'Услуги', 'portfolio.title': 'Портфолио', 'status.can_help_now': 'Готов помочь', 'common.not_found': 'Страница не найдена', 'common.anonymous': 'Анонимно', 'specialist_setup.page_title': 'Настройка профиля специалиста', 'specialist_setup.step_of': 'Шаг {current} из {total}', 'specialist_setup.next': 'Далее', 'specialist_setup.back': 'Назад', 'specialist_setup.skip': 'Пропустить', 'specialist_setup.finish': 'Завершить', 'specialist_setup.go_to_profile': 'Перейти в профиль', 'specialist_setup.browse_tasks': 'Найти задачи', 'specialist_setup.step1.title': 'Добро пожаловать!', 'specialist_setup.step1.subtitle': 'Давайте настроим ваш профиль', 'specialist_setup.step1.desc': 'Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.', 'specialist_setup.step1.what_next': 'Что мы сделаем:', 'specialist_setup.step1.item1': 'Заполним основную информацию', 'specialist_setup.step1.item2': 'Создадим карточку услуги', 'specialist_setup.step1.item3': 'Добавим навыки и категории', 'specialist_setup.step1.item4': 'Выберем географию обслуживания', 'specialist_setup.step1.item5': 'Загрузим фото портфолио', 'specialist_setup.step2.title': 'Базовый профиль', 'specialist_setup.step2.subtitle': 'Расскажите о себе', 'specialist_setup.step2.bio_label': 'О себе', 'specialist_setup.step2.bio_placeholder': 'Опишите ваш опыт, услуги которые вы предлагаете...', 'specialist_setup.step2.phone_label': 'Телефон', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Фото профиля', 'specialist_setup.step2.photo_btn': 'Загрузить фото', 'specialist_setup.step2.photo_uploading': 'Загрузка...', 'specialist_setup.step2.photo_hint': 'Отображается в вашем профиле', 'specialist_setup.step3.title': 'Карточка услуги', 'specialist_setup.step3.subtitle': 'Создайте вашу первую карточку услуги', 'specialist_setup.step3.title_label': 'Название карточки', 'specialist_setup.step3.title_placeholder': 'Напр. Сантехник, Электрик, Уборка...', 'specialist_setup.step3.desc_label': 'Описание', 'specialist_setup.step3.desc_placeholder': 'Подробно опишите что вы предлагаете, опыт, преимущества...', 'specialist_setup.step3.title_required': 'Название обязательно', 'specialist_setup.step4.title': 'Навыки и категории', 'specialist_setup.step4.subtitle': 'Добавьте навыки и выберите категории', 'specialist_setup.step4.skills_label': 'Навыки', 'specialist_setup.step4.skills_placeholder': 'Напр. Монтаж труб...', 'specialist_setup.step4.skills_add': 'Добавить', 'specialist_setup.step4.categories_label': 'Категории', 'specialist_setup.step5.title': 'География обслуживания', 'specialist_setup.step5.subtitle': 'Где вы оказываете услуги?', 'specialist_setup.step5.hint': 'Выберите города или конкретные районы', 'specialist_setup.done.title': 'Ваш профиль готов!', 'specialist_setup.done.subtitle': 'Поздравляем! Профиль настроен', 'specialist_setup.done.desc': 'Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам.' } }; export function getTranslations(locale) { const t = translations[locale] ?? translations.el; return (key, fallback)=>t[key] ?? translations.el[key] ?? fallback ?? key; } C sybuffersourcesizemapshasho/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ getTranslations), /* harmony export */ YZ: () => (/* binding */ LOCALES) /* harmony export */ }); /* unused harmony export translations */ const LOCALES = [ { code: 'el', label: 'Ελληνικά', flag: '🇬🇷' }, { code: 'en', label: 'English', flag: '🇬🇧' }, { code: 'ru', label: 'Русский', flag: '🇷🇺' } ]; const translations = { el: { 'footer.slogan': 'Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.', 'footer.links': 'Σύνδεσμοι', 'footer.socials': 'Στα κοινωνικά δίκτυα', // Nav 'nav.home': 'Αρχική', 'nav.tasks': 'Εργασίες', 'nav.post': '+ Δημοσίευση', 'nav.dashboard': 'Πίνακας', 'nav.chat': 'Μηνύματα', 'nav.notifications': 'Ειδοποιήσεις', 'nav.profile': 'Προφίλ', 'nav.admin': 'Διαχείριση', 'nav.specialists': 'Ειδικοί', 'nav.new_task': 'Νέα εργασία', 'nav.login': 'Σύνδεση', 'nav.register': 'Εγγραφή', 'nav.logout': 'Έξοδος', // Hero 'hero.title': 'Βρες ειδικό για κάθε δουλειά', 'hero.subtitle': 'Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία', 'hero.cta.post': 'Δημοσίευσε εργασία', 'hero.cta.browse': 'Γίνε ειδικός', 'hero.search.placeholder': 'Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...', 'stats.specialists': 'ειδικοί', 'stats.tasks': 'εργασίες', 'stats.categories': 'κατηγορίες', 'stats.free': 'δωρεάν εγγραφή', // Sections 'section.categories': 'Δημιούργησε εργασία σε οποιαδήποτε κατηγορία', 'section.how': 'Πώς λειτουργεί', 'section.recent': 'Πρόσφατες εργασίες', 'section.all': 'Δες όλες →', 'section.more': 'ακόμα', 'section.cities': 'Πόλεις & Περιοχές', 'section.community': 'Ένα κοινοτικό έργο για όλους', 'community.subtitle': 'Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.', 'community.point1.title': 'Είσαι ειδικός σε κάτι;', 'community.point1.desc': 'Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.', 'community.point2.title': 'Χρειάζεσαι βοήθεια;', 'community.point2.desc': 'Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.', 'community.point3.title': 'Βοήθησε το έργο να αναπτυχθεί', 'community.point3.desc': 'Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.', 'community.share': 'Μοιράσου με φίλους', 'community.share.copied': 'Σύνδεσμος αντιγράφηκε!', // Referral section on home page 'section.referral': 'Πρόγραμμα παραπομπών', 'referral.home.subtitle': 'Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.', 'referral.home.step1.title': 'Εγγραφείσε και λάβε σύνδεσμο', 'referral.home.step1.desc': 'Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.', 'referral.home.step2.title': 'Μοιράσου με φίλους', 'referral.home.step2.desc': 'Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.', 'referral.home.step3.title': 'Κέρδισε ανταμοιβές', 'referral.home.step3.desc': 'Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.', 'referral.home.cta': 'Πάρε τον σύνδεσμό σου', 'referral.home.badge': 'Πρόγραμμα παραπομπών', // FAQ section 'section.faq': 'Συχνές Ερωτήσεις', 'faq.q1': 'Πώς λειτουργεί το CanHelp;', 'faq.a1': 'Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.', 'faq.q2': 'Πόσο κοστίζει η χρήση της πλατφόρμας;', 'faq.a2': 'Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.', 'faq.q3': 'Πώς μπορώ να γίνω ειδικός;', 'faq.a3': 'Κάνε εγγραφή, πήγαινε στο «Γίνε Ειδικός», συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.', 'faq.q4': 'Πώς επιλέγω τον κατάλληλο ειδικό;', 'faq.a4': 'Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q5': 'Τι γίνεται αν δεν είμαι ικανοποιημένος;', 'faq.a5': 'Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.', 'faq.q6': 'Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;', 'faq.a6': 'Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q7': 'Πόσος χρόνος χρειάζεται για να λάβω προσφορές;', 'faq.a7': 'Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.', 'faq.q8': 'Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;', 'faq.a8': 'Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.', 'faq.q9': 'Τι είδη εργασιών μπορώ να βρω στο CanHelp;', 'faq.a9': 'Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.', 'faq.q10': 'Υπάρχει εφαρμογή για κινητό;', 'faq.a10': 'Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.', // How it works 'how.step1.title': 'Δημοσίευσε εργασία', 'how.step1.desc': 'Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου', 'how.step2.title': 'Λάβε προσφορές', 'how.step2.desc': 'Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο', 'how.step3.title': 'Επίλεξε & ξεκίνα', 'how.step3.desc': 'Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία', // Tasks page 'tasks.title': 'εργασίες', 'tasks.filters': 'Φίλτρα', 'tasks.search': 'Αναζήτηση', 'tasks.search.placeholder': 'Τίτλος ή λέξη κλειδί...', 'tasks.search.btn': 'Αναζήτηση', 'tasks.publish': 'Δημοσίευση', 'tasks.category.all': 'Όλες', 'tasks.category.all_in': 'Όλα στην', 'tasks.category.label': 'Κατηγορία', 'tasks.location.label': 'Πόλη', 'tasks.location.placeholder': 'π.χ. Αθήνα', 'tasks.empty': 'Δεν βρέθηκαν εργασίες', 'tasks.empty.cta': 'Δημοσίευσε την πρώτη', // Task detail 'task.status.open': 'Ανοιχτή', 'task.status.in_progress': 'Σε εξέλιξη', 'task.status.completed': 'Ολοκληρωμένη', 'task.status.cancelled': 'Ακυρωμένη', 'task.status.draft': 'Πρόχειρο', 'task.budget': 'Προϋπολογισμός', 'task.location': 'Τοποθεσία', 'task.deadline': 'Ημερομηνία έναρξης', 'task.created_at': 'Δημιουργήθηκε', 'task.customer': 'Πελάτης', 'task.offer.btn': 'Υποβολή προσφοράς', 'task.invite.banner_title': 'Σας προσκαλούν σε αυτήν την εργασία', 'task.invite.banner_hint': 'Ο πελάτης σας πρόσκαλεσε προσωπικά', 'task.invite.accept': 'Αποστολή προσφοράς', 'task.invite.decline': 'Άρνηση', 'offer.accept': 'Αποδοχή', 'offer.decline': 'Απόρριψη', 'task.complete': 'Ολοκλήρωση εργασίας', 'task.complete.confirm': 'Να ολοκληρωθεί η εργασία;', 'task.edit': 'Επεξεργασία', 'task.status_label': 'Κατάσταση', 'task.yours': 'Η εργασία σου', 'task.offer.yours': 'Η προσφορά σου', 'review.leave': 'Άφησε αξιολόγηση', 'review.rating': 'Βαθμολογία', 'review.comment': 'Σχόλιο', 'review.comment.placeholder': 'Πες μας για την εμπειρία σου...', 'review.submit': 'Υποβολή αξιολόγησης', 'review.submitting': 'Αποστολή...', 'review.done': 'Η αξιολόγηση καταχωρήθηκε!', 'profile.reviews': 'Αξιολογήσεις', 'profile.no_reviews': 'Δεν υπάρχουν αξιολογήσεις ακόμα', 'profile.rating': 'Βαθμολογία', 'profile.skills.label': 'Δεξιότητες', 'profile.member_since': 'Μέλος από', 'task.offers': 'Προσφορές', 'task.offers.none': 'Δεν υπάρχουν ακόμα προσφορές', // Create task 'create.title': 'Δημοσίευση εργασίας', 'create.field.title': 'Τίτλος', 'create.field.description': 'Περιγραφή', 'create.field.category': 'Κατηγορία', 'create.field.category.select': 'Επιλέξτε...', 'create.field.location': 'Τοποθεσία', 'create.field.location.any': 'Οπουδήποτε', 'create.field.location.all': 'Ολόκληρη η πόλη', 'create.field.budget': 'Προϋπολογισμός (€)', 'create.field.deadline': 'Ημερομηνία έναρξης', 'create.field.budget_negotiable': 'Η τιμή είναι διαπραγματεύσιμη', 'create.field.time_slot': 'Χρόνος εκτέλεσης', 'create.field.time_slot.any': 'Οποιαδήποτε', 'create.field.time_slot.morning': 'Πρωινό (08:00–13:00)', 'create.field.time_slot.afternoon': 'Μεσημέρι (13:00–18:00)', 'create.field.time_slot.evening': 'Βράδυ (18:00–22:00)', 'create.field.time_slot.weekend': 'Σαββατοκύριακο', 'create.field.address': 'Διεύθυνση (προαιρετικά)', 'create.field.address.district': 'Συνοικία', 'create.field.address.street': 'Οδός', 'create.field.address.house': 'Αριθμός', 'create.field.confidential': 'Εμπιστευτική σημείωση', 'create.field.confidential.placeholder': 'Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...', 'create.field.confidential.hint': 'Δεν εμφανίζεται δημόσια', 'create.field.photos': 'Φωτογραφίες', 'create.field.photos.add': 'Προσθήκη φωτογραφίας', 'create.field.photos.uploading': 'Ανέβασμα...', 'task.budget_negotiable': 'Τιμή διαπραγματεύσιμη', 'task.time_slot': 'Χρόνος', 'task.confidential': 'Εμπιστευτική σημείωση', 'create.field.title.placeholder': 'π.χ. Καθαρισμός διαμερίσματος 80τμ', 'create.field.description.placeholder': 'Περίγραψε λεπτομερώς τι χρειάζεσαι...', 'create.field.location.placeholder': 'π.χ. Αθήνα, Κολωνάκι', 'create.field.budget.placeholder': 'π.χ. 100', 'create.submit': 'Δημοσίευση εργασίας', 'create.submitting': 'Δημοσίευση...', // Auth 'login.title': 'Καλωσόρισες', 'login.subtitle': 'Σύνδεση στο CanHelp', 'login.email': 'Email', 'login.password': 'Κωδικός', 'login.submit': 'Σύνδεση', 'login.submitting': 'Σύνδεση...', 'login.error': 'Λάθος email ή κωδικός', 'login.unverified.title': 'Επιβεβαιώστε το email σας', 'login.unverified.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.', 'login.unverified.resend': 'Αποστολή νέου email επαλήθευσης', 'login.unverified.sending': 'Αποστολή...', 'login.unverified.sent': '✓ Εστάλη — ελέγξτε τα εισερχόμενα', 'profile.email.verified': 'Email επαληθεύτηκε', 'profile.email.not_verified': 'Email δεν επαληθεύτηκε', 'login.no_account': 'Δεν έχεις λογαριασμό;', 'login.register_link': 'Εγγραφή', 'login.forgot_password': 'Ξέχασα τον κωδικό', 'login.or_continue_with': 'ή συνεχίστε με', 'login.continue_google': 'Σύνδεση με Google', 'forgot.title': 'Ξέχασα τον κωδικό', 'forgot.subtitle': 'Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης', 'forgot.email': 'Email', 'forgot.submit': 'Αποστολή', 'forgot.submitting': 'Αποστολή...', 'forgot.sent.title': 'Ελέγξτε τα εισερχόμενά σας', 'forgot.sent.desc': 'Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.', 'forgot.back_to_login': 'Επιστροφή στη σύνδεση', 'forgot.error': 'Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.', 'forgot.error.not_found': 'Δεν βρέθηκε λογαριασμός με αυτό το email.', 'forgot.error.send_failed': 'Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα', 'reset.title': 'Νέος κωδικός', 'reset.subtitle': 'Εισάγετε τον νέο σας κωδικό', 'reset.password': 'Νέος κωδικός', 'reset.confirm': 'Επιβεβαίωση κωδικού', 'reset.submit': 'Αλλαγή κωδικού', 'reset.submitting': 'Αποθήκευση...', 'reset.success': 'Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...', 'reset.back_to_login': 'Επιστροφή στη σύνδεση', 'reset.error.mismatch': 'Οι κωδικοί δεν ταιριάζουν', 'reset.error.invalid': 'Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.', 'register.title': 'Εγγραφή', 'register.subtitle': 'Δημιουργία λογαριασμού στο CanHelp', 'register.first_name': 'Όνομα', 'register.last_name': 'Επώνυμο', 'register.email': 'Email', 'register.password': 'Κωδικός (min 8 χαρακτήρες)', 'register.role': 'Ρόλος', 'register.role.customer': 'Χρήστης', 'register.role.customer.desc': 'Δημοσιεύω εργασίες', 'register.role.specialist': 'Ειδικός', 'register.role.specialist.desc': 'Αναλαμβάνω εργασίες', 'register.submit': 'Δημιουργία λογαριασμού', 'register.submitting': 'Εγγραφή...', 'register.has_account': 'Έχεις ήδη λογαριασμό;', 'register.login_link': 'Σύνδεση', 'register.continue_google': 'Εγγραφή με Google', 'register.check_email.title': 'Ελέγξτε το email σας', 'register.check_email.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.', 'register.check_email.login': 'Επιστροφή στη σύνδεση', // Dashboard 'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.new_task': '+ Νέα εργασία', 'dashboard.my_tasks': 'Οι εργασίες μου', 'dashboard.my_offers': 'Οι προσφορές μου', 'dashboard.invitations': 'Προσκλήσεις για εργασία', 'dashboard.offers_count': 'προσφορές', 'dashboard.declined_count': 'απορρίφθηκαν', 'dashboard.completed_tasks': 'Ολοκληρωμένες εργασίες', 'dashboard.completed_offers': 'Ολοκληρωμένες προσφορές', 'dashboard.review_pending': 'Η αξιολόγηση δεν έχει υποβληθεί ακόμα', 'tasks.new.top_specialists': 'Κορυφαίοι ειδικοί', 'tasks.new.select_category': 'Επιλέξτε κατηγορία για να δείτε ειδικούς', 'tasks.new.invite': 'Πρόσκληση', 'tasks.new.invited': 'Επιλέχθηκε ✓', 'reviews.count': 'αξιολογήσεις', 'filter.location': 'Τοποθεσία', 'filter.language': 'Γλώσσες', 'filter.language.any': 'Οποιαδήποτε γλώσσα', 'filter.category.all': 'Όλες οι κατηγορίες', 'user.categories': 'Κατηγορίες', 'user.work_area': 'Περιοχή εργασίας', 'dashboard.tasks.empty': 'Δεν έχεις δημοσιεύσει εργασίες', 'dashboard.tasks.empty.cta': 'Δημοσίευσε την πρώτη σου', 'dashboard.tasks.add_new': 'Πρόσθεσε νέα εργασία', 'dashboard.offers.empty': 'Δεν έχεις υποβάλλει προσφορές', 'dashboard.offers.empty.cta': 'Βρες εργασίες', 'dashboard.customer.specialists_title': 'Ψάχνεις εκτελεστή;', 'dashboard.customer.specialists_hint': 'Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου', 'dashboard.customer.specialists_cta': 'Βρες ειδικό', 'dashboard.customer.how_title': 'Πώς λειτουργεί', 'dashboard.customer.step1': 'Δημιούργησε εργασία με περιγραφή και προϋπολογισμό', 'dashboard.customer.step2': 'Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο', 'dashboard.customer.step3': 'Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία', // Notifications 'notif.title': 'Ειδοποιήσεις', 'notif.mark_all': 'Σήμανση όλων ως αναγνωσμένα', 'notif.empty': 'Δεν υπάρχουν ειδοποιήσεις', 'notif.type.new_offer': 'Νέα προσφορά', 'notif.type.offer_accepted': 'Η προσφορά σας έγινε δεκτή', 'notif.type.offer_declined': 'Η προσφορά σας απορρίφθηκε', 'notif.type.task_completed': 'Η εργασία ολοκληρώθηκε', 'notif.type.task_cancelled': 'Η εργασία ακυρώθηκε', 'notif.type.new_message': 'Νέο μήνυμα', 'notif.type.new_review': 'Νέα αξιολόγηση', 'notif.type.task_invite': 'Πρόσκληση σε εργασία', 'notif.body.new_offer': 'Νέα προσφορά για «{title}»', 'notif.body.offer_accepted': 'Η προσφορά σας για «{title}» έγινε δεκτή', 'notif.body.offer_declined': 'Η προσφορά σας για «{title}» απορρίφθηκε', 'notif.body.task_invite': 'Σας προσκαλούν για «{title}»', 'notif.body.new_review': 'Λάβατε αξιολόγηση {rating}★', // Offer status 'offer.status.pending': 'Εκκρεμεί', 'offer.status.accepted': 'Αποδεκτή', 'offer.status.declined': 'Απορρίφθηκε', 'offer.status.withdrawn': 'Αποσύρθηκε', 'offer.status.other_accepted': 'Επιλέχθηκε άλλος ειδικός', // Common 'common.loading': 'Φόρτωση...', 'common.error': 'Σφάλμα', 'common.save': 'Αποθήκευση', 'common.saving': 'Αποθήκευση...', 'common.cancel': 'Ακύρωση', 'common.add': 'Προσθήκη', 'common.close': 'Κλείσιμο', 'common.edit': 'Επεξεργασία', 'common.delete': 'Διαγραφή', 'common.from': 'από', 'common.currency': '€', 'common.greece': 'Ελλάδα', // Chat 'chat.connected': 'Συνδεδεμένος', 'chat.disconnected': 'Αποσυνδεδεμένος', 'chat.no_rooms': 'Δεν υπάρχουν συνομιλίες ακόμα', 'chat.task_fallback': 'Εργασία', 'chat.select': 'Επίλεξε συνομιλία', 'chat.no_messages': 'Δεν υπάρχουν μηνύματα', 'chat.placeholder': 'Γράψε μήνυμα... (Enter για αποστολή)', 'chat.conversation_fallback': 'Συνομιλία', 'chat.direct_chat': 'Απευθείας συνομιλία', 'chat.linked_task': 'Συνδεδεμένη εργασία', 'chat.write_btn': 'Μήνυμα', 'chat.just_now': 'μόλις τώρα', 'chat.min_ago': 'λ', 'chat.write_specialist': 'Γράψε στον ειδικό', 'chat.write_customer': 'Γράψε στον πελάτη', 'chat.notif_settings': 'Ρυθμίσεις ειδοποιήσεων', 'chat.notif_messages': 'Ειδοποιήσεις για νέα μηνύματα', 'chat.toast_title': 'Νέο μήνυμα', 'chat.toast_open': 'Άνοιγμα συνομιλίας', // Offer form 'offer.price': 'Τιμή', 'offer.price.placeholder': 'π.χ. 80', 'offer.customer_budget': 'Προϋπολογισμός πελάτη', 'offer.message': 'Μήνυμα', 'offer.optional': 'προαιρετικό', 'offer.message.placeholder': 'Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...', 'offer.submitting': 'Αποστολή...', // Profile 'profile.photo': 'Φωτογραφία προφίλ', 'profile.photo.change': 'Αλλαγή φωτογραφίας', 'profile.photo.hint': 'JPEG, PNG, WebP · έως 5MB', 'profile.basic_info': 'Βασικά στοιχεία', 'profile.phone': 'Τηλέφωνο', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Σύντομη περιγραφή', 'profile.bio.placeholder': 'Πες μας λίγα λόγια για εσένα...', 'profile.language': 'Γλώσσα', 'profile.language.hint': 'Γλώσσα διεπαφής και email ειδοποιήσεων', 'profile.languages': 'Γλώσσες επικοινωνίας', 'profile.languages.hint': 'Επιλέξτε όλες τις γλώσσες που μιλάτε', 'profile.skills': 'Δεξιότητες', 'profile.skills.subtitle': 'Προσθέσε τις υπηρεσίες που προσφέρεις', 'profile.skills.placeholder': 'π.χ. Καθαρισμός, IT, Μαθήματα...', 'profile.role': 'Ρόλος λογαριασμού', 'profile.role.specialist': '🔧 Ειδικός', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Χρήστης', 'profile.role.change': 'Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.', 'profile.become_specialist': 'Γίνε Ειδικός', 'profile.become_specialist.desc': 'Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.', 'become_specialist.hero.title': 'Κέρδισε χρήματα κάνοντας αυτό που ξέρεις', 'become_specialist.hero.subtitle': 'Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα', 'become_specialist.how.title': 'Πώς λειτουργεί', 'become_specialist.step1.title': 'Δημιούργησε κάρτα ειδικού', 'become_specialist.step1.desc': 'Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα', 'become_specialist.step2.title': 'Βρες εργασίες', 'become_specialist.step2.desc': 'Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα «Αναζήτηση εργασιών»', 'become_specialist.step3.title': 'Στείλε προσφορά & κέρδισε', 'become_specialist.step3.desc': 'Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες', 'become_specialist.benefits.title': 'Πλεονεκτήματα προφίλ ειδικού', 'become_specialist.benefit1': 'Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία', 'become_specialist.benefit2': 'Δημόσιο προφίλ με αξιολογήσεις πελατών', 'become_specialist.benefit3': 'Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες', 'become_specialist.benefit4': 'Προσθήκη σε αγαπημένα από πελάτες', 'become_specialist.cta': 'Περισσότερα', 'become_specialist.free_badge': 'Δωρεάν εγγραφή', 'profile.tab.notifications': 'Ειδοποιήσεις', 'profile.tab.reviews': 'Αξιολογήσεις', 'profile.tab.referral': 'Παραπομπές', 'profile.tab.auto_response': 'Αυτόματη απάντηση', 'profile.tab.site': 'Site', 'profile.site.title': 'Προσωπική σελίδα', 'profile.site.url_label': 'Προσωπικό site', 'profile.site.copy': 'Αντιγραφή', 'profile.site.copied': 'Αντιγράφηκε', 'profile.site.visible_title': 'Τι εμφανίζεται στη σελίδα σας', 'profile.site.visible.name': 'Όνομα και φωτογραφία', 'profile.site.visible.bio': 'Βιογραφικό', 'profile.site.visible.rating': 'Αξιολόγηση και κριτικές', 'profile.site.visible.portfolio': 'Χαρτοφυλάκιο / Κάρτες', 'profile.site.visible.contacts': 'Στοιχεία επικοινωνίας', 'profile.site.visible.full_last_name': 'Πλήρες επώνυμο', 'profile.site.visible.services': 'Κάρτες υπηρεσιών', 'profile.site.visible.reviews': 'Ενότητα κριτικών', 'profile.site.visible.status': 'Κατάσταση «Έτοιμος να βοηθήσω»', 'profile.site.theme': 'Θέμα εμφάνισης', 'profile.site.theme.dark': 'Σκοτεινό', 'profile.site.theme.light': 'Φωτεινό', 'profile.site.slug_taken': 'Αυτή η διεύθυνση είναι ήδη κατειλημμένη', 'profile.site.stats.title': 'Στατιστικά επισκεψιμότητας', 'profile.site.stats.days': 'τελευταίες 30 ημέρες', 'profile.site.stats.views': 'Προβολές', 'profile.site.stats.unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.messages': 'Μηνύματα', 'profile.site.stats.total_views': 'Συνολικές προβολές', 'profile.site.stats.total_unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.total_messages': 'Μηνύματα', 'profile.site.stats.empty': 'Δεν υπάρχουν δεδομένα ακόμη', 'profile.site.stats.loading': 'Φόρτωση στατιστικών...', 'profile.site.stats.no_slug': 'Ορίστε τη διεύθυνση του site για να δείτε στατιστικά', 'profile.site.edit_bio_hint': 'Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα «Βασικά».', 'status.can_help_now_hint': 'Η κάρτα σου εμφανίζεται ψηλότερα', 'status.need_help_hint': 'Οι ειδικοί μπορούν να σε βοηθήσουν', 'profile.referral.title': 'Πρόγραμμα παραπομπών', 'profile.referral.desc': 'Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.', 'profile.referral.link_label': 'Ο σύνδεσμος παραπομπής σου', 'profile.referral.copy': 'Αντιγραφή', 'profile.referral.copied': 'Αντιγράφηκε!', 'profile.referral.invited_count': 'επιτυχείς παραπομπές', 'profile.referral.no_code': 'Ο κωδικός παραπομπής δεν είναι διαθέσιμος.', 'notifications.title': 'Ρυθμίσεις ειδοποιήσεων', 'notifications.email.new_tasks': 'Email για νέες εργασίες', 'notifications.email.new_tasks.desc': 'Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου', 'notifications.messages.desc': 'Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα', 'notifications.saved': 'Ρυθμίσεις αποθηκεύτηκαν', 'notifications.plan_required': 'Συνδρομή απαιτείται για αυτή τη λειτουργία', 'profile.tab.info': 'Βασικά στοιχεία', 'profile.tab.finance': 'Οικονομικά', 'profile.tab.skills': 'Δεξιότητες', 'profile.tab.categories': 'Κατηγορίες', 'profile.tab.geography': 'Γεωγραφία', 'profile.specialist.categories': 'Κατηγορίες εργασιών', 'profile.specialist.categories.desc': 'Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι', 'profile.specialist.geography': 'Περιοχές κάλυψης', 'profile.specialist.geography.desc': 'Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι', 'profile.saving': 'Αποθήκευση...', 'profile.upload.error': 'Σφάλμα κατά την αναφόρτωση', 'profile.saved': 'Αποθηκεύτηκε', 'profile.tab.cards': 'Χαρτοφυλάκιο', 'profile.cards.count': 'Χαρτοφυλάκια', 'profile.cards.add': 'Νέο χαρτοφυλάκιο', 'profile.cards.new_title': 'Τίτλος νέου χαρτοφυλακίου', 'profile.cards.placeholder': 'π.χ. Υδραυλικά', 'profile.cards.create': 'Δημιουργία', 'profile.cards.cancel': 'Ακύρωση', 'profile.cards.empty': 'Δεν έχετε χαρτοφυλάκιο', 'profile.cards.create_first': 'Δημιουργήστε το πρώτο σας χαρτοφυλάκιο', 'profile.cards.delete_confirm': 'Διαγραφή χαρτοφυλακίου;', 'profile.card.tab.main': 'Γενικά', 'profile.card.tab.skills': 'Δεξιότητες', 'profile.card.tab.categories': 'Κατηγορίες', 'profile.card.tab.geography': 'Γεωγραφία', 'profile.card.tab.portfolio': 'Γκαλερί', 'profile.card.active': 'Ενεργή', 'profile.card.save': 'Αποθήκευση', 'profile.card.saved': 'Αποθηκεύτηκε', 'profile.card.delete': 'Διαγραφή', 'profile.card.skill.add': 'Προσθήκη δεξιότητας', 'profile.card.photo.add': 'Προσθήκη φωτογραφίας', 'profile.card.photo.uploading': 'Μεταφόρτωση...', 'profile.card.photo.empty': 'Δεν υπάρχουν φωτογραφίες', 'profile.card.item.title': 'Τίτλος', 'profile.card.item.desc': 'Περιγραφή', 'profile.card.item.save': 'Αποθήκευση', 'profile.card.item.cancel': 'Ακύρωση', 'profile.card.item.edit': 'Επεξεργασία', 'profile.upgrade.cards_limit': 'Όριο χαρτοφυλακίων εξαντλήθηκε', 'profile.upgrade.plan': 'Τρέχον πλάνο:', 'profile.upgrade.contact': 'Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου', 'profile.upgrade.ok': 'Εντάξει', 'profile.plan.title': 'Πλάνο συνδρομής', 'profile.balance': 'Υπόλοιπο', 'profile.balance.topup': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.amount': 'Ποσό (σε EUR)', 'profile.balance.topup.hint': 'Επιλέξτε ποσό ή εισαγάγετε μανούαλα', 'profile.balance.topup.submit': 'Πληρωμή', 'profile.balance.topup.loading': 'Ρεδιρεκτάρισμα...', 'profile.balance.topup.error': 'Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.', 'payment.success.title': 'Πληρωμή επιτυχής!', 'payment.success.desc': 'Το υπόλοιπό σας ενημερώθηκε.', 'payment.cancelled.title': 'Ακύρωση πληρωμής', 'payment.cancelled.desc': 'Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.', 'payment.pending.title': 'Σε εξέλιξη...', 'payment.pending.desc': 'Επεξεργαζόμαστε την πληρωμή σας.', 'payment.back_to_profile': 'Επιστροφή στο προφίλ', 'profile.plan.basic': 'Βασικό (δωρεάν)', 'profile.plan.contact_upgrade': 'Επικοινωνήστε με τον διαχειριστή για αναβάθμιση', 'profile.plan.cards_up_to': 'Χαρτοφυλάκια: έως', 'profile.plan.cards_unlimited': 'Χαρτοφυλάκια: απεριόριστα', 'profile.plan.tasks_up_to': 'Εργασίες: έως', 'profile.plan.offers_up_to': 'Προσφορές: έως', 'profile.plan.valid_until': 'Ισχύει έως', 'profile.plan.no_expiry': 'Δεν λήγει', // Create task 'create.error': 'Σφάλμα κατά τη δημοσίευση', // Tasks list extras 'tasks.category.general': 'Γενικά', 'tasks.budget.range': 'Εύρος:', 'tasks.budget.from': 'από', 'tasks.budget.to': 'έως', 'tasks.filter.reset': 'Εκκαθάριση φίλτρων', 'tasks.load_more': 'Φόρτωση ακόμα', 'tasks.showing': 'Αποτελέσματα:', 'tasks.field.budget': 'Προϋπολογισμός, €', // Admin 'admin.title': 'Πίνακας Διαχείρισης', 'admin.tab.stats': 'Στατιστικά', 'admin.tab.users': 'Χρήστες', 'admin.tab.tasks': 'Εργασίες', 'admin.tab.reports': 'Αναφορές', 'admin.stats.users': 'Χρήστες', 'admin.stats.tasks': 'Εργασίες', 'admin.stats.offers': 'Προσφορές', 'admin.stats.reviews': 'Αξιολογήσεις', 'admin.tasks.by_status': 'Εργασίες ανά κατάσταση', 'admin.col.user': 'Χρήστης', 'admin.col.email': 'Email', 'admin.col.role': 'Ρόλος', 'admin.col.registered': 'Εγγραφή', 'admin.col.status': 'Κατάσταση', 'admin.col.title': 'Τίτλος', 'admin.col.budget': 'Προϋπολογισμός', 'admin.col.created': 'Δημιουργία', 'admin.users.active': 'Ενεργός', 'admin.users.inactive': 'Ανενεργός', 'admin.users.deactivate': 'Απενεργοποίηση', 'admin.users.activate': 'Ενεργοποίηση', 'admin.tasks.cancel': 'Ακύρωση', 'admin.reports.none': 'Δεν υπάρχουν αναφορές', 'admin.reports.reviewed': 'Αναθεωρήθηκε', 'admin.reports.dismiss': 'Απόρριψη', 'admin.pagination.total': 'Σύνολο', 'admin.users.role.change': 'Αλλαγή ρόλου', 'admin.users.search.placeholder': 'Αναζήτηση ονόματος ή email...', 'admin.tasks.delete': 'Διαγραφή', 'admin.tasks.delete.confirm': 'Διαγραφή αυτής της εργασίας μόνιμα;', 'admin.tasks.search.placeholder': 'Αναζήτηση τίτλου...', 'admin.col.customer': 'Πελάτης', 'admin.col.reporter': 'Καταγγέλλων', 'admin.col.target': 'Στόχος', 'admin.filter.all_roles': 'Όλοι οι ρόλοι', 'admin.filter.all_statuses': 'Όλες οι καταστάσεις', 'admin.reports.target.task': 'Εργασία', 'admin.reports.target.user': 'Χρήστης', 'admin.tab.categories': 'Κατηγορίες', 'admin.tab.locations': 'Πόλεις & Περιοχές', 'admin.tab.logs': 'Αρχεία', 'admin.tab.plans': 'Πακέτα', 'admin.tab.settings': 'Ρυθμίσεις', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Δραστηριότητα', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Ειδοποιήσεις', 'admin.notif_logs.type': 'Τύπος', 'admin.notif_logs.title': 'Τίτλος', 'admin.notif_logs.read': 'Διαβασμένο', 'admin.notif_logs.empty': 'Δεν υπάρχουν αρχεία ειδοποιήσεων', 'admin.stats.notif_chart_title': 'Ειδοποιήσεις ανά ημέρα', 'admin.stats.notif_label': 'Ειδοποιήσεις', 'admin.stats.mail_chart_title': 'Emails ανά ημέρα', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Όλα', 'admin.stats.specialists': 'Ειδικοί', 'admin.col.plan': 'Πακέτο', 'admin.back_home': 'Αρχική', 'admin.plans.title': 'Πακέτα συνδρομής', 'admin.plans.add': '+ Νέο πακέτο', 'admin.plans.empty': 'Δεν υπάρχουν πακέτα', 'admin.plans.form.new': 'Νέο πακέτο', 'admin.plans.form.edit': 'Επεξεργασία πακέτου', 'admin.plans.form.name': 'Όνομα', 'admin.plans.form.price': 'Τιμή (EUR)', 'admin.plans.form.old_price': 'Παλιά τιμή (EUR, προαιρετικό)', 'admin.plans.form.max_offers': 'Μέγ. προσφορές (κενό = χωρίς όριο)', 'admin.plans.form.max_cards': 'Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)', 'admin.plans.form.duration_days': 'Διάρκεια (ημέρες, κενό = χωρίς λήξη)', 'admin.plans.form.description': 'Περιγραφή', 'admin.plans.form.features': 'Δυνατότητες (μία ανά γραμμή)', 'admin.plans.form.notify': 'Ειδοποιήσεις νέων εργασιών', 'admin.plans.form.default': 'Προεπιλογή', 'admin.plans.form.active': 'Ενεργό', 'admin.plans.form.order': 'Σειρά', 'admin.plans.form.role': 'Ρόλος', 'admin.plans.form.tier': 'Επίπεδο', 'admin.plans.form.role.customer': 'Πελάτης', 'admin.plans.form.role.specialist': 'Ειδικός', 'admin.plans.form.tier.free': 'Δωρεάν', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Όρια (κενό = χωρίς όριο)', 'admin.plans.form.max_messages_day': 'Μέγ. μηνύματα/ημέρα', 'admin.plans.form.max_orders_day': 'Μέγ. παραγγελίες/ημέρα', 'admin.plans.form.max_skills': 'Μέγ. δεξιότητες', 'admin.plans.form.max_profiles': 'Μέγ. προφίλ', 'admin.plans.form.max_portfolio': 'Μέγ. στοιχεία χαρτοφυλακίου', 'admin.plans.form.section.boost': 'Πολλαπλασιαστές & Ενίσχυση', 'admin.plans.form.search_boost': 'Ενίσχυση αναζήτησης', 'admin.plans.form.offers_multiplier': 'Πολλαπλασιαστής προσφορών', 'admin.plans.form.section.contact': 'Δικαιώματα επικοινωνίας', 'admin.plans.form.can_contact_free': 'Επικοινωνία με δωρεάν χρήστες', 'admin.plans.form.can_contact_pro': 'Επικοινωνία με Pro χρήστες', 'admin.plans.form.can_contact_all': 'Επικοινωνία με όλους', 'admin.plans.form.can_show_contact': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.plans.form.can_view_phone': 'Προβολή τηλεφώνου', 'admin.plans.form.section.features': 'Λειτουργίες', 'admin.plans.form.upload_video': 'Μεταφόρτωση βίντεο', 'admin.plans.form.favorites': 'Αγαπημένα', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Σήμα επαλήθευσης', 'admin.plans.form.highlighted_reviews': 'Προβεβλημένες κριτικές', 'admin.plans.form.personal_site': 'Προσωπική σελίδα', 'admin.plans.form.can_help_now': 'Κατάσταση «Μπορώ να βοηθήσω»', 'admin.plans.form.need_help': 'Κατάσταση «Χρειάζομαι βοήθεια»', 'admin.plans.form.auto_response': 'Αυτόματη απάντηση', 'admin.plans.form.auto_match': 'Αυτόματη αντιστοίχιση', 'admin.plans.form.instant_dispatch_free': 'Άμεση αποστολή (δωρεάν)', 'admin.plans.form.instant_dispatch_pro': 'Άμεση αποστολή (Pro)', 'admin.plans.badge.default': 'Προεπιλογή', 'admin.plans.badge.inactive': 'Ανενεργό', 'admin.plans.make_default': 'Ορισμός ως προεπιλογή', 'admin.plans.tasks': 'Εργασίες', 'admin.plans.offers': 'Προσφορές', 'admin.plans.cards': 'Χαρτοφυλάκιο', 'admin.plans.notify_tasks': 'Ειδοποιήσεις εργασιών', 'admin.plans.delete.confirm': 'Διαγραφή πακέτου', 'admin.activity.title': 'Αρχείο δραστηριότητας', 'admin.activity.event': 'Γεγονός', 'admin.activity.all_events': 'Όλα τα γεγονότα', 'admin.activity.from': 'Από', 'admin.activity.to': 'Έως', 'admin.activity.reset': 'Επαναφορά', 'admin.activity.total': 'Σύνολο', 'admin.activity.empty': 'Δεν υπάρχουν εγγραφές', 'admin.mail.event': 'Συμβάν email', 'admin.mail.all_events': 'Όλα τα email συμβάντα', 'admin.mail.from': 'Από', 'admin.mail.to': 'Έως', 'admin.mail.reset': 'Επαναφορά', 'admin.mail.total': 'Σύνολο', 'admin.mail.empty': 'Δεν υπάρχουν email logs', 'admin.mail.recipient': 'Παραλήπτης', 'admin.mail.provider': 'Πάροχος', 'admin.mail.details': 'Λεπτομέρειες', 'admin.mail.status': 'Κατάσταση', 'admin.mail.success': 'Επιτυχία', 'admin.mail.failed': 'Σφάλμα', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'Δεν υπάρχουν εγγραφές', 'admin.logs.date': 'Ημερομηνία', 'admin.logs.provider': 'Πάροχος', 'admin.logs.model': 'Μοντέλο', 'admin.logs.action': 'Ενέργεια', 'admin.logs.langs': 'Γλώσσες', 'admin.logs.in': 'Είσοδος', 'admin.logs.out': 'Έξοδος', 'admin.logs.total': 'Σύνολο', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Κατάσταση', 'admin.stats.activity_30d': 'Δραστηριότητα 30 ημερών', 'admin.stats.tasks_label': 'Εργασίες', 'admin.stats.users_label': 'Χρήστες', 'admin.stats.specialists_label': 'Ειδικοί', 'admin.stats.tokens_title': 'Χρήση tokens (ανά μήνα)', 'admin.stats.tokens_out': 'Εξερχόμενα', 'admin.stats.tokens_in': 'Εισερχόμενα', 'admin.stats.tokens_out_label': 'Εξερχόμενα tokens', 'admin.stats.tokens_in_label': 'Εισερχόμενα tokens', 'admin.stats.cost_label': 'Κόστος (USD)', 'admin.stats.tasks_by_status': 'Εργασίες ανά κατάσταση', 'admin.task_status.open': 'Ανοιχτές', 'admin.task_status.in_progress': 'Σε εξέλιξη', 'admin.task_status.completed': 'Ολοκληρωμένες', 'admin.task_status.cancelled': 'Ακυρωμένες', 'admin.task_status.draft': 'Προσχέδια', 'admin.settings.tab.general': 'Γενικά', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Ειδοποιήσεις', 'admin.settings.tab.payment': 'Πληρωμή', 'admin.settings.tab.referral': 'Παραπομπές', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Κοινωνικά δίκτυα', 'admin.settings.socials.title': 'Σύνδεσμοι κοινωνικών δικτύων', 'admin.settings.socials.hint': 'Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο', 'admin.settings.seo.maintenance_label': 'Λειτουργία συντήρησης', 'admin.settings.seo.maintenance_hint': 'Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες', 'admin.settings.seo.indexing_label': 'Ευρετηρίαση από μηχανές αναζήτησης', 'admin.settings.seo.indexing_hint': 'Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο', 'admin.settings.seo.head_scripts_label': 'Scripts στο (JS)', 'admin.settings.seo.head_scripts_hint': 'Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)', 'admin.settings.seo.site_title_label': 'Τίτλος ιστότοπου', 'admin.settings.seo.site_description_label': 'Περιγραφή ιστότοπου (meta description)', 'admin.settings.referral.title': 'Πρόγραμμα παραπομπών', 'admin.settings.referral.hint': 'Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.', 'admin.settings.referral.enabled_label': 'Ενεργό', 'admin.settings.referral.enabled_hint': 'Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών', 'admin.settings.referral.customer_section': 'Για πελάτες', 'admin.settings.referral.specialist_section': 'Για ειδικούς', 'admin.settings.referral.plan_label': 'Πλάνο ανταμοιβής', 'admin.settings.referral.no_plan': '— χωρίς πλάνο —', 'admin.settings.referral.plan_hint': 'Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.', 'admin.settings.referral.days_label': 'Ημέρες ανταμοιβής', 'admin.settings.referral.days_hint': 'Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.', 'admin.settings.general.title': 'Γενικές ρυθμίσεις', 'admin.settings.general.site_name': 'Όνομα ιστότοπου', 'admin.settings.general.site_url': 'URL ιστότοπου', 'admin.settings.general.contact_email': 'Email επικοινωνίας', 'admin.settings.general.support_phone': 'Τηλέφωνο υποστήριξης', 'admin.settings.smtp.title': 'Ρυθμίσεις SMTP', 'admin.settings.smtp.hint': 'Χρησιμοποιείται για αποστολή ειδοποιήσεων email.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Θύρα', 'admin.settings.smtp.encryption': 'Κρυπτογράφηση', 'admin.settings.smtp.enc.none': 'Χωρίς', 'admin.settings.smtp.enc.tls': 'STARTTLS (θύρα 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (θύρα 465)', 'admin.settings.smtp.username': 'Όνομα χρήστη', 'admin.settings.smtp.password': 'Κωδικός / App Password', 'admin.settings.smtp.from_name': 'Όνομα αποστολέα', 'admin.settings.smtp.from_email': 'Email αποστολέα', 'admin.settings.smtp.test': 'Αποστολή δοκιμαστικού email', 'admin.settings.smtp.sending': 'Αποστολή...', 'admin.settings.payment.hint': 'Τα στοιχεία για ePay Piraeus Bank.', 'admin.settings.env.test': 'Δοκιμαστικό (sandbox)', 'admin.settings.env.prod': 'Παραγωγή', 'admin.settings.env.label': 'Περιβάλλον', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Ενεργό', 'admin.settings.saving': 'Αποθήκευση...', 'admin.settings.saved': '✓ Αποθηκεύτηκε', 'admin.notif.vars_hint': 'Διαθέσιμες μεταβλητές στα πρότυπα', 'admin.notif.tmpl.not_set': 'Πρότυπο δεν έχει οριστεί', 'admin.notif.tmpl.subject_label': 'Θέμα email', 'admin.notif.tmpl.body_label': 'Κείμενο email (HTML)', 'admin.notif.tmpl.save': 'Αποθήκευση', 'admin.notif.tmpl.close': 'Κλείσιμο', 'admin.notif.tmpl.translate': 'Αυτόματη μετάφραση', 'admin.notif.tmpl.translating': 'Μετάφραση...', 'admin.notif.tmpl.saving': 'Αποθήκευση...', 'admin.notif.email_verification': 'Επαλήθευση email', 'admin.notif.registration_success': 'Επιτυχής εγγραφή', 'admin.notif.password_reset': 'Επαναφορά κωδικού', 'admin.notif.new_offer': 'Νέα προσφορά', 'admin.notif.new_task': 'Νέα εργασία', 'admin.notif.offer_accepted': 'Προσφορά αποδεκτή', 'admin.notif.new_message': 'Νέο μήνυμα', 'admin.notif.offer_declined': 'Απόρριψη προσφοράς', 'admin.notif.offer_other_accepted': 'Επιλέχθηκε άλλος ειδικός', 'admin.notif.task_updated': 'Ενημέρωση εργασίας', 'admin.notif.deadline_reminder': 'Υπενθύμιση προθεσμίας', 'admin.notif.task_archived': 'Αυτόματη απόσυρση εργασίας', 'admin.notif.referral_reward': 'Ανταμοιβή παραπομπής', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Τιμολόγιο — ενεργοποίηση πλάνου', 'admin.email_template.plan_upgraded': 'Τιμολόγιο — αναβάθμιση πλάνου', 'admin.email_template.plan_downgrade_scheduled': 'Τιμολόγιο — προγραμματισμένη υποβάθμιση', 'admin.email_template.plan_downgrade_applied': 'Τιμολόγιο — εφαρμογή υποβάθμισης', 'admin.email_template.plan_renewal_reminder': 'Τιμολόγιο — υπενθύμιση ανανέωσης', 'admin.email_template.plan_insufficient_funds': 'Τιμολόγιο — ανεπαρκές υπόλοιπο', // Pricing confirm modal 'pricing.confirm.title': 'Επιβεβαίωση επιλογής πλάνου', 'pricing.confirm.plan': 'Πλάνο', 'pricing.confirm.prorated': 'Αναλογική έκπτωση', 'pricing.confirm.effective_price': 'Προς πληρωμή', 'pricing.confirm.your_balance': 'Το υπόλοιπό σας', 'pricing.confirm.downgrade_info': 'Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.', 'pricing.confirm.insufficient': 'Ανεπαρκές υπόλοιπο.', 'pricing.confirm.top_up': 'Ανανέωση', 'pricing.confirm.schedule_downgrade': 'Προγραμματισμός μετάβασης', 'pricing.confirm.pay': 'Πληρωμή', 'admin.user_edit.title': 'Επεξεργασία χρήστη', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Διευθυνση email επαληθεύτηκε', 'admin.user_edit.email_not_verified': 'Email δεν έχει επαληθευτεί', 'admin.user_edit.verify_email_btn': 'Χειροκίνητη επαλήθευση', 'admin.user_edit.verify_email_done': 'Email επαληθεύτηκε!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Εγγραφή', 'admin.user_edit.last_seen': 'Τελευταία σύνδεση', 'admin.user_edit.lang': 'Γλώσσα', 'admin.user_edit.first_name': 'Όνομα', 'admin.user_edit.last_name': 'Επώνυμο', 'admin.user_edit.phone': 'Τηλέφωνο', 'admin.user_edit.bio': 'Βιογραφικό', 'admin.user_edit.role': 'Ρόλος', 'admin.user_edit.plan': 'Πακέτο', 'admin.user_edit.no_plan': '— Χωρίς πακέτο —', 'admin.user_edit.active': 'Ενεργός λογαριασμός', 'admin.user_edit.balance': 'Υπόλοιπο (EUR)', 'admin.user_edit.skills': 'Δεξιότητες', 'admin.user_edit.tab.profile': 'Προφίλ', 'admin.user_edit.tab.account': 'Λογαριασμός', 'admin.user_edit.tab.balance': 'Υπόλοιπο', 'admin.user_edit.tab.settings': 'Ρυθμίσεις', 'admin.user_edit.tab.specialist': 'Χαρτοφυλάκιο', 'admin.user_edit.tab.site': 'Ιστοσελίδα', 'admin.user_edit.plan_expires': 'Λήξη πλάνου', 'admin.user_edit.interface_lang': 'Γλώσσα διεπαφής', 'admin.user_edit.comm_languages': 'Γλώσσες επικοινωνίας', 'admin.user_edit.personal_site_slug': 'Προσωπική σελίδα', 'admin.user_edit.show_contact_info': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.user_edit.show_contact_info.hint': 'Ορατό στους πελάτες', 'admin.user_edit.notify_new_tasks': 'Ειδοποίηση για νέες εργασίες', 'admin.user_edit.notify_new_tasks.hint': 'Push και email ειδοποιήσεις', 'admin.user_edit.notif_messages': 'Ειδοποιήσεις μηνυμάτων', 'admin.user_edit.notif_messages.hint': 'Νέα μηνύματα στη συνομιλία', 'admin.user_edit.site_settings': 'Ρυθμίσεις προσωπικής σελίδας', 'admin.user_edit.categories': 'Κατηγορίες υπηρεσιών', 'admin.user_edit.locations': 'Περιοχές εξυπηρέτησης', 'admin.user_edit.skill_placeholder': 'Νέα δεξιότητα...', 'admin.user_edit.add_category': '— Επιλέξτε κατηγορία —', 'admin.user_edit.add_location': '— Επιλέξτε περιοχή —', 'admin.user_edit.specialist_cards': 'Χαρτοφυλάκιο ειδικού', 'admin.user_edit.no_cards': 'Δεν βρέθηκαν στοιχεία χαρτοφυλακίου', 'admin.user_edit.card_title': 'Τίτλος χαρτοφυλακίου', 'admin.user_edit.card_description': 'Περιγραφή', 'admin.balance.topup.btn': 'Αναπλήρωση', 'admin.balance.withdraw.btn': 'Αφαίρεση', 'admin.balance.modal_hint': 'Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό', 'admin.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'admin.balance.topup.amount': 'Ποσό', 'admin.balance.topup.description': 'Σχόλιο', 'admin.balance.topup.description.placeholder': 'Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση', 'admin.balance.topup.submit': 'Αναπλήρωση υπολοίπου', 'admin.balance.withdraw.title': 'Αφαίρεση υπολοίπου', 'admin.balance.withdraw.amount': 'Ποσό', 'admin.balance.withdraw.description': 'Σχόλιο', 'admin.balance.withdraw.description.placeholder': 'Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση', 'admin.balance.withdraw.submit': 'Αφαίρεση από το υπόλοιπο', 'admin.user_edit.role.customer': 'Πελάτης', 'admin.user_edit.role.specialist': 'Ειδικός', 'admin.user_edit.role.admin': 'Διαχειριστής', 'common.refresh': 'Ανανέωση', 'common.back_home': 'Αρχική', 'admin.loc.hint': 'Διαχείριση πόλεων και συνοικιών', 'admin.loc.add_city': 'Νέα πόλη', 'admin.loc.add_district': 'Προσθήκη συνοικίας', 'admin.loc.new': 'Νέα τοποθεσία', 'admin.loc.edit': 'Επεξεργασία τοποθεσίας', 'admin.loc.district': 'συνοικία', 'admin.loc.empty': 'Δεν υπάρχουν τοποθεσίες', 'admin.loc.delete.confirm': 'Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.', 'admin.cat.add_root': 'Νέα κατηγορία', 'admin.cat.add_sub': 'Υποκατηγορία', 'admin.cat.edit': 'Επεξεργασία', 'admin.cat.delete': 'Διαγραφή', 'admin.cat.delete.confirm': 'Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Εικονίδιο', 'admin.cat.name_el': 'Ελληνικά', 'admin.cat.name_en': 'Αγγλικά', 'admin.cat.name_ru': 'Ρωσικά', 'admin.cat.order': 'Σειρά', 'admin.cat.active': 'Ενεργή', 'admin.cat.parent': 'Γονική κατηγορία', 'admin.cat.no_parent': 'Κορυφαίο επίπεδο', 'admin.cat.save': 'Αποθήκευση', 'admin.cat.cancel': 'Ακύρωση', 'admin.cat.empty': 'Δεν υπάρχουν κατηγορίες', 'admin.cat.hint': 'Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία', 'admin.cat.new': 'Νέα κατηγορία', 'admin.cat.subcategory': 'υποκατηγορία', 'admin.cat.add_child': 'Προσθήκη υποκατηγορίας', 'admin.cat.inactive': 'Ανενεργή', 'admin.event.user_login': 'Σύνδεση', 'admin.event.user_register': 'Εγγραφή', 'admin.event.admin_user_deactivate': 'Αποκλεισμός χρήστη', 'admin.event.admin_user_activate': 'Ενεργοποίηση χρήστη', 'admin.event.admin_user_role_changed': 'Αλλαγή ρόλου', 'admin.event.admin_task_cancelled': 'Ακύρωση εργασίας', 'admin.event.admin_task_deleted': 'Διαγραφή εργασίας', 'admin.event.admin_report_reviewed': 'Αναφορά εξετάστηκε', 'admin.event.admin_report_dismissed': 'Αναφορά απορρίφθηκε', 'admin.event.task_created': 'Δημιουργία εργασίας', 'user.online': 'Σε σύνδεση', 'user.seen_minutes': 'ήταν εδώ πριν {n} λεπτά', 'user.seen_hours': 'ήταν εδώ πριν {n} ώρες', 'user.seen_yesterday': 'ήταν εδώ χθες', 'user.seen_days': 'ήταν εδώ πριν {n} μέρες', // Specialists 'specialists.title': 'Ειδικοί', 'specialists.search': 'Αναζήτηση ειδικού...', 'specialists.search.btn': 'Αναζήτηση', 'specialists.empty': 'Δεν βρέθηκαν ειδικοί', 'specialists.no_bio': 'Χωρίς περιγραφή', 'specialists.view': 'Προβολή προφίλ', 'specialists.reviews': 'αξιολογήσεις', 'specialist.favorite': 'Προσθήκη στα αγαπημένα', 'specialist.unfavorite': 'Αφαίρεση από αγαπημένα', 'specialist.site_link': 'Προσωπικό site', 'favorites.specialists.title': 'Αγαπημένοι ειδικοί', 'favorites.specialists.empty': 'Δεν έχετε αγαπημένους ειδικούς', 'nav.favorites': 'Αγαπημένα', 'nav.schedule': 'Πρόγραμμα', 'nav.find_tasks': 'Αναζήτηση εργασιών', 'schedule.title': 'Το πρόγραμμά μου', 'schedule.subtitle': 'Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας', 'schedule.available': 'Ελεύθερος', 'schedule.busy': 'Απασχολημένος', 'schedule.unset': 'Μη ορισμένο', 'schedule.click_hint': '← κλικ για εναλλαγή κατάστασης', 'schedule.range_mode': 'Επιλογή εύρους', 'schedule.range_from': 'Από {date} — επιλέξτε τελική ημερομηνία', 'schedule.click_to_set': 'Κλικ για ορισμό', 'schedule.free': 'ελεύθερα', 'schedule.busy_count': 'απασχολημένα', 'schedule.free_days': 'ελεύθερες ημέρες', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Σύνδεση με Google Calendar', 'schedule.disconnectGoogle': 'Αποσύνδεση', 'schedule.connectedAs': 'Συνδεδεμένο ως', 'schedule.importFromGoogle': 'Συγχρονισμός από Google', 'schedule.gcalConnected': '✓ Google Calendar συνδέθηκε', 'schedule.gcalError': 'Σφάλμα σύνδεσης Google Calendar', 'schedule.gcalImportDone': 'Εισήχθησαν {n} ημερ. από Google Calendar', 'schedule.gcalAutoSyncNote': 'Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar', 'schedule.gcalConnectDesc': 'Συνδέστε το Google Calendar για αυτόματο συγχρονισμό', 'schedule.gcalDisconnectConfirm': 'Αποσύνδεση Google Calendar;', 'find_tasks.title': 'Αναζήτηση εργασιών', 'find_tasks.for_me': 'Για μένα', 'find_tasks.all': 'Όλες οι εργασίες', 'find_tasks.by_category': 'Ανά κατηγορία', 'find_tasks.list': 'Λίστα', 'find_tasks.already_offered': 'Προσφορά υποβλήθηκε', 'find_tasks.offer_now': 'Υποβολή προσφοράς', 'find_tasks.empty_for_me': 'Δεν βρέθηκαν εργασίες στις κατηγορίες σας', 'find_tasks.banner_hint': 'Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας', 'find_tasks.no_cards': 'Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς', 'find_tasks.add_card': 'Δημιουργία χαρτοφυλακίου', 'find_tasks.search': 'Αναζήτηση εργασιών...', 'find_tasks.tasks_count': 'εργασίες', // Footer 'footer.tagline': 'Η πλατφόρμα εργασιών για την Ελλάδα', 'footer.rights': 'Όλα τα δικαιώματα διατηρούνται.', // App download section 'app.download_title': 'Κατεβάστε την εφαρμογή CanHelp', 'app.download_desc': 'Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.', // Nav 'nav.pricing': 'Τιμές', // Pricing page 'pricing.title': 'Τιμολόγηση', 'pricing.subtitle': 'Επιλέξτε το κατάλληλο πρόγραμμα', 'pricing.role.customer': 'Πελάτης', 'pricing.role.specialist': 'Ειδικός', 'pricing.free': 'Δωρεάν', 'pricing.per_month': 'μήνα', 'pricing.duration': 'Διάρκεια', 'pricing.days': 'ημ.', 'pricing.current_plan': 'Το πρόγραμμά σας', 'pricing.popular': 'Δημοφιλές', 'pricing.choose': 'Επιλογή', 'pricing.your_plan': 'Ενεργό πρόγραμμα', 'pricing.free_default': 'Προεπιλογή', 'pricing.compare': 'Σύγκριση λειτουργιών', 'pricing.feature': 'Λειτουργία', 'pricing.faq_note': 'Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.', 'pricing.feat.messages': 'Μηνύματα / ημέρα', 'pricing.feat.orders': 'Παραγγελίες / ημέρα', 'pricing.feat.contact_all': 'Επικοινωνία με όλους', 'pricing.feat.view_phone': 'Εμφάνιση τηλεφώνου', 'pricing.feat.show_contact': 'Εμφάνιση στοιχείων επαφής', 'pricing.feat.favorites': 'Αγαπημένα', 'pricing.feat.verified_badge': 'Επαληθευμένο badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Προσωπικό site', 'pricing.feat.auto_response': 'Αυτόματη απάντηση', 'pricing.feat.auto_match': 'Αυτόματη αντιστοίχιση', 'pricing.feat.highlighted_reviews': 'Επισημασμένες αξιολογήσεις', 'pricing.feat.portfolio': 'Στοιχεία χαρτοφυλακίου', 'pricing.feat.cards': 'Κάρτες ειδικού', 'pricing.feat.notify_tasks': 'Ειδοποιήσεις νέων εργασιών', 'pricing.feat.video': 'Βίντεο στο χαρτοφυλάκιο', // Upgrade prompt 'upgrade.available_in': 'Διαθέσιμο στο', 'upgrade.cta': 'Αναβάθμιση', // Dashboard plan block 'dashboard.plan.title': 'Το πρόγραμμά μου', 'dashboard.plan.expires': 'Λήγει σε {n} ημέρες', 'dashboard.plan.upgrade': 'Αναβάθμιση προγράμματος', 'dashboard.plan.no_plan': 'Δωρεάν πρόγραμμα', 'dashboard.plan.messages': 'Μηνύματα σήμερα', 'dashboard.plan.orders': 'Παραγγελίες σήμερα', 'dashboard.plan.limits': 'Ημερήσια όρια', 'dashboard.plan.features': 'Λειτουργίες', 'dashboard.plan.stats': 'Στατιστικά', 'dashboard.stats.cards': 'Χαρτοφυλάκια', 'dashboard.stats.maxCards': 'Μέγ. χαρτοφυλάκια', 'dashboard.stats.portfolioItems': 'Στοιχεία portfolio', 'dashboard.stats.maxPortfolioItems': 'Μέγ. στοιχεία', 'dashboard.stats.activeOffers': 'Ενεργές προσφορές', 'dashboard.stats.reviewsReceived': 'Αξιολογήσεις', 'dashboard.stats.activeTasks': 'Ενεργές εργασίες', 'dashboard.stats.completedTasks': 'Ολοκληρωμένες', 'status.can_help_now': 'Είμαι διαθέσιμος τώρα', 'status.need_help': 'Χρειάζομαι βοήθεια', 'status.active': 'Ενεργό', 'status.toggle_on': 'Ενεργοποίηση', 'status.toggle_off': 'Απενεργοποίηση', // FOMO 'fomo.missed_orders': 'Χάσατε {n} παραγγελίες', 'fomo.missed_value': 'Αξία €{v}', 'fomo.upgrade_hint': 'Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες', 'fomo.conversion': 'Μετατροπές εργασιών', 'fomo.active': 'Ενεργές', 'fomo.with_offers': 'Με προσφορές', 'fomo.completed': 'Ολοκληρωμένες', 'fomo.already_offered': '{n} ειδικοί έχουν ήδη απαντήσει', 'fomo.specialist_missed': 'Χάσατε {n} παραγγελίες', 'fomo.top_categories': 'Κατηγορίες', 'fomo.offers_received': 'προσφορές ελήφθησαν', 'fomo.avg_offers': 'Μέσο {n}/εργασία', 'fomo.completion_rate': 'ολοκληρωμένες', // Task auto-match 'task.auto_match': 'Αυτόματη αντιστοίχιση', 'task.auto_match_results': 'Κορυφαίοι ειδικοί', 'task.no_offer_yet': 'Δεν έχετε στείλει προσφορά ακόμα', 'task.make_offer': 'Αποστολή προσφοράς', 'auto_response.title': 'Αυτόματη Απάντηση', 'auto_response.enabled': 'Ενεργοποίηση αυτόματης απάντησης', 'auto_response.min_budget': 'Ελάχ. προϋπολογισμός', 'auto_response.max_budget': 'Μέγ. προϋπολογισμός', 'auto_response.default_price': 'Προεπιλεγμένη τιμή', 'auto_response.default_message': 'Προεπιλεγμένο μήνυμα', 'auto_response.max_per_day': 'Μέγ. αυτόματες προσφορές/ημέρα', 'auto_response.save': 'Αποθήκευση', 'auto_response.saved': 'Αποθηκεύτηκε', 'auto_response.categories': 'Κατηγορίες', 'auto_response.locations': 'Τοποθεσίες', // Personal site 'profile.personal_site': 'Προσωπικό Site', 'profile.site_slug': 'Slug URL', 'profile.site_slug_hint': 'Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _', 'profile.site_open': 'Άνοιγμα site', 'profile.site_preview': 'Το site σας', 'profile.show_contact': 'Εμφάνιση στοιχείων επαφής', 'profile.show_contact_hint': 'Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας', // Google Calendar plan gate 'gcal.upgrade_required': 'Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα', // Chat limits 'chat.limit_warning': 'Απομένουν {n} μηνύματα σήμερα', 'chat.limit_reached': 'Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας', 'chat.upgrade': 'Αναβάθμιση', // Site page 'site.member_since': 'Μαζί μας από', 'site.rating': 'Βαθμολογία', 'site.completed_tasks': 'Ολοκληρώθηκαν', 'site.languages': 'Γλώσσες', 'site.photos': 'φωτ.', 'site.contact_form': 'Επικοινωνία', 'site.contact_sent': 'Το μήνυμα στάλθηκε!', 'site.contact_sent_desc': 'Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα', 'site.contact_name': 'Όνομα', 'site.contact_name_ph': 'Το όνομά σας', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Μήνυμα', 'site.contact_message_ph': 'Περιγράψτε την εργασία σας...', 'site.contact_send': 'Αποστολή', 'site.share': 'Κοινοποίηση', 'site.speaks_languages': 'Μιλάει', 'site.message_sent': 'Το μήνυμα εστάλη!', 'site.message_sent_desc': 'Ο ειδικός θα το λάβει στη συνομιλία', 'site.message_placeholder': 'Γράψτε το μήνυμά σας...', 'site.write_to_chat': 'Γράψτε στο chat', 'site.auth_required_title': 'Απαιτείται σύνδεση', 'site.auth_required_desc': 'Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.', 'site.auth_login_btn': 'Σύνδεση', 'site.auth_contact_form_btn': 'Επικοινωνία μέσω φόρμας', 'specialist.services': 'Υπηρεσίες', 'portfolio.title': 'Χαρτοφυλάκιο', 'common.not_found': 'Η σελίδα δεν βρέθηκε', 'common.anonymous': 'Ανώνυμα', 'specialist_setup.page_title': 'Ρύθμιση προφίλ ειδικού', 'specialist_setup.step_of': 'Βήμα {current} από {total}', 'specialist_setup.next': 'Επόμενο', 'specialist_setup.back': 'Πίσω', 'specialist_setup.skip': 'Παράλειψη', 'specialist_setup.finish': 'Ολοκλήρωση', 'specialist_setup.go_to_profile': 'Μεταβείτε στο προφίλ', 'specialist_setup.browse_tasks': 'Εξερεύνηση εργασιών', 'specialist_setup.step1.title': 'Καλωσήλθατε!', 'specialist_setup.step1.subtitle': 'Ας ρυθμίσουμε το προφίλ σας', 'specialist_setup.step1.desc': 'Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.', 'specialist_setup.step1.what_next': 'Τι θα κάνουμε:', 'specialist_setup.step1.item1': 'Συμπλήρωση βασικών πληροφοριών', 'specialist_setup.step1.item2': 'Δημιουργία κάρτας υπηρεσίας', 'specialist_setup.step1.item3': 'Προσθήκη δεξιοτήτων και κατηγοριών', 'specialist_setup.step1.item4': 'Επιλογή γεωγραφικής περιοχής', 'specialist_setup.step1.item5': 'Μεταφόρτωση φωτογραφιών χαρτοφυλακίου', 'specialist_setup.step2.title': 'Βασικό προφίλ', 'specialist_setup.step2.subtitle': 'Πείτε μας για σας', 'specialist_setup.step2.bio_label': 'Σχετικά με εμένα', 'specialist_setup.step2.bio_placeholder': 'Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...', 'specialist_setup.step2.phone_label': 'Τηλέφωνο', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Φωτογραφία προφίλ', 'specialist_setup.step2.photo_btn': 'Μεταφόρτωση φωτογραφίας', 'specialist_setup.step2.photo_uploading': 'Μεταφόρτωση...', 'specialist_setup.step2.photo_hint': 'Εμφανίζεται στο προφίλ σας', 'specialist_setup.step3.title': 'Κάρτα υπηρεσίας', 'specialist_setup.step3.subtitle': 'Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας', 'specialist_setup.step3.title_label': 'Τίτλος κάρτας', 'specialist_setup.step3.title_placeholder': 'Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...', 'specialist_setup.step3.desc_label': 'Περιγραφή', 'specialist_setup.step3.desc_placeholder': 'Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...', 'specialist_setup.step3.title_required': 'Απαιτείται τίτλος', 'specialist_setup.step4.title': 'Δεξιότητες & Κατηγορίες', 'specialist_setup.step4.subtitle': 'Προσθέστε δεξιότητες και επιλέξτε κατηγορίες', 'specialist_setup.step4.skills_label': 'Δεξιότητες', 'specialist_setup.step4.skills_placeholder': 'Π.χ. Εγκατάσταση σωληνώσεων...', 'specialist_setup.step4.skills_add': 'Προσθήκη', 'specialist_setup.step4.categories_label': 'Κατηγορίες', 'specialist_setup.step5.title': 'Γεωγραφική περιοχή', 'specialist_setup.step5.subtitle': 'Πού παρέχετε υπηρεσίες;', 'specialist_setup.step5.hint': 'Επιλέξτε πόλεις ή συγκεκριμένες περιοχές', 'specialist_setup.done.title': 'Το προφίλ σας είναι έτοιμο!', 'specialist_setup.done.subtitle': 'Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί', 'specialist_setup.done.desc': 'Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας.' }, en: { 'footer.slogan': 'Your task — our care! We solve any issue quickly and easily.', 'footer.links': 'Links', 'footer.socials': 'Socials', 'nav.home': 'Home', 'nav.tasks': 'Tasks', 'nav.post': '+ Post task', 'nav.dashboard': 'Dashboard', 'nav.chat': 'Messages', 'nav.notifications': 'Notifications', 'nav.profile': 'Profile', 'nav.admin': 'Admin Panel', 'nav.specialists': 'Specialists', 'nav.new_task': 'New task', 'nav.login': 'Login', 'nav.register': 'Register', 'nav.logout': 'Logout', 'hero.title': 'Find a specialist for any job', 'hero.subtitle': 'Post a task, receive offers and choose the best professional', 'hero.cta.post': 'Post a task', 'hero.cta.browse': 'Become a specialist', 'hero.search.placeholder': 'What do you need? e.g. electrician, cleaning...', 'stats.specialists': 'specialists', 'stats.tasks': 'tasks', 'stats.categories': 'categories', 'stats.free': 'free sign-up', 'section.categories': 'Create a task in any category', 'section.how': 'How it works', 'section.recent': 'Recent tasks', 'section.all': 'See all →', 'section.more': 'more', 'section.cities': 'Cities & Districts', 'section.community': 'A community project for everyone', 'community.subtitle': 'CanHelp is not just a marketplace — it\'s a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.', 'community.point1.title': 'Are you good at something?', 'community.point1.desc': 'Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.', 'community.point2.title': 'Need help with something?', 'community.point2.desc': 'Post a task in under a minute and receive offers from verified specialists in your city.', 'community.point3.title': 'Help the project grow', 'community.point3.desc': 'CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.', 'community.share': 'Share with friends', 'community.share.copied': 'Link copied!', // Referral section on home page 'section.referral': 'Referral Program', 'referral.home.subtitle': 'Share your link — every new user who signs up through it earns you a reward.', 'referral.home.step1.title': 'Sign up and get your link', 'referral.home.step1.desc': 'Create an account and find your unique referral link in your profile.', 'referral.home.step2.title': 'Share with friends', 'referral.home.step2.desc': 'Send the link to friends, acquaintances, or post it on social media.', 'referral.home.step3.title': 'Earn rewards', 'referral.home.step3.desc': 'Once your friend verifies their email, you automatically receive your reward.', 'referral.home.cta': 'Get your link', 'referral.home.badge': 'Referral Program', // FAQ section 'section.faq': 'Frequently Asked Questions', 'faq.q1': 'How does CanHelp work?', 'faq.a1': 'Post a task, receive offers from specialists, choose the best one and start working together. It\'s fast, simple and free for customers.', 'faq.q2': 'How much does it cost to use the platform?', 'faq.a2': 'Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.', 'faq.q3': 'How can I become a specialist?', 'faq.a3': 'Register, go to «Become a Specialist», fill in your profile with skills and categories, and start receiving tasks.', 'faq.q4': 'How do I choose the right specialist?', 'faq.a4': 'Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.', 'faq.q5': 'What if I am not satisfied?', 'faq.a5': 'You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.', 'faq.q6': 'Can I contact a specialist before accepting their offer?', 'faq.a6': 'Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.', 'faq.q7': 'How long does it take to receive offers?', 'faq.a7': 'Usually within a few hours. Specialists get notified about new tasks and can respond quickly.', 'faq.q8': 'Can I post a task in any city in Greece?', 'faq.a8': 'Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.', 'faq.q9': 'What types of tasks can I find on CanHelp?', 'faq.a9': 'Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.', 'faq.q10': 'Is there a mobile app?', 'faq.a10': 'Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.', 'how.step1.title': 'Post a task', 'how.step1.desc': 'Describe what you need and set your budget', 'how.step2.title': 'Receive offers', 'how.step2.desc': 'Specialists will send you offers with price and timeline', 'how.step3.title': 'Choose & start', 'how.step3.desc': 'Pick the best professional and start the collaboration', 'tasks.title': 'tasks', 'tasks.filters': 'Filters', 'tasks.search': 'Search', 'tasks.search.placeholder': 'Title or keyword...', 'tasks.search.btn': 'Search', 'tasks.publish': 'Post', 'tasks.category.all': 'All', 'tasks.category.all_in': 'All in', 'tasks.category.label': 'Category', 'tasks.location.label': 'City', 'tasks.location.placeholder': 'e.g. Athens', 'tasks.empty': 'No tasks found', 'tasks.empty.cta': 'Post the first one', 'task.status.open': 'Open', 'task.status.in_progress': 'In progress', 'task.status.completed': 'Completed', 'task.status.cancelled': 'Cancelled', 'task.status.draft': 'Draft', 'task.budget': 'Budget', 'task.location': 'Location', 'task.deadline': 'Start date', 'task.created_at': 'Created', 'task.customer': 'Customer', 'task.offer.btn': 'Submit offer', 'task.invite.banner_title': "You've been invited to this task", 'task.invite.banner_hint': 'The customer personally invited you', 'task.invite.accept': 'Send offer', 'task.invite.decline': 'Decline', 'offer.accept': 'Accept', 'offer.decline': 'Decline', 'task.complete': 'Complete task', 'task.complete.confirm': 'Mark this task as complete?', 'task.edit': 'Edit', 'task.status_label': 'Status', 'task.yours': 'Your task', 'task.offer.yours': 'Your offer', 'review.leave': 'Leave a review', 'review.rating': 'Rating', 'review.comment': 'Comment', 'review.comment.placeholder': 'Tell us about your experience...', 'review.submit': 'Submit review', 'review.submitting': 'Submitting...', 'review.done': 'Review submitted!', 'profile.reviews': 'Reviews', 'profile.no_reviews': 'No reviews yet', 'profile.rating': 'Rating', 'profile.skills.label': 'Skills', 'profile.member_since': 'Member since', 'task.offers': 'Offers', 'task.offers.none': 'No offers yet', 'create.title': 'Post a task', 'create.field.title': 'Title', 'create.field.description': 'Description', 'create.field.category': 'Category', 'create.field.category.select': 'Select...', 'create.field.location': 'Location', 'create.field.location.any': 'Anywhere', 'create.field.location.all': 'Entire city', 'create.field.budget': 'Budget (€)', 'create.field.deadline': 'Start date', 'create.field.budget_negotiable': 'Price is negotiable', 'create.field.time_slot': 'Time slot', 'create.field.time_slot.any': 'Anytime', 'create.field.time_slot.morning': 'Morning (08:00–13:00)', 'create.field.time_slot.afternoon': 'Afternoon (13:00–18:00)', 'create.field.time_slot.evening': 'Evening (18:00–22:00)', 'create.field.time_slot.weekend': 'Weekend', 'create.field.address': 'Address (optional)', 'create.field.address.district': 'District', 'create.field.address.street': 'Street', 'create.field.address.house': 'Number', 'create.field.confidential': 'Confidential note', 'create.field.confidential.placeholder': 'Details visible only to the assigned specialist...', 'create.field.confidential.hint': 'Not shown publicly', 'create.field.photos': 'Photos', 'create.field.photos.add': 'Add photo', 'create.field.photos.uploading': 'Uploading...', 'task.budget_negotiable': 'Price negotiable', 'task.time_slot': 'Time slot', 'task.confidential': 'Confidential note', 'create.field.title.placeholder': 'e.g. Clean 80sqm apartment', 'create.field.description.placeholder': 'Describe in detail what you need...', 'create.field.location.placeholder': 'e.g. Athens, Kolonaki', 'create.field.budget.placeholder': 'e.g. 100', 'create.submit': 'Post task', 'create.submitting': 'Posting...', 'login.title': 'Welcome back', 'login.subtitle': 'Sign in to CanHelp', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.submitting': 'Signing in...', 'login.error': 'Invalid email or password', 'login.unverified.title': 'Verify your email address', 'login.unverified.desc': 'We sent a verification link to your email. Check your inbox (or spam) and click the link.', 'login.unverified.resend': 'Resend verification email', 'login.unverified.sending': 'Sending...', 'login.unverified.sent': '✓ Sent — check your inbox', 'profile.email.verified': 'Email verified', 'profile.email.not_verified': 'Email not verified', 'login.no_account': "Don't have an account?", 'login.register_link': 'Register', 'login.forgot_password': 'Forgot password?', 'login.or_continue_with': 'or continue with', 'login.continue_google': 'Continue with Google', 'forgot.title': 'Forgot password', 'forgot.subtitle': 'Enter your email to receive a reset link', 'forgot.email': 'Email', 'forgot.submit': 'Send reset link', 'forgot.submitting': 'Sending...', 'forgot.sent.title': 'Check your inbox', 'forgot.sent.desc': 'If an account exists with that email, we\'ll send you a password reset link.', 'forgot.back_to_login': 'Back to sign in', 'forgot.error': 'Could not send reset link. Check the email address and try again.', 'forgot.error.not_found': 'No account found with this email address.', 'forgot.error.send_failed': 'Failed to send email. Please try again later.', 'reset.title': 'New password', 'reset.subtitle': 'Enter your new password', 'reset.password': 'New password', 'reset.confirm': 'Confirm password', 'reset.submit': 'Change password', 'reset.submitting': 'Saving...', 'reset.success': 'Password changed successfully. Redirecting to sign in...', 'reset.back_to_login': 'Back to sign in', 'reset.error.mismatch': 'Passwords do not match', 'reset.error.invalid': 'Invalid or expired link. Please request a new one.', 'register.title': 'Register', 'register.subtitle': 'Create a CanHelp account', 'register.first_name': 'First name', 'register.last_name': 'Last name', 'register.email': 'Email', 'register.password': 'Password (min 8 characters)', 'register.role': 'Role', 'register.role.customer': 'User', 'register.role.customer.desc': 'I post tasks', 'register.role.specialist': 'Specialist', 'register.role.specialist.desc': 'I take on tasks', 'register.submit': 'Create account', 'register.submitting': 'Registering...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Sign in', 'register.continue_google': 'Continue with Google', 'register.check_email.title': 'Check your email', 'register.check_email.desc': 'We sent a verification link to your email address. Check your inbox (or spam) and click the link.', 'register.check_email.login': 'Back to sign in', 'dashboard.title': 'Dashboard', 'dashboard.new_task': '+ New task', 'dashboard.my_tasks': 'My tasks', 'dashboard.my_offers': 'My offers', 'dashboard.invitations': 'Job invitations', 'dashboard.offers_count': 'offers', 'dashboard.declined_count': 'declined', 'dashboard.completed_tasks': 'Completed tasks', 'dashboard.completed_offers': 'Completed offers', 'dashboard.review_pending': 'Review not yet submitted', 'tasks.new.top_specialists': 'Top specialists', 'tasks.new.select_category': 'Select a category to see matching specialists', 'tasks.new.invite': 'Offer work', 'tasks.new.invited': 'Selected ✓', 'reviews.count': 'reviews', 'filter.location': 'Location', 'filter.language': 'Languages', 'filter.language.any': 'Any language', 'filter.category.all': 'All categories', 'user.categories': 'Categories', 'user.work_area': 'Work area', 'dashboard.tasks.empty': "You haven't posted any tasks", 'dashboard.tasks.empty.cta': 'Post your first one', 'dashboard.tasks.add_new': 'Add a new task', 'dashboard.offers.empty': "You haven't submitted any offers", 'dashboard.offers.empty.cta': 'Find tasks', 'dashboard.customer.specialists_title': 'Looking for a specialist?', 'dashboard.customer.specialists_hint': 'Browse specialist profiles, read reviews and invite them to your tasks', 'dashboard.customer.specialists_cta': 'Find a specialist', 'dashboard.customer.how_title': 'How it works', 'dashboard.customer.step1': 'Create a task with a description and budget', 'dashboard.customer.step2': 'Specialists will send offers with price and timeline', 'dashboard.customer.step3': 'Choose the right one and start working', 'notif.title': 'Notifications', 'notif.mark_all': 'Mark all as read', 'notif.empty': 'No notifications', 'notif.type.new_offer': 'New offer', 'notif.type.offer_accepted': 'Your offer was accepted', 'notif.type.offer_declined': 'Your offer was declined', 'notif.type.task_completed': 'Task completed', 'notif.type.task_cancelled': 'Task cancelled', 'notif.type.new_message': 'New message', 'notif.type.new_review': 'New review', 'notif.type.task_invite': 'Job invitation', 'notif.body.new_offer': 'New offer for «{title}»', 'notif.body.offer_accepted': 'Your offer for «{title}» was accepted', 'notif.body.offer_declined': 'Your offer for «{title}» was declined', 'notif.body.task_invite': 'You\'ve been invited for «{title}»', 'notif.body.new_review': 'You received a {rating}★ review', 'offer.status.pending': 'Pending', 'offer.status.accepted': 'Accepted', 'offer.status.declined': 'Declined', 'offer.status.withdrawn': 'Withdrawn', 'offer.status.other_accepted': 'Another specialist was chosen', 'common.loading': 'Loading...', 'common.error': 'Error', 'common.save': 'Save', 'common.saving': 'Saving...', 'common.cancel': 'Cancel', 'common.add': 'Add', 'common.close': 'Close', 'common.edit': 'Edit', 'common.delete': 'Delete', 'common.from': 'by', 'common.currency': '€', 'common.greece': 'Greece', // Chat 'chat.connected': 'Connected', 'chat.disconnected': 'Disconnected', 'chat.no_rooms': 'No conversations yet', 'chat.task_fallback': 'Task', 'chat.select': 'Select a conversation', 'chat.no_messages': 'No messages yet', 'chat.placeholder': 'Write a message... (Enter to send)', 'chat.conversation_fallback': 'Conversation', 'chat.direct_chat': 'Direct chat', 'chat.linked_task': 'Linked task', 'chat.write_btn': 'Message', 'chat.just_now': 'just now', 'chat.min_ago': 'm', 'chat.write_specialist': 'Write to specialist', 'chat.write_customer': 'Write to customer', 'chat.notif_settings': 'Notification settings', 'chat.notif_messages': 'Notifications for new messages', 'chat.toast_title': 'New message', 'chat.toast_open': 'Open chat', // Offer form 'offer.price': 'Price', 'offer.price.placeholder': 'e.g. 80', 'offer.customer_budget': 'Client budget', 'offer.message': 'Message', 'offer.optional': 'optional', 'offer.message.placeholder': 'Introduce yourself, your experience and why you are the best choice...', 'offer.submitting': 'Sending...', // Profile 'profile.photo': 'Profile photo', 'profile.photo.change': 'Change photo', 'profile.photo.hint': 'JPEG, PNG, WebP · up to 5MB', 'profile.basic_info': 'Basic info', 'profile.phone': 'Phone', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Short bio', 'profile.bio.placeholder': 'Tell us a bit about yourself...', 'profile.language': 'Language', 'profile.language.hint': 'App interface and email notification language', 'profile.languages': 'Languages spoken', 'profile.languages.hint': 'Select all languages you speak', 'profile.skills': 'Skills', 'profile.skills.subtitle': 'Add the services you offer', 'profile.skills.placeholder': 'e.g. Cleaning, IT, Tutoring...', 'profile.role': 'Account role', 'profile.role.specialist': '🔧 Specialist', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 User', 'profile.role.change': 'To change your role please contact support.', 'profile.become_specialist': 'Become a Specialist', 'profile.become_specialist.desc': 'Upgrade to Specialist to take on tasks and build your profile.', 'become_specialist.hero.title': 'Earn money doing what you do best', 'become_specialist.hero.subtitle': 'Create a specialist profile and receive orders from clients across Greece', 'become_specialist.how.title': 'How it works', 'become_specialist.step1.title': 'Create a specialist portfolio', 'become_specialist.step1.desc': 'Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks', 'become_specialist.step2.title': 'Find tasks', 'become_specialist.step2.desc': 'Discover tasks in your categories in the "Find Orders" section', 'become_specialist.step3.title': 'Send an offer & earn', 'become_specialist.step3.desc': 'Submit offers with price and timeline, chat with clients and complete tasks', 'become_specialist.benefits.title': 'Specialist profile advantages', 'become_specialist.benefit1': 'Task search filtered by your categories and location', 'become_specialist.benefit2': 'Public profile with client reviews', 'become_specialist.benefit3': 'Availability schedule visible to clients', 'become_specialist.benefit4': 'Saved to favourites by clients', 'become_specialist.cta': 'Learn more', 'become_specialist.free_badge': 'Free registration', 'profile.tab.notifications': 'Notifications', 'profile.tab.reviews': 'Reviews', 'profile.tab.referral': 'Referrals', 'profile.tab.auto_response': 'Auto-response', 'profile.tab.site': 'Site', 'profile.site.title': 'Personal page', 'profile.site.url_label': 'Personal site', 'profile.site.copy': 'Copy', 'profile.site.copied': 'Copied', 'profile.site.visible_title': "What's on your page", 'profile.site.visible.name': 'Name and photo', 'profile.site.visible.bio': 'Bio', 'profile.site.visible.rating': 'Rating and reviews', 'profile.site.visible.portfolio': 'Portfolio / Cards', 'profile.site.visible.contacts': 'Contact info', 'profile.site.visible.full_last_name': 'Full last name', 'profile.site.visible.services': 'Service cards', 'profile.site.visible.reviews': 'Reviews section', 'profile.site.visible.status': '"Ready to help" status', 'profile.site.theme': 'Appearance theme', 'profile.site.theme.dark': 'Dark', 'profile.site.theme.light': 'Light', 'profile.site.slug_taken': 'This address is already taken', 'profile.site.stats.title': 'Site analytics', 'profile.site.stats.days': 'last 30 days', 'profile.site.stats.views': 'Views', 'profile.site.stats.unique': 'Unique visitors', 'profile.site.stats.messages': 'Messages', 'profile.site.stats.total_views': 'Total views', 'profile.site.stats.total_unique': 'Unique visitors', 'profile.site.stats.total_messages': 'Messages', 'profile.site.stats.empty': 'No data yet', 'profile.site.stats.loading': 'Loading analytics...', 'profile.site.stats.no_slug': 'Set your site URL to see analytics', 'profile.site.edit_bio_hint': 'Bio and photo are edited in the "Basic info" tab.', 'status.title': 'Status', 'status.can_help_now_hint': 'Your card is shown higher in search', 'status.need_help_hint': 'Specialists can offer you help', 'profile.referral.title': 'Referral program', 'profile.referral.desc': 'Share your link and earn rewards for every new user you invite.', 'profile.referral.link_label': 'Your referral link', 'profile.referral.copy': 'Copy', 'profile.referral.copied': 'Copied!', 'profile.referral.invited_count': 'successful referrals', 'profile.referral.no_code': 'Referral code is not available.', 'notifications.title': 'Notification settings', 'notifications.email.new_tasks': 'Email for new tasks', 'notifications.email.new_tasks.desc': 'Receive an email when a new task is posted in your categories', 'notifications.messages.desc': 'Receive a notification when a new message arrives', 'notifications.saved': 'Settings saved', 'notifications.plan_required': 'Not available in your plan', 'profile.tab.info': 'Basic info', 'profile.tab.finance': 'Finance', 'profile.tab.skills': 'Skills', 'profile.tab.categories': 'Categories', 'profile.tab.geography': 'Geography', 'profile.specialist.categories': 'Work categories', 'profile.specialist.categories.desc': 'Select the categories you work in', 'profile.specialist.geography': 'Coverage areas', 'profile.specialist.geography.desc': 'Select the cities / districts where you are active', 'profile.saving': 'Saving...', 'profile.upload.error': 'Error uploading photo', 'profile.saved': 'Saved', 'profile.tab.cards': 'Portfolio', 'profile.cards.count': 'Portfolio', 'profile.cards.add': 'Add portfolio', 'profile.cards.new_title': 'New portfolio title', 'profile.cards.placeholder': 'e.g. Plumbing', 'profile.cards.create': 'Create', 'profile.cards.cancel': 'Cancel', 'profile.cards.empty': 'No portfolio yet', 'profile.cards.create_first': 'Create your first portfolio', 'profile.cards.delete_confirm': 'Delete portfolio?', 'profile.card.tab.main': 'General', 'profile.card.tab.skills': 'Skills', 'profile.card.tab.categories': 'Categories', 'profile.card.tab.geography': 'Geography', 'profile.card.tab.portfolio': 'Portfolio', 'profile.card.active': 'Active', 'profile.card.save': 'Save', 'profile.card.saved': 'Saved', 'profile.card.delete': 'Delete', 'profile.card.skill.add': 'Add skill', 'profile.card.photo.add': 'Add photo', 'profile.card.photo.uploading': 'Uploading...', 'profile.card.photo.empty': 'No photos yet', 'profile.card.item.title': 'Title', 'profile.card.item.desc': 'Description', 'profile.card.item.save': 'Save', 'profile.card.item.cancel': 'Cancel', 'profile.card.item.edit': 'Edit', 'profile.upgrade.cards_limit': 'Portfolio limit reached', 'profile.upgrade.plan': 'Current plan:', 'profile.upgrade.contact': 'Contact the administrator to change your plan', 'profile.upgrade.ok': 'Got it', 'profile.plan.title': 'Subscription plan', 'profile.balance': 'Balance', 'profile.balance.topup': 'Top Up Balance', 'profile.balance.topup.title': 'Top Up Balance', 'profile.balance.topup.amount': 'Amount (EUR)', 'profile.balance.topup.hint': 'Choose a preset or enter a custom amount', 'profile.balance.topup.submit': 'Proceed to Payment', 'profile.balance.topup.loading': 'Redirecting...', 'profile.balance.topup.error': 'Payment initiation failed. Please try again.', 'payment.success.title': 'Payment Successful!', 'payment.success.desc': 'Your balance has been updated.', 'payment.cancelled.title': 'Payment Cancelled', 'payment.cancelled.desc': 'Payment was cancelled. No charges were made.', 'payment.pending.title': 'Processing...', 'payment.pending.desc': 'Your payment is being processed.', 'payment.back_to_profile': 'Back to Profile', 'profile.plan.basic': 'Basic (free)', 'profile.plan.contact_upgrade': 'Contact admin to upgrade your plan', 'profile.plan.cards_up_to': 'Portfolio: up to', 'profile.plan.cards_unlimited': 'Portfolio: unlimited', 'profile.plan.tasks_up_to': 'Tasks: up to', 'profile.plan.offers_up_to': 'Offers: up to', 'profile.plan.valid_until': 'Valid until', 'profile.plan.no_expiry': 'No expiry', // Create task 'create.error': 'Error posting task', // Tasks list extras 'tasks.category.general': 'General', 'tasks.budget.range': 'Range:', 'tasks.budget.from': 'from', 'tasks.budget.to': 'to', 'tasks.filter.reset': 'Reset filters', 'tasks.load_more': 'Load more', 'tasks.showing': 'Results:', 'tasks.field.budget': 'Budget, €', // Admin 'admin.title': 'Admin Panel', 'admin.tab.stats': 'Statistics', 'admin.tab.users': 'Users', 'admin.tab.tasks': 'Tasks', 'admin.tab.reports': 'Reports', 'admin.stats.users': 'Users', 'admin.stats.tasks': 'Tasks', 'admin.stats.offers': 'Offers', 'admin.stats.reviews': 'Reviews', 'admin.tasks.by_status': 'Tasks by status', 'admin.col.user': 'User', 'admin.col.email': 'Email', 'admin.col.role': 'Role', 'admin.col.registered': 'Registered', 'admin.col.status': 'Status', 'admin.col.title': 'Title', 'admin.col.budget': 'Budget', 'admin.col.created': 'Created', 'admin.users.active': 'Active', 'admin.users.inactive': 'Inactive', 'admin.users.deactivate': 'Deactivate', 'admin.users.activate': 'Activate', 'admin.tasks.cancel': 'Cancel', 'admin.reports.none': 'No reports', 'admin.reports.reviewed': 'Reviewed', 'admin.reports.dismiss': 'Dismiss', 'admin.pagination.total': 'Total', 'admin.users.role.change': 'Change role', 'admin.users.search.placeholder': 'Search name or email...', 'admin.tasks.delete': 'Delete', 'admin.tasks.delete.confirm': 'Permanently delete this task?', 'admin.tasks.search.placeholder': 'Search title...', 'admin.col.customer': 'Customer', 'admin.col.reporter': 'Reporter', 'admin.col.target': 'Target', 'admin.filter.all_roles': 'All roles', 'admin.filter.all_statuses': 'All statuses', 'admin.reports.target.task': 'Task', 'admin.reports.target.user': 'User', 'admin.tab.categories': 'Categories', 'admin.tab.locations': 'Cities & Districts', 'admin.tab.logs': 'Logs', 'admin.tab.plans': 'Plans', 'admin.tab.settings': 'Settings', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Activity', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Notifications', 'admin.notif_logs.type': 'Type', 'admin.notif_logs.title': 'Title', 'admin.notif_logs.read': 'Read', 'admin.notif_logs.empty': 'No notification logs', 'admin.stats.notif_chart_title': 'Notifications per day', 'admin.stats.notif_label': 'Notifications', 'admin.stats.mail_chart_title': 'Emails per day', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'All', 'admin.stats.specialists': 'Specialists', 'admin.col.plan': 'Plan', 'admin.back_home': 'Home', 'admin.plans.title': 'Subscription plans', 'admin.plans.add': '+ New plan', 'admin.plans.empty': 'No plans created', 'admin.plans.form.new': 'New plan', 'admin.plans.form.edit': 'Edit plan', 'admin.plans.form.name': 'Name', 'admin.plans.form.price': 'Price (EUR)', 'admin.plans.form.old_price': 'Old price (EUR, optional)', 'admin.plans.form.max_offers': 'Max offers (empty = no limit)', 'admin.plans.form.max_cards': 'Max portfolio (empty = no limit)', 'admin.plans.form.duration_days': 'Duration (days, empty = no expiry)', 'admin.plans.form.description': 'Description', 'admin.plans.form.features': 'Features (one per line)', 'admin.plans.form.notify': 'Notify about new tasks', 'admin.plans.form.default': 'Default', 'admin.plans.form.active': 'Active', 'admin.plans.form.order': 'Order', 'admin.plans.form.role': 'Role', 'admin.plans.form.tier': 'Tier', 'admin.plans.form.role.customer': 'Customer', 'admin.plans.form.role.specialist': 'Specialist', 'admin.plans.form.tier.free': 'Free', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Limits (empty = unlimited)', 'admin.plans.form.max_messages_day': 'Max Messages/Day', 'admin.plans.form.max_orders_day': 'Max Orders/Day', 'admin.plans.form.max_skills': 'Max Skills', 'admin.plans.form.max_profiles': 'Max Profiles', 'admin.plans.form.max_portfolio': 'Max Portfolio Items', 'admin.plans.form.section.boost': 'Multipliers & Boost', 'admin.plans.form.search_boost': 'Search Boost', 'admin.plans.form.offers_multiplier': 'Offers Multiplier', 'admin.plans.form.section.contact': 'Contact Permissions', 'admin.plans.form.can_contact_free': 'Contact Free Plan users', 'admin.plans.form.can_contact_pro': 'Contact Pro Plan users', 'admin.plans.form.can_contact_all': 'Contact All users', 'admin.plans.form.can_show_contact': 'Show Contact Info', 'admin.plans.form.can_view_phone': 'View Phone', 'admin.plans.form.section.features': 'Feature Flags', 'admin.plans.form.upload_video': 'Upload Video', 'admin.plans.form.favorites': 'Favorites', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Verified Badge', 'admin.plans.form.highlighted_reviews': 'Highlighted Reviews', 'admin.plans.form.personal_site': 'Personal Site', 'admin.plans.form.can_help_now': 'Can Help Now Status', 'admin.plans.form.need_help': 'Need Help Status', 'admin.plans.form.auto_response': 'Auto Response', 'admin.plans.form.auto_match': 'Auto Match', 'admin.plans.form.instant_dispatch_free': 'Instant Dispatch (Free)', 'admin.plans.form.instant_dispatch_pro': 'Instant Dispatch (Pro)', 'admin.plans.badge.default': 'Default', 'admin.plans.badge.inactive': 'Inactive', 'admin.plans.make_default': 'Set as default', 'admin.plans.tasks': 'Tasks', 'admin.plans.offers': 'Offers', 'admin.plans.cards': 'Portfolio', 'admin.plans.notify_tasks': 'Task notifications', 'admin.plans.delete.confirm': 'Delete plan', 'admin.activity.title': 'Activity log', 'admin.activity.event': 'Event', 'admin.activity.all_events': 'All events', 'admin.activity.from': 'From', 'admin.activity.to': 'To', 'admin.activity.reset': 'Reset', 'admin.activity.total': 'Total', 'admin.activity.empty': 'No records', 'admin.mail.event': 'Email event', 'admin.mail.all_events': 'All email events', 'admin.mail.from': 'From', 'admin.mail.to': 'To', 'admin.mail.reset': 'Reset', 'admin.mail.total': 'Total', 'admin.mail.empty': 'No email logs', 'admin.mail.recipient': 'Recipient', 'admin.mail.provider': 'Provider', 'admin.mail.details': 'Details', 'admin.mail.status': 'Status', 'admin.mail.success': 'Success', 'admin.mail.failed': 'Failed', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'No records', 'admin.logs.date': 'Date', 'admin.logs.provider': 'Provider', 'admin.logs.model': 'Model', 'admin.logs.action': 'Action', 'admin.logs.langs': 'Languages', 'admin.logs.in': 'In', 'admin.logs.out': 'Out', 'admin.logs.total': 'Total', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Status', 'admin.stats.activity_30d': 'Activity over 30 days', 'admin.stats.tasks_label': 'Tasks', 'admin.stats.users_label': 'Users', 'admin.stats.specialists_label': 'Specialists', 'admin.stats.tokens_title': 'Token usage (by month)', 'admin.stats.tokens_out': 'Output', 'admin.stats.tokens_in': 'Input', 'admin.stats.tokens_out_label': 'Output tokens', 'admin.stats.tokens_in_label': 'Input tokens', 'admin.stats.cost_label': 'Cost (USD)', 'admin.stats.tasks_by_status': 'Tasks by status', 'admin.task_status.open': 'Open', 'admin.task_status.in_progress': 'In progress', 'admin.task_status.completed': 'Completed', 'admin.task_status.cancelled': 'Cancelled', 'admin.task_status.draft': 'Drafts', 'admin.settings.tab.general': 'General', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Notifications', 'admin.settings.tab.payment': 'Payment', 'admin.settings.tab.referral': 'Referrals', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Socials', 'admin.settings.socials.title': 'Social Network Links', 'admin.settings.socials.hint': 'Filled links are displayed in the site footer', 'admin.settings.seo.maintenance_label': 'Maintenance Mode', 'admin.settings.seo.maintenance_hint': 'Show a maintenance page to all visitors', 'admin.settings.seo.indexing_label': 'Search Engine Indexing', 'admin.settings.seo.indexing_hint': 'Allow search engines to index the site', 'admin.settings.seo.head_scripts_label': ' Scripts (JS)', 'admin.settings.seo.head_scripts_hint': 'Runs on every page (Google Tag Manager, analytics, etc.)', 'admin.settings.seo.site_title_label': 'Site Title', 'admin.settings.seo.site_description_label': 'Site Description (meta description)', 'admin.settings.referral.title': 'Referral program', 'admin.settings.referral.hint': 'Reward users who bring new registrations.', 'admin.settings.referral.enabled_label': 'Enabled', 'admin.settings.referral.enabled_hint': 'Enable / disable reward application', 'admin.settings.referral.customer_section': 'For customers', 'admin.settings.referral.specialist_section': 'For specialists', 'admin.settings.referral.plan_label': 'Reward plan', 'admin.settings.referral.no_plan': '— no plan —', 'admin.settings.referral.plan_hint': 'This plan will be assigned to the referrer. If their current plan is higher, only days will be added.', 'admin.settings.referral.days_label': 'Reward days', 'admin.settings.referral.days_hint': 'Number of days added to the plan expiry.', 'admin.settings.general.title': 'General settings', 'admin.settings.general.site_name': 'Site name', 'admin.settings.general.site_url': 'Site URL', 'admin.settings.general.contact_email': 'Contact email', 'admin.settings.general.support_phone': 'Support phone', 'admin.settings.smtp.title': 'SMTP settings', 'admin.settings.smtp.hint': 'Used to send email notifications.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Port', 'admin.settings.smtp.encryption': 'Encryption', 'admin.settings.smtp.enc.none': 'None', 'admin.settings.smtp.enc.tls': 'STARTTLS (port 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (port 465)', 'admin.settings.smtp.username': 'Username', 'admin.settings.smtp.password': 'Password / App Password', 'admin.settings.smtp.from_name': 'Sender name', 'admin.settings.smtp.from_email': 'Sender email', 'admin.settings.smtp.test': 'Send test email', 'admin.settings.smtp.sending': 'Sending...', 'admin.settings.payment.hint': 'ePay Piraeus Bank credentials.', 'admin.settings.env.test': 'Test (sandbox)', 'admin.settings.env.prod': 'Production', 'admin.settings.env.label': 'Environment', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Active', 'admin.settings.saving': 'Saving...', 'admin.settings.saved': 'Saved', 'admin.notif.vars_hint': 'Available variables in templates', 'admin.notif.tmpl.not_set': 'Template not configured', 'admin.notif.tmpl.subject_label': 'Email subject', 'admin.notif.tmpl.body_label': 'Email body (HTML)', 'admin.notif.tmpl.save': 'Save', 'admin.notif.tmpl.close': 'Close', 'admin.notif.tmpl.translate': 'Auto-translate to other languages', 'admin.notif.tmpl.translating': 'Translating...', 'admin.notif.tmpl.saving': 'Saving...', 'admin.notif.email_verification': 'Email verification', 'admin.notif.registration_success': 'Successful registration', 'admin.notif.password_reset': 'Password reset', 'admin.notif.new_offer': 'New offer', 'admin.notif.new_task': 'New task', 'admin.notif.offer_accepted': 'Offer accepted', 'admin.notif.new_message': 'New message', 'admin.notif.offer_declined': 'Offer declined', 'admin.notif.offer_other_accepted': 'Another specialist chosen', 'admin.notif.task_updated': 'Task updated', 'admin.notif.deadline_reminder': 'Deadline reminder', 'admin.notif.task_archived': 'Task unpublished automatically', 'admin.notif.referral_reward': 'Referral reward', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Plan activated', 'admin.email_template.plan_upgraded': 'Plan upgraded', 'admin.email_template.plan_downgrade_scheduled': 'Downgrade scheduled', 'admin.email_template.plan_downgrade_applied': 'Downgrade applied', 'admin.email_template.plan_renewal_reminder': 'Renewal reminder', 'admin.email_template.plan_insufficient_funds': 'Insufficient funds warning', // Pricing confirm modal 'pricing.confirm.title': 'Confirm plan selection', 'pricing.confirm.plan': 'Plan', 'pricing.confirm.prorated': 'Prorated credit', 'pricing.confirm.effective_price': 'Amount due', 'pricing.confirm.your_balance': 'Your balance', 'pricing.confirm.downgrade_info': 'The switch to the new plan will happen automatically after the current period ends.', 'pricing.confirm.insufficient': 'Insufficient balance.', 'pricing.confirm.top_up': 'Top up', 'pricing.confirm.schedule_downgrade': 'Schedule downgrade', 'pricing.confirm.pay': 'Pay', 'admin.user_edit.title': 'Edit user', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email verified', 'admin.user_edit.email_not_verified': 'Email not verified', 'admin.user_edit.verify_email_btn': 'Verify manually', 'admin.user_edit.verify_email_done': 'Email verified!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Registered', 'admin.user_edit.last_seen': 'Last seen', 'admin.user_edit.lang': 'Language', 'admin.user_edit.first_name': 'First name', 'admin.user_edit.last_name': 'Last name', 'admin.user_edit.phone': 'Phone', 'admin.user_edit.bio': 'Bio', 'admin.user_edit.role': 'Role', 'admin.user_edit.plan': 'Plan', 'admin.user_edit.no_plan': '— No plan —', 'admin.user_edit.active': 'Active account', 'admin.user_edit.balance': 'Balance (EUR)', 'admin.user_edit.skills': 'Skills', 'admin.user_edit.tab.profile': 'Profile', 'admin.user_edit.tab.account': 'Account', 'admin.user_edit.tab.balance': 'Balance', 'admin.user_edit.tab.settings': 'Settings', 'admin.user_edit.tab.specialist': 'Portfolio', 'admin.user_edit.tab.site': 'Website', 'admin.user_edit.plan_expires': 'Plan expires', 'admin.user_edit.interface_lang': 'Interface language', 'admin.user_edit.comm_languages': 'Communication languages', 'admin.user_edit.personal_site_slug': 'Personal page', 'admin.user_edit.show_contact_info': 'Show contact info', 'admin.user_edit.show_contact_info.hint': 'Visible to customers', 'admin.user_edit.notify_new_tasks': 'Notify about new tasks', 'admin.user_edit.notify_new_tasks.hint': 'Push and email notifications', 'admin.user_edit.notif_messages': 'Message notifications', 'admin.user_edit.notif_messages.hint': 'New messages in chat', 'admin.user_edit.site_settings': 'Personal page settings', 'admin.user_edit.categories': 'Service categories', 'admin.user_edit.locations': 'Service areas', 'admin.user_edit.skill_placeholder': 'New skill...', 'admin.user_edit.add_category': '— Select category —', 'admin.user_edit.add_location': '— Select location —', 'admin.user_edit.specialist_cards': 'Portfolio', 'admin.user_edit.no_cards': 'No portfolio found', 'admin.user_edit.card_title': 'Portfolio title', 'admin.user_edit.card_description': 'Description', 'admin.balance.topup.btn': 'Top up', 'admin.balance.withdraw.btn': 'Withdraw', 'admin.balance.modal_hint': 'Changes take effect immediately and are recorded in history', 'admin.balance.topup.title': 'Top up balance', 'admin.balance.topup.amount': 'Amount', 'admin.balance.topup.description': 'Comment', 'admin.balance.topup.description.placeholder': 'For example: bonus or manual top-up', 'admin.balance.topup.submit': 'Top up balance', 'admin.balance.withdraw.title': 'Withdraw balance', 'admin.balance.withdraw.amount': 'Amount', 'admin.balance.withdraw.description': 'Comment', 'admin.balance.withdraw.description.placeholder': 'For example: refund or manual debit', 'admin.balance.withdraw.submit': 'Withdraw from balance', 'admin.user_edit.role.customer': 'Customer', 'admin.user_edit.role.specialist': 'Specialist', 'admin.user_edit.role.admin': 'Administrator', 'common.refresh': 'Refresh', 'common.back_home': 'Home', 'admin.loc.hint': 'Manage cities and districts', 'admin.loc.add_city': 'New city', 'admin.loc.add_district': 'Add district', 'admin.loc.new': 'New location', 'admin.loc.edit': 'Edit location', 'admin.loc.district': 'district', 'admin.loc.empty': 'No locations', 'admin.loc.delete.confirm': 'Delete location? All districts will also be deleted.', 'admin.cat.add_root': 'New category', 'admin.cat.add_sub': 'Subcategory', 'admin.cat.edit': 'Edit', 'admin.cat.delete': 'Delete', 'admin.cat.delete.confirm': 'Delete category? All subcategories will also be deleted.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Icon', 'admin.cat.name_el': 'Greek', 'admin.cat.name_en': 'English', 'admin.cat.name_ru': 'Russian', 'admin.cat.order': 'Order', 'admin.cat.active': 'Active', 'admin.cat.parent': 'Parent category', 'admin.cat.no_parent': 'Top level', 'admin.cat.save': 'Save', 'admin.cat.cancel': 'Cancel', 'admin.cat.empty': 'No categories', 'admin.cat.hint': 'Manage categories with multi-level hierarchy', 'admin.cat.new': 'New category', 'admin.cat.subcategory': 'subcategory', 'admin.cat.add_child': 'Add subcategory', 'admin.cat.inactive': 'Inactive', 'admin.event.user_login': 'Login', 'admin.event.user_register': 'Registration', 'admin.event.admin_user_deactivate': 'User blocked', 'admin.event.admin_user_activate': 'User activated', 'admin.event.admin_user_role_changed': 'Role changed', 'admin.event.admin_task_cancelled': 'Task cancelled', 'admin.event.admin_task_deleted': 'Task deleted', 'admin.event.admin_report_reviewed': 'Report reviewed', 'admin.event.admin_report_dismissed': 'Report dismissed', 'admin.event.task_created': 'Task created', // User status 'user.online': 'Online', 'user.seen_minutes': 'was here {n} min ago', 'user.seen_hours': 'was here {n} hr ago', 'user.seen_yesterday': 'was here yesterday', 'user.seen_days': 'was here {n} days ago', // Specialists 'specialists.title': 'Specialists', 'specialists.search': 'Search specialist...', 'specialists.search.btn': 'Search', 'specialists.empty': 'No specialists found', 'specialists.no_bio': 'No description', 'specialists.view': 'View profile', 'specialists.reviews': 'reviews', 'specialist.favorite': 'Add to favorites', 'specialist.unfavorite': 'Remove from favorites', 'specialist.site_link': 'Personal site', 'favorites.specialists.title': 'Favourite specialists', 'favorites.specialists.empty': 'No favourite specialists yet', 'nav.favorites': 'Favourites', 'nav.schedule': 'Schedule', 'nav.find_tasks': 'Find Orders', 'schedule.title': 'My Schedule', 'schedule.subtitle': 'Mark the days when you are free or busy — clients will see your availability', 'schedule.available': 'Available', 'schedule.busy': 'Busy', 'schedule.unset': 'Not set', 'schedule.click_hint': '← click to cycle status', 'schedule.range_mode': 'Select range', 'schedule.range_from': 'From {date} — select end date', 'schedule.click_to_set': 'Click to set', 'schedule.free': 'free', 'schedule.busy_count': 'busy', 'schedule.free_days': 'free days', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Connect Google Calendar', 'schedule.disconnectGoogle': 'Disconnect', 'schedule.connectedAs': 'Connected as', 'schedule.importFromGoogle': 'Sync from Google', 'schedule.gcalConnected': '\u2713 Google Calendar connected', 'schedule.gcalError': 'Google Calendar connection error', 'schedule.gcalImportDone': 'Imported {n} days from Google Calendar', 'schedule.gcalAutoSyncNote': 'Availability changes are automatically synced to Google Calendar', 'schedule.gcalConnectDesc': 'Connect Google Calendar to automatically sync your availability', 'schedule.gcalDisconnectConfirm': 'Disconnect Google Calendar?', 'find_tasks.title': 'Find Orders', 'find_tasks.for_me': 'For me', 'find_tasks.all': 'All orders', 'find_tasks.by_category': 'By category', 'find_tasks.list': 'List', 'find_tasks.already_offered': 'Offer sent', 'find_tasks.offer_now': 'Make an offer', 'find_tasks.empty_for_me': 'No tasks found in your categories', 'find_tasks.banner_hint': 'Find tasks matching your portfolio categories', 'find_tasks.no_cards': 'Create a specialist portfolio to see tasks matched to you', 'find_tasks.add_card': 'Create portfolio', 'find_tasks.search': 'Search tasks...', 'find_tasks.tasks_count': 'tasks', 'footer.tagline': 'The task platform for Greece', 'footer.rights': 'All rights reserved.', // App download section 'app.download_title': 'Download the CanHelp mobile app', 'app.download_desc': 'All of CanHelp — always at your fingertips. Available for Android and iOS.', // Nav 'nav.pricing': 'Pricing', // Pricing page 'pricing.title': 'Pricing', 'pricing.subtitle': 'Choose the right plan for you', 'pricing.role.customer': 'Customer', 'pricing.role.specialist': 'Specialist', 'pricing.free': 'Free', 'pricing.per_month': 'mo', 'pricing.duration': 'Duration', 'pricing.days': 'days', 'pricing.current_plan': 'Your plan', 'pricing.popular': 'Popular', 'pricing.choose': 'Choose', 'pricing.your_plan': 'Active plan', 'pricing.free_default': 'Default', 'pricing.compare': 'Compare features', 'pricing.feature': 'Feature', 'pricing.faq_note': 'Payment is deducted from your CanHelp balance. Top up available in Payments.', 'pricing.feat.messages': 'Messages / day', 'pricing.feat.orders': 'Orders / day', 'pricing.feat.contact_all': 'Contact everyone', 'pricing.feat.view_phone': 'View phone number', 'pricing.feat.show_contact': 'Show contact info', 'pricing.feat.favorites': 'Favorites', 'pricing.feat.verified_badge': 'Verified badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Personal site', 'pricing.feat.auto_response': 'Auto-response', 'pricing.feat.auto_match': 'Auto-match', 'pricing.feat.highlighted_reviews': 'Highlighted reviews', 'pricing.feat.portfolio': 'Portfolio items', 'pricing.feat.cards': 'Specialist cards', 'pricing.feat.notify_tasks': 'New task notifications', 'pricing.feat.video': 'Video in portfolio', // Upgrade prompt 'upgrade.available_in': 'Available in', 'upgrade.cta': 'Upgrade', // Dashboard plan block 'dashboard.plan.title': 'My Plan', 'dashboard.plan.expires': 'Expires in {n} days', 'dashboard.plan.upgrade': 'Upgrade plan', 'dashboard.plan.no_plan': 'Free plan', 'dashboard.plan.messages': 'Messages today', 'dashboard.plan.orders': 'Orders today', 'dashboard.plan.limits': 'Daily limits', 'dashboard.plan.features': 'Features', 'dashboard.plan.stats': 'Stats', 'dashboard.stats.cards': 'Portfolios', 'dashboard.stats.maxCards': 'Max portfolios', 'dashboard.stats.portfolioItems': 'Portfolio items', 'dashboard.stats.maxPortfolioItems': 'Max items', 'dashboard.stats.activeOffers': 'Active offers', 'dashboard.stats.reviewsReceived': 'Reviews', 'dashboard.stats.activeTasks': 'Active tasks', 'dashboard.stats.completedTasks': 'Completed', 'status.need_help': 'I need help', 'status.active': 'Active', 'status.toggle_on': 'Enable', 'status.toggle_off': 'Disable', // FOMO 'fomo.missed_orders': 'Missed {n} orders', 'fomo.missed_value': 'Worth €{v}', 'fomo.upgrade_hint': 'Upgrade to receive more orders', 'fomo.conversion': 'Task conversion', 'fomo.active': 'Active', 'fomo.with_offers': 'With offers', 'fomo.completed': 'Completed', 'fomo.already_offered': '{n} specialists have already responded', 'fomo.specialist_missed': 'You missed {n} orders', 'fomo.top_categories': 'Categories', 'fomo.offers_received': 'offers received', 'fomo.avg_offers': 'Avg {n}/task', 'fomo.completion_rate': 'completed', // Task auto-match 'task.auto_match': 'Auto-match', 'task.auto_match_results': 'Top specialists', 'task.no_offer_yet': 'You haven\'t sent an offer yet', 'task.make_offer': 'Send offer', 'auto_response.title': 'Auto-Response', 'auto_response.enabled': 'Enable auto-response', 'auto_response.min_budget': 'Min budget', 'auto_response.max_budget': 'Max budget', 'auto_response.default_price': 'Default price', 'auto_response.default_message': 'Default message', 'auto_response.max_per_day': 'Max auto-offers per day', 'auto_response.save': 'Save', 'auto_response.saved': 'Saved', 'auto_response.categories': 'Categories', 'auto_response.locations': 'Locations', // Personal site 'profile.personal_site': 'Personal Site', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Only latin letters, numbers, - and _', 'profile.site_open': 'Open site', 'profile.site_preview': 'Your site', 'profile.show_contact': 'Show contact info', 'profile.show_contact_hint': 'Customers with Pro/Ultimate plans will see your phone number', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Calendar requires a Pro or Ultimate plan', // Chat limits 'chat.limit_warning': '{n} messages left today', 'chat.limit_reached': 'Message limit reached. Upgrade your plan', 'chat.upgrade': 'Upgrade', // Site page 'site.member_since': 'Member since', 'site.rating': 'Rating', 'site.completed_tasks': 'Completed', 'site.languages': 'Languages', 'site.photos': 'photos', 'site.contact_form': 'Get in touch', 'site.contact_sent': 'Message sent!', 'site.contact_sent_desc': 'The specialist will contact you soon', 'site.contact_name': 'Name', 'site.contact_name_ph': 'Your name', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Message', 'site.contact_message_ph': 'Describe your task...', 'site.contact_send': 'Send', 'site.share': 'Share', 'site.speaks_languages': 'Speaks', 'site.message_sent': 'Message sent!', 'site.message_sent_desc': 'The specialist will receive it in the chat', 'site.message_placeholder': 'Write your message...', 'site.write_to_chat': 'Write to chat', 'site.auth_required_title': 'Sign in required', 'site.auth_required_desc': 'To write in the chat, you need to sign in to your CanHelp account.', 'site.auth_login_btn': 'Sign in', 'site.auth_contact_form_btn': 'Contact via feedback form', 'specialist.services': 'Services', 'portfolio.title': 'Portfolio', 'status.can_help_now': 'Available now', 'common.not_found': 'Page not found', 'common.anonymous': 'Anonymous', 'specialist_setup.page_title': 'Specialist profile setup', 'specialist_setup.step_of': 'Step {current} of {total}', 'specialist_setup.next': 'Next', 'specialist_setup.back': 'Back', 'specialist_setup.skip': 'Skip', 'specialist_setup.finish': 'Finish', 'specialist_setup.go_to_profile': 'Go to profile', 'specialist_setup.browse_tasks': 'Browse tasks', 'specialist_setup.step1.title': 'Welcome!', 'specialist_setup.step1.subtitle': "Let's set up your profile", 'specialist_setup.step1.desc': 'A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.', 'specialist_setup.step1.what_next': 'What we will do:', 'specialist_setup.step1.item1': 'Fill in basic information', 'specialist_setup.step1.item2': 'Create a service card', 'specialist_setup.step1.item3': 'Add skills and categories', 'specialist_setup.step1.item4': 'Select service area', 'specialist_setup.step1.item5': 'Upload portfolio photos', 'specialist_setup.step2.title': 'Basic profile', 'specialist_setup.step2.subtitle': 'Tell us about yourself', 'specialist_setup.step2.bio_label': 'About me', 'specialist_setup.step2.bio_placeholder': 'Describe your experience, services you offer...', 'specialist_setup.step2.phone_label': 'Phone', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Profile photo', 'specialist_setup.step2.photo_btn': 'Upload photo', 'specialist_setup.step2.photo_uploading': 'Uploading...', 'specialist_setup.step2.photo_hint': 'Shown on your profile', 'specialist_setup.step3.title': 'Service card', 'specialist_setup.step3.subtitle': 'Create your first service card', 'specialist_setup.step3.title_label': 'Card title', 'specialist_setup.step3.title_placeholder': 'E.g. Plumber, Electrician, Cleaning...', 'specialist_setup.step3.desc_label': 'Description', 'specialist_setup.step3.desc_placeholder': 'Describe in detail what you offer, your experience, advantages...', 'specialist_setup.step3.title_required': 'Title is required', 'specialist_setup.step4.title': 'Skills & Categories', 'specialist_setup.step4.subtitle': 'Add skills and select categories', 'specialist_setup.step4.skills_label': 'Skills', 'specialist_setup.step4.skills_placeholder': 'E.g. Pipe installation...', 'specialist_setup.step4.skills_add': 'Add', 'specialist_setup.step4.categories_label': 'Categories', 'specialist_setup.step5.title': 'Service area', 'specialist_setup.step5.subtitle': 'Where do you provide services?', 'specialist_setup.step5.hint': 'Select cities or specific areas', 'specialist_setup.done.title': 'Your profile is ready!', 'specialist_setup.done.subtitle': 'Congratulations! Your profile has been set up', 'specialist_setup.done.desc': 'You can now receive orders from clients. Browse tasks that match your skills.' }, ru: { 'footer.slogan': 'Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.', 'footer.links': 'Ссылки', 'footer.socials': 'Мы в соцсетях', 'nav.home': 'Главная', 'nav.tasks': 'Задачи', 'nav.post': '+ Опубликовать', 'nav.dashboard': 'Панель управления', 'nav.chat': 'Сообщения', 'nav.notifications': 'Уведомления', 'nav.profile': 'Профиль', 'nav.admin': 'Админка', 'nav.specialists': 'Специалисты', 'nav.new_task': 'Новая задача', 'nav.login': 'Войти', 'nav.register': 'Регистрация', 'nav.logout': 'Выйти', 'hero.title': 'Найди специалиста для любой работы', 'hero.subtitle': 'Опубликуй задачу, получи предложения и выбери лучшего профессионала', 'hero.cta.post': 'Опубликовать задачу', 'hero.cta.browse': 'Стать специалистом', 'hero.search.placeholder': 'Что нужно? напр. электрик, уборка...', 'stats.specialists': 'специалистов', 'stats.tasks': 'задач', 'stats.categories': 'категорий', 'stats.free': 'бесплатная регистрация', 'section.categories': 'Создай задачу в любой категории', 'section.how': 'Как это работает', 'section.recent': 'Последние задачи', 'section.all': 'Смотреть все →', 'section.more': 'ещё', 'section.cities': 'Города и районы', 'section.community': 'Общественный проект для всех', 'community.subtitle': 'CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.', 'community.point1.title': 'Умеете что-то делать?', 'community.point1.desc': 'Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.', 'community.point2.title': 'Нужна помощь?', 'community.point2.desc': 'Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.', 'community.point3.title': 'Помогите проекту расти', 'community.point3.desc': 'CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.', 'community.share': 'Поделиться с друзьями', 'community.share.copied': 'Ссылка скопирована!', // Referral section on home page 'section.referral': 'Реферальная программа', 'referral.home.subtitle': 'Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.', 'referral.home.step1.title': 'Зарегистрируйтесь и получите ссылку', 'referral.home.step1.desc': 'Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.', 'referral.home.step2.title': 'Поделитесь с друзьями', 'referral.home.step2.desc': 'Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.', 'referral.home.step3.title': 'Получайте награды', 'referral.home.step3.desc': 'Как только друг подтвердит email, вы автоматически получите свою награду.', 'referral.home.cta': 'Получить ссылку', 'referral.home.badge': 'Реферальная программа', // FAQ section 'section.faq': 'Частые вопросы', 'faq.q1': 'Как работает CanHelp?', 'faq.a1': 'Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.', 'faq.q2': 'Сколько стоит использование платформы?', 'faq.a2': 'Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.', 'faq.q3': 'Как стать специалистом?', 'faq.a3': 'Зарегистрируйтесь, перейдите в «Стать специалистом», заполните профиль навыками и категориями и начните получать задачи.', 'faq.q4': 'Как выбрать подходящего специалиста?', 'faq.a4': 'Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.', 'faq.q5': 'Что если я не доволен результатом?', 'faq.a5': 'Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.', 'faq.q6': 'Можно ли связаться со специалистом до принятия предложения?', 'faq.a6': 'Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.', 'faq.q7': 'Сколько времени ждать предложений?', 'faq.a7': 'Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.', 'faq.q8': 'Можно ли разместить задачу в любом городе Греции?', 'faq.a8': 'Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.', 'faq.q9': 'Какие виды задач есть на CanHelp?', 'faq.a9': 'Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.', 'faq.q10': 'Есть ли мобильное приложение?', 'faq.a10': 'Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.', 'how.step1.title': 'Опубликуй задачу', 'how.step1.desc': 'Опиши что нужно и установи бюджет', 'how.step2.title': 'Получи предложения', 'how.step2.desc': 'Специалисты пришлют предложения с ценой и сроками', 'how.step3.title': 'Выбери и начни', 'how.step3.desc': 'Выбери лучшего профессионала и начни сотрудничество', 'tasks.title': 'задач', 'tasks.filters': 'Фильтры', 'tasks.search': 'Поиск', 'tasks.search.placeholder': 'Название или ключевое слово...', 'tasks.search.btn': 'Поиск', 'tasks.publish': 'Опубликовать', 'tasks.category.all': 'Все', 'tasks.category.all_in': 'Все в', 'tasks.category.label': 'Категория', 'tasks.location.label': 'Город', 'tasks.location.placeholder': 'напр. Афины', 'tasks.empty': 'Задачи не найдены', 'tasks.empty.cta': 'Опубликуй первую', 'task.status.open': 'Открыта', 'task.status.in_progress': 'В работе', 'task.status.completed': 'Завершена', 'task.status.cancelled': 'Отменена', 'task.status.draft': 'Черновик', 'task.budget': 'Бюджет', 'task.location': 'Местоположение', 'task.deadline': 'Дата начала', 'task.created_at': 'Создано', 'task.customer': 'Заказчик', 'task.offer.btn': 'Отправить предложение', 'task.invite.banner_title': 'Вас пригласили на это задание', 'task.invite.banner_hint': 'Заказчик лично пригласил вас', 'task.invite.accept': 'Отправить предложение', 'task.invite.decline': 'Отказаться', 'offer.accept': 'Принять', 'offer.decline': 'Отклонить', 'task.complete': 'Завершить задачу', 'task.complete.confirm': 'Отметить задачу как выполненную?', 'task.edit': 'Редактировать', 'task.status_label': 'Статус', 'task.yours': 'Ваша задача', 'task.offer.yours': 'Ваше предложение', 'review.leave': 'Оставить отзыв', 'review.rating': 'Оценка', 'review.comment': 'Комментарий', 'review.comment.placeholder': 'Расскажите о своём опыте...', 'review.submit': 'Отправить отзыв', 'review.submitting': 'Отправка...', 'review.done': 'Отзыв отправлен!', 'profile.reviews': 'Отзывы', 'profile.no_reviews': 'Отзывов пока нет', 'profile.rating': 'Рейтинг', 'profile.skills.label': 'Навыки', 'profile.member_since': 'Участник с', 'task.offers': 'Предложения', 'task.offers.none': 'Предложений пока нет', 'create.title': 'Опубликовать задачу', 'create.field.title': 'Название', 'create.field.description': 'Описание', 'create.field.category': 'Категория', 'create.field.category.select': 'Выберите...', 'create.field.location': 'Местоположение', 'create.field.location.any': 'Где угодно', 'create.field.location.all': 'Весь город', 'create.field.budget': 'Бюджет (€)', 'create.field.deadline': 'Дата начала', 'create.field.budget_negotiable': 'Цена обсуждается', 'create.field.time_slot': 'Время выполнения', 'create.field.time_slot.any': 'В любое время', 'create.field.time_slot.morning': 'Утром (08:00–13:00)', 'create.field.time_slot.afternoon': 'Днём (13:00–18:00)', 'create.field.time_slot.evening': 'Вечером (18:00–22:00)', 'create.field.time_slot.weekend': 'Выходной', 'create.field.address': 'Адрес (необязательно)', 'create.field.address.district': 'Квартал', 'create.field.address.street': 'Улица', 'create.field.address.house': 'Дом', 'create.field.confidential': 'Конфиденциальная заметка', 'create.field.confidential.placeholder': 'Детали, видные только назначенному специалисту...', 'create.field.confidential.hint': 'Не отображается публично', 'create.field.photos': 'Фотографии', 'create.field.photos.add': 'Добавить фото', 'create.field.photos.uploading': 'Загрузка...', 'task.budget_negotiable': 'Цена обсуждается', 'task.time_slot': 'Время', 'task.confidential': 'Конфид. заметка', 'create.field.title.placeholder': 'напр. Уборка квартиры 80кв', 'create.field.description.placeholder': 'Подробно опишите что нужно...', 'create.field.location.placeholder': 'напр. Афины, Колонаки', 'create.field.budget.placeholder': 'напр. 100', 'create.submit': 'Опубликовать задачу', 'create.submitting': 'Публикация...', 'login.title': 'Добро пожаловать', 'login.subtitle': 'Вход в CanHelp', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.submitting': 'Вход...', 'login.error': 'Неверный email или пароль', 'login.unverified.title': 'Подтвердите ваш email', 'login.unverified.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'login.unverified.resend': 'Отправить письмо повторно', 'login.unverified.sending': 'Отправка...', 'login.unverified.sent': '✓ Отправлено — проверьте входящие', 'profile.email.verified': 'Email подтверждён', 'profile.email.not_verified': 'Email не подтверждён', 'login.no_account': 'Нет аккаунта?', 'login.register_link': 'Зарегистрироваться', 'login.forgot_password': 'Забыл пароль?', 'login.or_continue_with': 'или продолжите через', 'login.continue_google': 'Войти через Google', 'forgot.title': 'Забыл пароль', 'forgot.subtitle': 'Введите email для получения ссылки восстановления', 'forgot.email': 'Email', 'forgot.submit': 'Отправить ссылку', 'forgot.submitting': 'Отправка...', 'forgot.sent.title': 'Проверьте входящие', 'forgot.sent.desc': 'Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.', 'forgot.back_to_login': 'Вернуться ко входу', 'forgot.error': 'Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.', 'forgot.error.not_found': 'Аккаунт с таким email не найден.', 'forgot.error.send_failed': 'Ошибка отправки письма. Попробуйте позже.', 'reset.title': 'Новый пароль', 'reset.subtitle': 'Введите новый пароль', 'reset.password': 'Новый пароль', 'reset.confirm': 'Подтвердите пароль', 'reset.submit': 'Изменить пароль', 'reset.submitting': 'Сохранение...', 'reset.success': 'Пароль успешно изменён. Перенаправление ко входу...', 'reset.back_to_login': 'Вернуться ко входу', 'reset.error.mismatch': 'Пароли не совпадают', 'reset.error.invalid': 'Недействительная или устаревшая ссылка. Запросите новую.', 'register.title': 'Регистрация', 'register.subtitle': 'Создать аккаунт в CanHelp', 'register.first_name': 'Имя', 'register.last_name': 'Фамилия', 'register.email': 'Email', 'register.password': 'Пароль (мин. 8 символов)', 'register.role': 'Роль', 'register.role.customer': 'Пользователь', 'register.role.customer.desc': 'Публикую задачи', 'register.role.specialist': 'Специалист', 'register.role.specialist.desc': 'Беру задачи', 'register.submit': 'Создать аккаунт', 'register.submitting': 'Регистрация...', 'register.has_account': 'Уже есть аккаунт?', 'register.login_link': 'Войти', 'register.continue_google': 'Зарегистрироваться через Google', 'register.check_email.title': 'Проверьте почту', 'register.check_email.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'register.check_email.login': 'Вернуться к входу', 'dashboard.title': 'Панель управления', 'dashboard.new_task': '+ Новая задача', 'dashboard.my_tasks': 'Мои задачи', 'dashboard.my_offers': 'Мои предложения', 'dashboard.invitations': 'Приглашения на задания', 'dashboard.offers_count': 'предл.', 'dashboard.declined_count': 'откл.', 'dashboard.completed_tasks': 'Завершённые задачи', 'dashboard.completed_offers': 'Завершённые предложения', 'dashboard.review_pending': 'Оценка ещё не оставлена', 'tasks.new.top_specialists': 'Топ специалисты', 'tasks.new.select_category': 'Выберите категорию, чтобы увидеть специалистов', 'tasks.new.invite': 'Предложить работу', 'tasks.new.invited': 'Выбран ✓', 'reviews.count': 'отзывов', 'filter.location': 'Локация', 'filter.language': 'Языки', 'filter.language.any': 'Любой язык', 'filter.category.all': 'Все категории', 'user.categories': 'Категории', 'user.work_area': 'Район работы', 'dashboard.tasks.empty': 'Вы не публиковали задачи', 'dashboard.tasks.empty.cta': 'Опубликуйте первую', 'dashboard.tasks.add_new': 'Добавить новую задачу', 'dashboard.offers.empty': 'Вы не отправляли предложений', 'dashboard.offers.empty.cta': 'Найти задачи', 'dashboard.customer.specialists_title': 'Ищете исполнителя?', 'dashboard.customer.specialists_hint': 'Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи', 'dashboard.customer.specialists_cta': 'Найти исполнителя', 'dashboard.customer.how_title': 'Как это работает', 'dashboard.customer.step1': 'Создайте задачу с описанием и бюджетом', 'dashboard.customer.step2': 'Специалисты пришлют предложения с ценой и сроками', 'dashboard.customer.step3': 'Выберите подходящего и начните работу', 'notif.title': 'Уведомления', 'notif.mark_all': 'Отметить все как прочитанные', 'notif.empty': 'Нет уведомлений', 'notif.type.new_offer': 'Новое предложение', 'notif.type.offer_accepted': 'Ваше предложение принято', 'notif.type.offer_declined': 'Ваше предложение отклонено', 'notif.type.task_completed': 'Задание выполнено', 'notif.type.task_cancelled': 'Задание отменено', 'notif.type.new_message': 'Новое сообщение', 'notif.type.new_review': 'Новый отзыв', 'notif.type.task_invite': 'Приглашение на задание', 'notif.body.new_offer': 'Новое предложение на «{title}»', 'notif.body.offer_accepted': 'Ваше предложение на «{title}» принято', 'notif.body.offer_declined': 'Ваше предложение на «{title}» отклонено', 'notif.body.task_invite': 'Вас приглашают на «{title}»', 'notif.body.new_review': 'Вы получили оценку {rating}★', 'offer.status.pending': 'Ожидает', 'offer.status.accepted': 'Принято', 'offer.status.declined': 'Отклонено', 'offer.status.withdrawn': 'Отозвано', 'offer.status.other_accepted': 'Выбран другой исполнитель', 'common.loading': 'Загрузка...', 'common.error': 'Ошибка', 'common.save': 'Сохранить', 'common.saving': 'Сохранение...', 'common.cancel': 'Отмена', 'common.add': 'Добавить', 'common.close': 'Закрыть', 'common.edit': 'Редактировать', 'common.delete': 'Удалить', 'common.from': 'от', 'common.currency': '€', 'common.greece': 'Греция', // Chat 'chat.connected': 'Подключено', 'chat.disconnected': 'Отключено', 'chat.no_rooms': 'Переписок пока нет', 'chat.task_fallback': 'Задача', 'chat.select': 'Выберите переписку', 'chat.no_messages': 'Сообщений пока нет', 'chat.placeholder': 'Напишите сообщение... (Enter для отправки)', 'chat.conversation_fallback': 'Переписка', 'chat.direct_chat': 'Личный чат', 'chat.linked_task': 'Прикреплённый заказ', 'chat.write_btn': 'Написать', 'chat.just_now': 'только что', 'chat.min_ago': 'м', 'chat.write_specialist': 'Написать специалисту', 'chat.write_customer': 'Написать заказчику', 'chat.notif_settings': 'Настройки уведомлений', 'chat.notif_messages': 'Уведомления о новых сообщениях', 'chat.toast_title': 'Новое сообщение', 'chat.toast_open': 'Открыть чат', // Offer form 'offer.price': 'Цена', 'offer.price.placeholder': 'напр. 80', 'offer.customer_budget': 'Бюджет заказчика', 'offer.message': 'Сообщение', 'offer.optional': 'необязательно', 'offer.message.placeholder': 'Представьтесь, расскажите об опыте и почему вы лучший выбор...', 'offer.submitting': 'Отправка...', // Profile 'profile.photo': 'Фото профиля', 'profile.photo.change': 'Изменить фото', 'profile.photo.hint': 'JPEG, PNG, WebP · до 5MB', 'profile.basic_info': 'Основная информация', 'profile.phone': 'Телефон', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Краткое описание', 'profile.bio.placeholder': 'Расскажите немного о себе...', 'profile.language': 'Язык', 'profile.language.hint': 'Язык интерфейса и email-уведомлений', 'profile.languages': 'Языки общения', 'profile.languages.hint': 'Выберите все языки, на которых вы общаетесь', 'profile.skills': 'Навыки', 'profile.skills.subtitle': 'Добавьте услуги, которые вы предлагаете', 'profile.skills.placeholder': 'напр. Уборка, IT, Репетиторство...', 'profile.role': 'Роль аккаунта', 'profile.role.specialist': '🔧 Специалист', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Пользователь', 'profile.role.change': 'Для смены роли обратитесь в службу поддержки.', 'profile.become_specialist': 'Стать специалистом', 'profile.become_specialist.desc': 'Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.', 'become_specialist.hero.title': 'Зарабатывай, делая то, что умеешь', 'become_specialist.hero.subtitle': 'Создай профиль специалиста и получай заказы от клиентов по всей Греции', 'become_specialist.how.title': 'Как это работает', 'become_specialist.step1.title': 'Создай портфолио специалиста', 'become_specialist.step1.desc': 'Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы', 'become_specialist.step2.title': 'Ищи заказы', 'become_specialist.step2.desc': 'Просматривай задачи по своим категориям в разделе «Поиск заказов»', 'become_specialist.step3.title': 'Откликайся и зарабатывай', 'become_specialist.step3.desc': 'Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы', 'become_specialist.benefits.title': 'Преимущества профиля специалиста', 'become_specialist.benefit1': 'Поиск заказов по вашим категориям и локации', 'become_specialist.benefit2': 'Публичный профиль с отзывами клиентов', 'become_specialist.benefit3': 'Расписание доступности, видимое клиентам', 'become_specialist.benefit4': 'Добавление в избранное клиентами', 'become_specialist.cta': 'Подробнее', 'become_specialist.free_badge': 'Бесплатная регистрация', 'profile.tab.notifications': 'Уведомления', 'profile.tab.reviews': 'Отзывы', 'profile.tab.referral': 'Рефералы', 'profile.tab.auto_response': 'Авто-ответ', 'profile.tab.site': 'Сайт', 'profile.site.title': 'Персональная страница', 'profile.site.url_label': 'Личный сайт', 'profile.site.copy': 'Копировать', 'profile.site.copied': 'Скопировано', 'profile.site.visible_title': 'Что отображается на вашей странице', 'profile.site.visible.name': 'Имя и фото', 'profile.site.visible.bio': 'Биография', 'profile.site.visible.rating': 'Рейтинг и отзывы', 'profile.site.visible.portfolio': 'Портфолио / Карточки', 'profile.site.visible.contacts': 'Контактные данные', 'profile.site.visible.full_last_name': 'Фамилия полностью', 'profile.site.visible.services': 'Карточки услуг', 'profile.site.visible.reviews': 'Раздел с отзывами', 'profile.site.visible.status': 'Статус «Готов помочь»', 'profile.site.theme': 'Тема оформления', 'profile.site.theme.dark': 'Тёмная', 'profile.site.theme.light': 'Светлая', 'profile.site.slug_taken': 'Этот адрес уже занят', 'profile.site.stats.title': 'Аналитика сайта', 'profile.site.stats.days': 'последние 30 дней', 'profile.site.stats.views': 'Просмотры', 'profile.site.stats.unique': 'Уникальные посетители', 'profile.site.stats.messages': 'Сообщения', 'profile.site.stats.total_views': 'Просмотры', 'profile.site.stats.total_unique': 'Уник. посетители', 'profile.site.stats.total_messages': 'Сообщения', 'profile.site.stats.empty': 'Данных пока нет', 'profile.site.stats.loading': 'Загрузка аналитики...', 'profile.site.stats.no_slug': 'Укажите адрес сайта, чтобы видеть статистику', 'profile.site.edit_bio_hint': 'Биография и фото настраиваются во вкладке «Основное».', 'status.title': 'Статус', 'status.can_help_now_hint': 'Ваша карточка показывается выше в поиске', 'status.need_help_hint': 'Специалисты могут предложить вам помощь', 'profile.referral.title': 'Партнёрская программа', 'profile.referral.desc': 'Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.', 'profile.referral.link_label': 'Ваша реферальная ссылка', 'profile.referral.copy': 'Копировать', 'profile.referral.copied': 'Скопировано!', 'profile.referral.invited_count': 'успешных приглашений', 'profile.referral.no_code': 'Реферальный код недоступен.', 'notifications.title': 'Настройки уведомлений', 'notifications.email.new_tasks': 'Email о новых заказах', 'notifications.email.new_tasks.desc': 'Получать email, когда в ваших категориях публикуется новый заказ', 'notifications.messages.desc': 'Получать уведомление при новом входящем сообщении', 'notifications.saved': 'Настройки сохранены', 'notifications.plan_required': 'Недоступно в вашем тарифе', 'profile.tab.info': 'Основное', 'profile.tab.finance': 'Финансы', 'profile.tab.skills': 'Навыки', 'profile.tab.categories': 'Категории', 'profile.tab.geography': 'География', 'profile.specialist.categories': 'Категории работ', 'profile.specialist.categories.desc': 'Выберите категории, в которых вы работаете', 'profile.specialist.geography': 'Города покрытия', 'profile.specialist.geography.desc': 'Выберите города / районы, где вы работаете', 'profile.saving': 'Сохранение...', 'profile.upload.error': 'Ошибка загрузки фото', 'profile.saved': 'Сохранено', 'profile.tab.cards': 'Портфолио', 'profile.cards.count': 'Портфолио', 'profile.cards.add': 'Добавить портфолио', 'profile.cards.new_title': 'Название нового портфолио', 'profile.cards.placeholder': 'Например: Сантехника', 'profile.cards.create': 'Создать', 'profile.cards.cancel': 'Отмена', 'profile.cards.empty': 'У вас нет портфолио', 'profile.cards.create_first': 'Создать первое портфолио', 'profile.cards.delete_confirm': 'Удалить портфолио?', 'profile.card.tab.main': 'Основное', 'profile.card.tab.skills': 'Навыки', 'profile.card.tab.categories': 'Категории', 'profile.card.tab.geography': 'География', 'profile.card.tab.portfolio': 'Галерея', 'profile.card.active': 'Активна', 'profile.card.save': 'Сохранить', 'profile.card.saved': 'Сохранено', 'profile.card.delete': 'Удалить', 'profile.card.skill.add': 'Добавить навык', 'profile.card.photo.add': 'Добавить фото', 'profile.card.photo.uploading': 'Загрузка...', 'profile.card.photo.empty': 'Нет фотографий', 'profile.card.item.title': 'Заголовок', 'profile.card.item.desc': 'Описание', 'profile.card.item.save': 'Сохранить', 'profile.card.item.cancel': 'Отмена', 'profile.card.item.edit': 'Описание работы', 'profile.upgrade.cards_limit': 'Лимит портфолио исчерпан', 'profile.upgrade.plan': 'Текущий тариф:', 'profile.upgrade.contact': 'Обратитесь к администратору для смены тарифа', 'profile.upgrade.ok': 'Понятно', 'profile.plan.title': 'Тарифный план', 'profile.balance': 'Баланс', 'profile.balance.topup': 'Пополнить баланс', 'profile.balance.topup.title': 'Пополнить баланс', 'profile.balance.topup.amount': 'Сумма (в EUR)', 'profile.balance.topup.hint': 'Выберите сумму или введите вручную', 'profile.balance.topup.submit': 'Перейти к оплате', 'profile.balance.topup.loading': 'Перенаправление...', 'profile.balance.topup.error': 'Ошибка инициализации платежа. Попробуйте снова.', 'payment.success.title': 'Оплата прошла успешно!', 'payment.success.desc': 'Ваш баланс обновлён.', 'payment.cancelled.title': 'Оплата отменена', 'payment.cancelled.desc': 'Оплата была отменена. Средства не списаны.', 'payment.pending.title': 'Обрабатывается...', 'payment.pending.desc': 'Ваш платёж в обработке.', 'payment.back_to_profile': 'Вернуться в профиль', 'profile.plan.basic': 'Базовый (бесплатный)', 'profile.plan.contact_upgrade': 'Обратитесь к администратору для подключения тарифа', 'profile.plan.cards_up_to': 'Портфолио: до', 'profile.plan.cards_unlimited': 'Портфолио: безлимитно', 'profile.plan.tasks_up_to': 'Задач: до', 'profile.plan.offers_up_to': 'Откликов: до', 'profile.plan.valid_until': 'Действителен до', 'profile.plan.no_expiry': 'Бессрочно', // Create task 'create.error': 'Ошибка при публикации', // Tasks list extras 'tasks.category.general': 'Общее', 'tasks.budget.range': 'Диапазон:', 'tasks.budget.from': 'от', 'tasks.budget.to': 'до', 'tasks.filter.reset': 'Сбросить фильтры', 'tasks.load_more': 'Загрузить ещё', 'tasks.showing': 'Результатов:', 'tasks.field.budget': 'Бюджет, €', // Admin 'admin.title': 'Панель администратора', 'admin.tab.stats': 'Статистика', 'admin.tab.users': 'Пользователи', 'admin.tab.tasks': 'Задачи', 'admin.tab.reports': 'Жалобы', 'admin.stats.users': 'Пользователи', 'admin.stats.tasks': 'Задачи', 'admin.stats.offers': 'Предложения', 'admin.stats.reviews': 'Отзывы', 'admin.tasks.by_status': 'Задачи по статусу', 'admin.col.user': 'Пользователь', 'admin.col.email': 'Email', 'admin.col.role': 'Роль', 'admin.col.registered': 'Регистрация', 'admin.col.status': 'Статус', 'admin.col.title': 'Название', 'admin.col.budget': 'Бюджет', 'admin.col.created': 'Создано', 'admin.users.active': 'Активен', 'admin.users.inactive': 'Неактивен', 'admin.users.deactivate': 'Деактивировать', 'admin.users.activate': 'Активировать', 'admin.tasks.cancel': 'Отменить', 'admin.reports.none': 'Жалоб нет', 'admin.reports.reviewed': 'Рассмотрено', 'admin.reports.dismiss': 'Отклонить', 'admin.pagination.total': 'Всего', 'admin.users.role.change': 'Изменить роль', 'admin.users.search.placeholder': 'Поиск по имени или email...', 'admin.tasks.delete': 'Удалить', 'admin.tasks.delete.confirm': 'Удалить эту задачу навсегда?', 'admin.tasks.search.placeholder': 'Поиск по названию...', 'admin.col.customer': 'Заказчик', 'admin.col.reporter': 'Жалобщик', 'admin.col.target': 'Цель', 'admin.filter.all_roles': 'Все роли', 'admin.filter.all_statuses': 'Все статусы', 'admin.reports.target.task': 'Задача', 'admin.reports.target.user': 'Пользователь', 'admin.tab.categories': 'Категории', 'admin.tab.locations': 'Города и районы', 'admin.tab.logs': 'Логи', 'admin.tab.plans': 'Тарифы', 'admin.tab.settings': 'Настройки', 'admin.logs.subtab.ai': 'AI логи', 'admin.logs.subtab.activity': 'Активность', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Уведомления', 'admin.notif_logs.type': 'Тип', 'admin.notif_logs.title': 'Заголовок', 'admin.notif_logs.read': 'Прочитано', 'admin.notif_logs.empty': 'Логи уведомлений пусты', 'admin.stats.notif_chart_title': 'Уведомления по дням', 'admin.stats.notif_label': 'Уведомления', 'admin.stats.mail_chart_title': 'Email по дням', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Все', 'admin.stats.specialists': 'Исполнители', 'admin.col.plan': 'Тариф', 'admin.back_home': 'На главную', 'admin.plans.title': 'Тарифные пакеты', 'admin.plans.add': '+ Добавить тариф', 'admin.plans.empty': 'Тарифы не созданы', 'admin.plans.form.new': 'Новый тариф', 'admin.plans.form.edit': 'Редактировать тариф', 'admin.plans.form.name': 'Название', 'admin.plans.form.price': 'Цена (EUR)', 'admin.plans.form.old_price': 'Старая цена (EUR, необязательно)', 'admin.plans.form.max_offers': 'Макс. откликов (пусто = без лимита)', 'admin.plans.form.max_cards': 'Макс. портфолио (пусто = без лимита)', 'admin.plans.form.duration_days': 'Срок (дней, пусто = без истечения)', 'admin.plans.form.description': 'Описание', 'admin.plans.form.features': 'Возможности (по одной на строку)', 'admin.plans.form.notify': 'Уведомления о новых заказах', 'admin.plans.form.default': 'По умолчанию', 'admin.plans.form.active': 'Активен', 'admin.plans.form.order': 'Порядок', 'admin.plans.form.role': 'Роль', 'admin.plans.form.tier': 'Уровень', 'admin.plans.form.role.customer': 'Заказчик', 'admin.plans.form.role.specialist': 'Специалист', 'admin.plans.form.tier.free': 'Бесплатный', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Лимиты (пусто = без ограничений)', 'admin.plans.form.max_messages_day': 'Макс. сообщений/день', 'admin.plans.form.max_orders_day': 'Макс. заказов/день', 'admin.plans.form.max_skills': 'Макс. навыков', 'admin.plans.form.max_profiles': 'Макс. профилей', 'admin.plans.form.max_portfolio': 'Макс. элементов портфолио', 'admin.plans.form.section.boost': 'Множители & Буст', 'admin.plans.form.search_boost': 'Буст в поиске', 'admin.plans.form.offers_multiplier': 'Множитель откликов', 'admin.plans.form.section.contact': 'Права контактов', 'admin.plans.form.can_contact_free': 'Контакт с бесплатными пользователями', 'admin.plans.form.can_contact_pro': 'Контакт с Pro пользователями', 'admin.plans.form.can_contact_all': 'Контакт со всеми', 'admin.plans.form.can_show_contact': 'Показывать контакты', 'admin.plans.form.can_view_phone': 'Просмотр телефона', 'admin.plans.form.section.features': 'Возможности', 'admin.plans.form.upload_video': 'Загрузка видео', 'admin.plans.form.favorites': 'Избранное', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Знак верификации', 'admin.plans.form.highlighted_reviews': 'Выделенные отзывы', 'admin.plans.form.personal_site': 'Личный сайт', 'admin.plans.form.can_help_now': 'Статус «Могу помочь»', 'admin.plans.form.need_help': 'Статус «Нужна помощь»', 'admin.plans.form.auto_response': 'Автоответ', 'admin.plans.form.auto_match': 'Автоподбор', 'admin.plans.form.instant_dispatch_free': 'Мгновенная рассылка (бесплатно)', 'admin.plans.form.instant_dispatch_pro': 'Мгновенная рассылка (Pro)', 'admin.plans.badge.default': 'По умолчанию', 'admin.plans.badge.inactive': 'Неактивен', 'admin.plans.make_default': 'Сделать по умолчанию', 'admin.plans.tasks': 'Задач', 'admin.plans.offers': 'Откликов', 'admin.plans.cards': 'Портфолио', 'admin.plans.notify_tasks': 'Уведомления о заказах', 'admin.plans.delete.confirm': 'Удалить тариф', 'admin.activity.title': 'Журнал активности', 'admin.activity.event': 'Событие', 'admin.activity.all_events': 'Все события', 'admin.activity.from': 'От', 'admin.activity.to': 'До', 'admin.activity.reset': 'Сбросить', 'admin.activity.total': 'Всего', 'admin.activity.empty': 'Нет записей', 'admin.mail.event': 'Email событие', 'admin.mail.all_events': 'Все email события', 'admin.mail.from': 'От', 'admin.mail.to': 'До', 'admin.mail.reset': 'Сбросить', 'admin.mail.total': 'Всего', 'admin.mail.empty': 'Нет email логов', 'admin.mail.recipient': 'Получатель', 'admin.mail.provider': 'Провайдер', 'admin.mail.details': 'Детали', 'admin.mail.status': 'Статус', 'admin.mail.success': 'Успешно', 'admin.mail.failed': 'Ошибка', 'admin.event.email_sent': 'Email отправлен', 'admin.event.email_failed': 'Email не отправлен', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Тестовый email отправлен', 'admin.event.admin_email_test_failed': 'Тестовый email не отправлен', 'admin.logs.empty': 'Нет записей', 'admin.logs.date': 'Дата', 'admin.logs.provider': 'Провайдер', 'admin.logs.model': 'Модель', 'admin.logs.action': 'Действие', 'admin.logs.langs': 'Языки', 'admin.logs.in': 'Вход', 'admin.logs.out': 'Выход', 'admin.logs.total': 'Итого', 'admin.logs.ms': 'мс', 'admin.logs.status': 'Статус', 'admin.stats.activity_30d': 'Активность за 30 дней', 'admin.stats.tasks_label': 'Заявки', 'admin.stats.users_label': 'Пользователи', 'admin.stats.specialists_label': 'Исполнители', 'admin.stats.tokens_title': 'Расход токенов (по месяцам)', 'admin.stats.tokens_out': 'Исходящие', 'admin.stats.tokens_in': 'Входящие', 'admin.stats.tokens_out_label': 'Исходящие токены', 'admin.stats.tokens_in_label': 'Входящие токены', 'admin.stats.cost_label': 'Стоимость (USD)', 'admin.stats.tasks_by_status': 'Заявки по статусам', 'admin.task_status.open': 'Открытые', 'admin.task_status.in_progress': 'В работе', 'admin.task_status.completed': 'Завершённые', 'admin.task_status.cancelled': 'Отменённые', 'admin.task_status.draft': 'Черновики', 'admin.settings.tab.general': 'Общие', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Уведомления', 'admin.settings.tab.payment': 'Оплата', 'admin.settings.tab.referral': 'Реферальная', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Соцсети', 'admin.settings.socials.title': 'Ссылки на социальные сети', 'admin.settings.socials.hint': 'Заполненные ссылки отображаются в подвале сайта', 'admin.settings.seo.maintenance_label': 'Режим обслуживания', 'admin.settings.seo.maintenance_hint': 'Показывать страницу обслуживания всем посетителям', 'admin.settings.seo.indexing_label': 'Индексация поисковыми системами', 'admin.settings.seo.indexing_hint': 'Разрешить поисковым системам индексировать сайт', 'admin.settings.seo.head_scripts_label': 'Скрипты в (JS)', 'admin.settings.seo.head_scripts_hint': 'Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)', 'admin.settings.seo.site_title_label': 'Заголовок сайта', 'admin.settings.seo.site_description_label': 'Описание сайта (meta description)', 'admin.settings.referral.title': 'Партнёрская программа', 'admin.settings.referral.hint': 'Награждайте пользователей, приводящих новых участников.', 'admin.settings.referral.enabled_label': 'Включено', 'admin.settings.referral.enabled_hint': 'Включить / отключить выдачу наград', 'admin.settings.referral.customer_section': 'Для клиентов', 'admin.settings.referral.specialist_section': 'Для специалистов', 'admin.settings.referral.plan_label': 'Тарифный план за реферала', 'admin.settings.referral.no_plan': '— без плана —', 'admin.settings.referral.plan_hint': 'Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.', 'admin.settings.referral.days_label': 'Дней награды', 'admin.settings.referral.days_hint': 'Количество дней, добавляемых к сроку действия плана.', 'admin.settings.general.title': 'Общие настройки', 'admin.settings.general.site_name': 'Название сайта', 'admin.settings.general.site_url': 'URL сайта', 'admin.settings.general.contact_email': 'Email для связи', 'admin.settings.general.support_phone': 'Телефон поддержки', 'admin.settings.smtp.title': 'Настройки SMTP сервера', 'admin.settings.smtp.hint': 'Используется для отправки email-уведомлений.', 'admin.settings.smtp.host': 'SMTP Хост', 'admin.settings.smtp.port': 'Порт', 'admin.settings.smtp.encryption': 'Шифрование', 'admin.settings.smtp.enc.none': 'Нет', 'admin.settings.smtp.enc.tls': 'STARTTLS (порт 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (порт 465)', 'admin.settings.smtp.username': 'Имя пользователя', 'admin.settings.smtp.password': 'Пароль / App Password', 'admin.settings.smtp.from_name': 'Имя отправителя', 'admin.settings.smtp.from_email': 'Email отправителя', 'admin.settings.smtp.test': 'Отправить тестовый email', 'admin.settings.smtp.sending': 'Отправка...', 'admin.settings.payment.hint': 'Данные для подключения к ePay Piraeus Bank.', 'admin.settings.env.test': 'Тест (sandbox)', 'admin.settings.env.prod': 'Боевой режим', 'admin.settings.env.label': 'Среда', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Активен', 'admin.settings.saving': 'Сохранение...', 'admin.settings.saved': 'Сохранено', 'admin.notif.vars_hint': 'Доступные переменные в шаблонах', 'admin.notif.tmpl.not_set': 'Шаблон не настроен', 'admin.notif.tmpl.subject_label': 'Тема письма', 'admin.notif.tmpl.body_label': 'Текст письма (HTML)', 'admin.notif.tmpl.save': 'Сохранить', 'admin.notif.tmpl.close': 'Закрыть', 'admin.notif.tmpl.translate': 'Авто-перевод на другие языки', 'admin.notif.tmpl.translating': 'Перевод...', 'admin.notif.tmpl.saving': 'Сохранение...', 'admin.notif.email_verification': 'Подтверждение email адреса', 'admin.notif.registration_success': 'Успешная регистрация', 'admin.notif.password_reset': 'Восстановление пароля', 'admin.notif.new_offer': 'Новое предложение', 'admin.notif.new_task': 'Новая задача', 'admin.notif.offer_accepted': 'Предложение принято', 'admin.notif.new_message': 'Новое сообщение', 'admin.notif.offer_declined': 'Отклонение предложения', 'admin.notif.offer_other_accepted': 'Выбран другой исполнитель', 'admin.notif.task_updated': 'Изменение задания', 'admin.notif.deadline_reminder': 'Напоминание о дедлайне', 'admin.notif.task_archived': 'Автоснятие задания', 'admin.notif.referral_reward': 'Реферальная награда', // Шаблоны email для тарифов 'admin.email_template.plan_activated': 'Тарифы — активация тарифа', 'admin.email_template.plan_upgraded': 'Тарифы — повышение тарифа', 'admin.email_template.plan_downgrade_scheduled': 'Тарифы — запланированное понижение', 'admin.email_template.plan_downgrade_applied': 'Тарифы — применение понижения', 'admin.email_template.plan_renewal_reminder': 'Тарифы — напоминание о продлении', 'admin.email_template.plan_insufficient_funds': 'Тарифы — нехватка средств', // Модальное окно подтверждения тарифа 'pricing.confirm.title': 'Подтвердите выбор тарифа', 'pricing.confirm.plan': 'Тариф', 'pricing.confirm.prorated': 'Зачёт остатка', 'pricing.confirm.effective_price': 'К оплате', 'pricing.confirm.your_balance': 'Ваш баланс', 'pricing.confirm.downgrade_info': 'Переход на новый тариф произойдёт автоматически после окончания текущего периода.', 'pricing.confirm.insufficient': 'Недостаточно средств на балансе.', 'pricing.confirm.top_up': 'Пополнить', 'pricing.confirm.schedule_downgrade': 'Запланировать переход', 'pricing.confirm.pay': 'Оплатить', 'admin.user_edit.title': 'Редактирование пользователя', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email подтверждён', 'admin.user_edit.email_not_verified': 'Email не подтверждён', 'admin.user_edit.verify_email_btn': 'Подтвердить вручную', 'admin.user_edit.verify_email_done': 'Email подтверждён!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Регистрация', 'admin.user_edit.last_seen': 'Последний визит', 'admin.user_edit.lang': 'Язык', 'admin.user_edit.first_name': 'Имя', 'admin.user_edit.last_name': 'Фамилия', 'admin.user_edit.phone': 'Телефон', 'admin.user_edit.bio': 'О себе', 'admin.user_edit.role': 'Роль', 'admin.user_edit.plan': 'Тариф', 'admin.user_edit.no_plan': '— Без тарифа —', 'admin.user_edit.active': 'Активный аккаунт', 'admin.user_edit.balance': 'Баланс (EUR)', 'admin.user_edit.skills': 'Навыки', 'admin.user_edit.tab.profile': 'Профиль', 'admin.user_edit.tab.account': 'Аккаунт', 'admin.user_edit.tab.balance': 'Баланс', 'admin.user_edit.tab.settings': 'Настройки', 'admin.user_edit.tab.specialist': 'Портфолио', 'admin.user_edit.tab.site': 'Сайт', 'admin.user_edit.plan_expires': 'Тариф истекает', 'admin.user_edit.interface_lang': 'Язык интерфейса', 'admin.user_edit.comm_languages': 'Языки общения', 'admin.user_edit.personal_site_slug': 'Персональная страница', 'admin.user_edit.show_contact_info': 'Показывать контакты', 'admin.user_edit.show_contact_info.hint': 'Видно заказчикам', 'admin.user_edit.notify_new_tasks': 'Уведомлять о новых задачах', 'admin.user_edit.notify_new_tasks.hint': 'Push и email уведомления', 'admin.user_edit.notif_messages': 'Уведомления о сообщениях', 'admin.user_edit.notif_messages.hint': 'Новые сообщения в чате', 'admin.user_edit.site_settings': 'Настройки персональной страницы', 'admin.user_edit.categories': 'Категории услуг', 'admin.user_edit.locations': 'Районы обслуживания', 'admin.user_edit.skill_placeholder': 'Новый навык...', 'admin.user_edit.add_category': '— Выберите категорию —', 'admin.user_edit.add_location': '— Выберите район —', 'admin.user_edit.specialist_cards': 'Портфолио специалиста', 'admin.user_edit.no_cards': 'Портфолио не найдено', 'admin.user_edit.card_title': 'Заголовок портфолио', 'admin.user_edit.card_description': 'Описание', 'admin.balance.topup.btn': 'Пополнить', 'admin.balance.withdraw.btn': 'Списать', 'admin.balance.modal_hint': 'Изменения применяются сразу и фиксируются в истории', 'admin.balance.topup.title': 'Пополнение баланса', 'admin.balance.topup.amount': 'Сумма', 'admin.balance.topup.description': 'Комментарий', 'admin.balance.topup.description.placeholder': 'Например: бонус или ручное пополнение', 'admin.balance.topup.submit': 'Пополнить баланс', 'admin.balance.withdraw.title': 'Снятие баланса', 'admin.balance.withdraw.amount': 'Сумма', 'admin.balance.withdraw.description': 'Комментарий', 'admin.balance.withdraw.description.placeholder': 'Например: возврат или ручное списание', 'admin.balance.withdraw.submit': 'Списать баланс', 'admin.user_edit.role.customer': 'Заказчик', 'admin.user_edit.role.specialist': 'Исполнитель', 'admin.user_edit.role.admin': 'Администратор', 'common.refresh': 'Обновить', 'common.back_home': 'На главную', 'admin.loc.hint': 'Управление городами и районами', 'admin.loc.add_city': 'Новый город', 'admin.loc.add_district': 'Добавить район', 'admin.loc.new': 'Новая локация', 'admin.loc.edit': 'Редактировать локацию', 'admin.loc.district': 'район', 'admin.loc.empty': 'Нет локаций', 'admin.loc.delete.confirm': 'Удалить локацию? Все районы также будут удалены.', 'admin.cat.add_root': 'Новая категория', 'admin.cat.add_sub': 'Подкатегория', 'admin.cat.edit': 'Редактировать', 'admin.cat.delete': 'Удалить', 'admin.cat.delete.confirm': 'Удалить категорию? Все подкатегории также будут удалены.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Иконка', 'admin.cat.name_el': 'Греческий', 'admin.cat.name_en': 'Английский', 'admin.cat.name_ru': 'Русский', 'admin.cat.order': 'Порядок', 'admin.cat.active': 'Активна', 'admin.cat.parent': 'Родительская категория', 'admin.cat.no_parent': 'Верхний уровень', 'admin.cat.save': 'Сохранить', 'admin.cat.cancel': 'Отмена', 'admin.cat.empty': 'Нет категорий', 'admin.cat.hint': 'Управление категориями с многоуровневой иерархией', 'admin.cat.new': 'Новая категория', 'admin.cat.subcategory': 'подкатегория', 'admin.cat.add_child': 'Добавить подкатегорию', 'admin.cat.inactive': 'Неактивна', 'admin.event.user_login': 'Вход', 'admin.event.user_register': 'Регистрация', 'admin.event.admin_user_deactivate': 'Блокировка юзера', 'admin.event.admin_user_activate': 'Разблокировка юзера', 'admin.event.admin_user_role_changed': 'Смена роли', 'admin.event.admin_task_cancelled': 'Отмена задачи', 'admin.event.admin_task_deleted': 'Удаление задачи', 'admin.event.admin_report_reviewed': 'Жалоба рассмотрена', 'admin.event.admin_report_dismissed': 'Жалоба отклонена', 'admin.event.task_created': 'Создана задача', // User status 'user.online': 'Онлайн', 'user.seen_minutes': 'был здесь {n} мин назад', 'user.seen_hours': 'был здесь {n} ч назад', 'user.seen_yesterday': 'был здесь вчера', 'user.seen_days': 'был здесь {n} дн назад', // Specialists 'specialists.title': 'Специалисты', 'specialists.search': 'Поиск специалиста...', 'specialists.search.btn': 'Поиск', 'specialists.empty': 'Специалисты не найдены', 'specialists.no_bio': 'Без описания', 'specialists.view': 'Смотреть профиль', 'specialists.reviews': 'отзывов', 'specialist.favorite': 'Добавить в избранное', 'specialist.unfavorite': 'Убрать из избранного', 'specialist.site_link': 'Личный сайт', 'favorites.specialists.title': 'Избранные специалисты', 'favorites.specialists.empty': 'Вы ещё не добавили специалистов в избранное', 'nav.favorites': 'Избранное', 'nav.schedule': 'Расписание', 'nav.find_tasks': 'Поиск заказов', 'schedule.title': 'Моё расписание', 'schedule.subtitle': 'Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность', 'schedule.available': 'Свободен', 'schedule.busy': 'Занят', 'schedule.unset': 'Не указано', 'schedule.click_hint': '← клик меняет статус по кругу', 'schedule.range_mode': 'Выделить диапазон', 'schedule.range_from': 'С {date} — выберите конечную дату', 'schedule.click_to_set': 'Нажмите чтобы отметить', 'schedule.free': 'свободно', 'schedule.busy_count': 'занято', 'schedule.free_days': 'свободных дней', 'schedule.googleCalendar': 'Google Календарь', 'schedule.connectGoogle': 'Подключить Google Календарь', 'schedule.disconnectGoogle': 'Отключить', 'schedule.connectedAs': 'Подключено как', 'schedule.importFromGoogle': 'Синхр. из Google', 'schedule.gcalConnected': '\u2713 Google Календарь подключён', 'schedule.gcalError': 'Ошибка подключения Google Календарь', 'schedule.gcalImportDone': 'Импортировано {n} дней из Google Календарь', 'schedule.gcalAutoSyncNote': 'Изменения доступности автоматически отправляются в Google Календарь', 'schedule.gcalConnectDesc': 'Подключите Google Календарь для автоматической синхронизации расписания', 'schedule.gcalDisconnectConfirm': 'Отключить Google Календарь?', 'find_tasks.title': 'Поиск заказов', 'find_tasks.for_me': 'Для меня', 'find_tasks.all': 'Все заказы', 'find_tasks.by_category': 'По категориям', 'find_tasks.list': 'Списком', 'find_tasks.already_offered': 'Предложение отправлено', 'find_tasks.offer_now': 'Откликнуться', 'find_tasks.empty_for_me': 'Нет заказов в ваших категориях', 'find_tasks.banner_hint': 'Найдите заказы по категориям вашего портфолио', 'find_tasks.no_cards': 'Создайте портфолио специалиста, чтобы видеть подходящие заказы', 'find_tasks.add_card': 'Создать портфолио', 'find_tasks.search': 'Поиск заказов...', 'find_tasks.tasks_count': 'заданий', 'footer.tagline': 'Платформа задач для Греции', 'footer.rights': 'Все права защищены.', // App download section 'app.download_title': 'Скачайте мобильное приложение CanHelp', 'app.download_desc': 'Всё CanHelp — всегда под рукой. Доступно для Android и iOS.', // Nav 'nav.pricing': 'Тарифы', // Pricing page 'pricing.title': 'Тарифы', 'pricing.subtitle': 'Выберите подходящий план', 'pricing.role.customer': 'Заказчик', 'pricing.role.specialist': 'Специалист', 'pricing.free': 'Бесплатно', 'pricing.per_month': 'мес', 'pricing.duration': 'Срок', 'pricing.days': 'дн.', 'pricing.current_plan': 'Ваш план', 'pricing.popular': 'Популярный', 'pricing.choose': 'Выбрать', 'pricing.your_plan': 'Активный план', 'pricing.free_default': 'По умолчанию', 'pricing.compare': 'Сравнение функций', 'pricing.feature': 'Функция', 'pricing.faq_note': 'Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.', 'pricing.feat.messages': 'Сообщений / день', 'pricing.feat.orders': 'Заказов / день', 'pricing.feat.contact_all': 'Связь со всеми', 'pricing.feat.view_phone': 'Просмотр телефона', 'pricing.feat.show_contact': 'Показывать контакты', 'pricing.feat.favorites': 'Избранное', 'pricing.feat.verified_badge': 'Верифицированный бейдж', 'pricing.feat.google_calendar': 'Google Календарь', 'pricing.feat.personal_site': 'Персональный сайт', 'pricing.feat.auto_response': 'Авто-ответ', 'pricing.feat.auto_match': 'Авто-подбор', 'pricing.feat.highlighted_reviews': 'Выделенные отзывы', 'pricing.feat.portfolio': 'Элементов портфолио', 'pricing.feat.cards': 'Карточки специалиста', 'pricing.feat.notify_tasks': 'Уведомления о новых задачах', 'pricing.feat.video': 'Видео в портфолио', // Upgrade prompt 'upgrade.available_in': 'Доступно в', 'upgrade.cta': 'Улучшить', // Dashboard plan block 'dashboard.plan.title': 'Мой план', 'dashboard.plan.expires': 'Истекает через {n} дней', 'dashboard.plan.upgrade': 'Улучшить план', 'dashboard.plan.no_plan': 'Бесплатный план', 'dashboard.plan.messages': 'Сообщений сегодня', 'dashboard.plan.orders': 'Заказов сегодня', 'dashboard.plan.limits': 'Дневные лимиты', 'dashboard.plan.features': 'Функции', 'dashboard.plan.stats': 'Статистика', 'dashboard.stats.cards': 'Портфолио', 'dashboard.stats.maxCards': 'Макс. портфолио', 'dashboard.stats.portfolioItems': 'Элементы портфолио', 'dashboard.stats.maxPortfolioItems': 'Макс. элементы', 'dashboard.stats.activeOffers': 'Активные отклики', 'dashboard.stats.reviewsReceived': 'Отзывы', 'dashboard.stats.activeTasks': 'Активные задачи', 'dashboard.stats.completedTasks': 'Завершённые', 'status.need_help': 'Нужна помощь', 'status.active': 'Активен', 'status.toggle_on': 'Включить', 'status.toggle_off': 'Выключить', // FOMO 'fomo.missed_orders': 'Пропущено {n} заказов', 'fomo.missed_value': 'На сумму €{v}', 'fomo.upgrade_hint': 'Улучшите план — получайте больше заказов', 'fomo.conversion': 'Конверсия задач', 'fomo.active': 'Активные', 'fomo.with_offers': 'С офертами', 'fomo.completed': 'Завершённые', 'fomo.already_offered': '{n} специалистов уже откликнулись', 'fomo.specialist_missed': 'Вы пропустили {n} заказов', 'fomo.top_categories': 'Категории', 'fomo.offers_received': 'предложений получено', 'fomo.avg_offers': 'В среднем {n}/задача', 'fomo.completion_rate': 'завершено', // Task auto-match 'task.auto_match': 'Авто-матч', 'task.auto_match_results': 'Топ специалисты', 'task.no_offer_yet': 'Вы ещё не отправили предложение', 'task.make_offer': 'Отправить предложение', 'auto_response.title': 'Авто-ответ', 'auto_response.enabled': 'Включить авто-ответ', 'auto_response.min_budget': 'Мин. бюджет', 'auto_response.max_budget': 'Макс. бюджет', 'auto_response.default_price': 'Цена по умолчанию', 'auto_response.default_message': 'Сообщение по умолчанию', 'auto_response.max_per_day': 'Макс. авто-офертов в день', 'auto_response.save': 'Сохранить', 'auto_response.saved': 'Сохранено', 'auto_response.categories': 'Категории', 'auto_response.locations': 'Локации', // Personal site 'profile.personal_site': 'Персональный сайт', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Только латинские буквы, цифры, - и _', 'profile.site_open': 'Открыть сайт', 'profile.site_preview': 'Ваш сайт', 'profile.show_contact': 'Показывать контакты', 'profile.show_contact_hint': 'Заказчики с Pro/Ultimate-планом увидят ваш телефон', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Календарь требует план Pro или Ultimate', // Chat limits 'chat.limit_warning': 'Осталось {n} сообщений сегодня', 'chat.limit_reached': 'Лимит сообщений исчерпан. Улучшите план', 'chat.upgrade': 'Улучшить', // Site page 'site.member_since': 'С нами с', 'site.rating': 'Рейтинг', 'site.completed_tasks': 'Выполнено', 'site.languages': 'Языков', 'site.photos': 'фото', 'site.contact_form': 'Связаться', 'site.contact_sent': 'Сообщение отправлено!', 'site.contact_sent_desc': 'Специалист свяжется с вами в ближайшее время', 'site.contact_name': 'Имя', 'site.contact_name_ph': 'Ваше имя', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Сообщение', 'site.contact_message_ph': 'Опишите вашу задачу...', 'site.contact_send': 'Отправить', 'site.share': 'Поделиться', 'site.speaks_languages': 'Говорит на языках', 'site.message_sent': 'Сообщение отправлено!', 'site.message_sent_desc': 'Специалист получит его в чате', 'site.message_placeholder': 'Напишите сообщение...', 'site.write_to_chat': 'Написать в чат', 'site.auth_required_title': 'Нужна авторизация', 'site.auth_required_desc': 'Чтобы написать в чат, необходимо войти в аккаунт CanHelp.', 'site.auth_login_btn': 'Войти в аккаунт', 'site.auth_contact_form_btn': 'Написать через форму обратной связи', 'specialist.services': 'Услуги', 'portfolio.title': 'Портфолио', 'status.can_help_now': 'Готов помочь', 'common.not_found': 'Страница не найдена', 'common.anonymous': 'Анонимно', 'specialist_setup.page_title': 'Настройка профиля специалиста', 'specialist_setup.step_of': 'Шаг {current} из {total}', 'specialist_setup.next': 'Далее', 'specialist_setup.back': 'Назад', 'specialist_setup.skip': 'Пропустить', 'specialist_setup.finish': 'Завершить', 'specialist_setup.go_to_profile': 'Перейти в профиль', 'specialist_setup.browse_tasks': 'Найти задачи', 'specialist_setup.step1.title': 'Добро пожаловать!', 'specialist_setup.step1.subtitle': 'Давайте настроим ваш профиль', 'specialist_setup.step1.desc': 'Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.', 'specialist_setup.step1.what_next': 'Что мы сделаем:', 'specialist_setup.step1.item1': 'Заполним основную информацию', 'specialist_setup.step1.item2': 'Создадим карточку услуги', 'specialist_setup.step1.item3': 'Добавим навыки и категории', 'specialist_setup.step1.item4': 'Выберем географию обслуживания', 'specialist_setup.step1.item5': 'Загрузим фото портфолио', 'specialist_setup.step2.title': 'Базовый профиль', 'specialist_setup.step2.subtitle': 'Расскажите о себе', 'specialist_setup.step2.bio_label': 'О себе', 'specialist_setup.step2.bio_placeholder': 'Опишите ваш опыт, услуги которые вы предлагаете...', 'specialist_setup.step2.phone_label': 'Телефон', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Фото профиля', 'specialist_setup.step2.photo_btn': 'Загрузить фото', 'specialist_setup.step2.photo_uploading': 'Загрузка...', 'specialist_setup.step2.photo_hint': 'Отображается в вашем профиле', 'specialist_setup.step3.title': 'Карточка услуги', 'specialist_setup.step3.subtitle': 'Создайте вашу первую карточку услуги', 'specialist_setup.step3.title_label': 'Название карточки', 'specialist_setup.step3.title_placeholder': 'Напр. Сантехник, Электрик, Уборка...', 'specialist_setup.step3.desc_label': 'Описание', 'specialist_setup.step3.desc_placeholder': 'Подробно опишите что вы предлагаете, опыт, преимущества...', 'specialist_setup.step3.title_required': 'Название обязательно', 'specialist_setup.step4.title': 'Навыки и категории', 'specialist_setup.step4.subtitle': 'Добавьте навыки и выберите категории', 'specialist_setup.step4.skills_label': 'Навыки', 'specialist_setup.step4.skills_placeholder': 'Напр. Монтаж труб...', 'specialist_setup.step4.skills_add': 'Добавить', 'specialist_setup.step4.categories_label': 'Категории', 'specialist_setup.step5.title': 'География обслуживания', 'specialist_setup.step5.subtitle': 'Где вы оказываете услуги?', 'specialist_setup.step5.hint': 'Выберите города или конкретные районы', 'specialist_setup.done.title': 'Ваш профиль готов!', 'specialist_setup.done.subtitle': 'Поздравляем! Профиль настроен', 'specialist_setup.done.desc': 'Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам.' } }; function getTranslations(locale) { const t = translations[locale] ?? translations.el; return (key, fallback)=>t[key] ?? translations.el[key] ?? fallback ?? key; } {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ getTranslations), /* harmony export */ YZ: () => (/* binding */ LOCALES) /* harmony export */ }); /* unused harmony export translations */ ReplaceSourceRawSourcenexport const LOCALES = [ { code: 'el', label: 'Ελληνικά', flag: '🇬🇷' }, { code: 'en', label: 'English', flag: '🇬🇧' }, { code: 'ru', label: 'Русский', flag: '🇷🇺' } ]; export const translations = { el: { 'footer.slogan': 'Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.', 'footer.links': 'Σύνδεσμοι', 'footer.socials': 'Στα κοινωνικά δίκτυα', // Nav 'nav.home': 'Αρχική', 'nav.tasks': 'Εργασίες', 'nav.post': '+ Δημοσίευση', 'nav.dashboard': 'Πίνακας', 'nav.chat': 'Μηνύματα', 'nav.notifications': 'Ειδοποιήσεις', 'nav.profile': 'Προφίλ', 'nav.admin': 'Διαχείριση', 'nav.specialists': 'Ειδικοί', 'nav.new_task': 'Νέα εργασία', 'nav.login': 'Σύνδεση', 'nav.register': 'Εγγραφή', 'nav.logout': 'Έξοδος', // Hero 'hero.title': 'Βρες ειδικό για κάθε δουλειά', 'hero.subtitle': 'Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία', 'hero.cta.post': 'Δημοσίευσε εργασία', 'hero.cta.browse': 'Γίνε ειδικός', 'hero.search.placeholder': 'Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...', 'stats.specialists': 'ειδικοί', 'stats.tasks': 'εργασίες', 'stats.categories': 'κατηγορίες', 'stats.free': 'δωρεάν εγγραφή', // Sections 'section.categories': 'Δημιούργησε εργασία σε οποιαδήποτε κατηγορία', 'section.how': 'Πώς λειτουργεί', 'section.recent': 'Πρόσφατες εργασίες', 'section.all': 'Δες όλες →', 'section.more': 'ακόμα', 'section.cities': 'Πόλεις & Περιοχές', 'section.community': 'Ένα κοινοτικό έργο για όλους', 'community.subtitle': 'Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.', 'community.point1.title': 'Είσαι ειδικός σε κάτι;', 'community.point1.desc': 'Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.', 'community.point2.title': 'Χρειάζεσαι βοήθεια;', 'community.point2.desc': 'Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.', 'community.point3.title': 'Βοήθησε το έργο να αναπτυχθεί', 'community.point3.desc': 'Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.', 'community.share': 'Μοιράσου με φίλους', 'community.share.copied': 'Σύνδεσμος αντιγράφηκε!', // Referral section on home page 'section.referral': 'Πρόγραμμα παραπομπών', 'referral.home.subtitle': 'Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.', 'referral.home.step1.title': 'Εγγραφείσε και λάβε σύνδεσμο', 'referral.home.step1.desc': 'Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.', 'referral.home.step2.title': 'Μοιράσου με φίλους', 'referral.home.step2.desc': 'Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.', 'referral.home.step3.title': 'Κέρδισε ανταμοιβές', 'referral.home.step3.desc': 'Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.', 'referral.home.cta': 'Πάρε τον σύνδεσμό σου', 'referral.home.badge': 'Πρόγραμμα παραπομπών', // FAQ section 'section.faq': 'Συχνές Ερωτήσεις', 'faq.q1': 'Πώς λειτουργεί το CanHelp;', 'faq.a1': 'Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.', 'faq.q2': 'Πόσο κοστίζει η χρήση της πλατφόρμας;', 'faq.a2': 'Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.', 'faq.q3': 'Πώς μπορώ να γίνω ειδικός;', 'faq.a3': 'Κάνε εγγραφή, πήγαινε στο «Γίνε Ειδικός», συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.', 'faq.q4': 'Πώς επιλέγω τον κατάλληλο ειδικό;', 'faq.a4': 'Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q5': 'Τι γίνεται αν δεν είμαι ικανοποιημένος;', 'faq.a5': 'Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.', 'faq.q6': 'Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;', 'faq.a6': 'Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q7': 'Πόσος χρόνος χρειάζεται για να λάβω προσφορές;', 'faq.a7': 'Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.', 'faq.q8': 'Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;', 'faq.a8': 'Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.', 'faq.q9': 'Τι είδη εργασιών μπορώ να βρω στο CanHelp;', 'faq.a9': 'Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.', 'faq.q10': 'Υπάρχει εφαρμογή για κινητό;', 'faq.a10': 'Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.', // How it works 'how.step1.title': 'Δημοσίευσε εργασία', 'how.step1.desc': 'Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου', 'how.step2.title': 'Λάβε προσφορές', 'how.step2.desc': 'Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο', 'how.step3.title': 'Επίλεξε & ξεκίνα', 'how.step3.desc': 'Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία', // Tasks page 'tasks.title': 'εργασίες', 'tasks.filters': 'Φίλτρα', 'tasks.search': 'Αναζήτηση', 'tasks.search.placeholder': 'Τίτλος ή λέξη κλειδί...', 'tasks.search.btn': 'Αναζήτηση', 'tasks.publish': 'Δημοσίευση', 'tasks.category.all': 'Όλες', 'tasks.category.all_in': 'Όλα στην', 'tasks.category.label': 'Κατηγορία', 'tasks.location.label': 'Πόλη', 'tasks.location.placeholder': 'π.χ. Αθήνα', 'tasks.empty': 'Δεν βρέθηκαν εργασίες', 'tasks.empty.cta': 'Δημοσίευσε την πρώτη', // Task detail 'task.status.open': 'Ανοιχτή', 'task.status.in_progress': 'Σε εξέλιξη', 'task.status.completed': 'Ολοκληρωμένη', 'task.status.cancelled': 'Ακυρωμένη', 'task.status.draft': 'Πρόχειρο', 'task.budget': 'Προϋπολογισμός', 'task.location': 'Τοποθεσία', 'task.deadline': 'Ημερομηνία έναρξης', 'task.created_at': 'Δημιουργήθηκε', 'task.customer': 'Πελάτης', 'task.offer.btn': 'Υποβολή προσφοράς', 'task.invite.banner_title': 'Σας προσκαλούν σε αυτήν την εργασία', 'task.invite.banner_hint': 'Ο πελάτης σας πρόσκαλεσε προσωπικά', 'task.invite.accept': 'Αποστολή προσφοράς', 'task.invite.decline': 'Άρνηση', 'offer.accept': 'Αποδοχή', 'offer.decline': 'Απόρριψη', 'task.complete': 'Ολοκλήρωση εργασίας', 'task.complete.confirm': 'Να ολοκληρωθεί η εργασία;', 'task.edit': 'Επεξεργασία', 'task.status_label': 'Κατάσταση', 'task.yours': 'Η εργασία σου', 'task.offer.yours': 'Η προσφορά σου', 'review.leave': 'Άφησε αξιολόγηση', 'review.rating': 'Βαθμολογία', 'review.comment': 'Σχόλιο', 'review.comment.placeholder': 'Πες μας για την εμπειρία σου...', 'review.submit': 'Υποβολή αξιολόγησης', 'review.submitting': 'Αποστολή...', 'review.done': 'Η αξιολόγηση καταχωρήθηκε!', 'profile.reviews': 'Αξιολογήσεις', 'profile.no_reviews': 'Δεν υπάρχουν αξιολογήσεις ακόμα', 'profile.rating': 'Βαθμολογία', 'profile.skills.label': 'Δεξιότητες', 'profile.member_since': 'Μέλος από', 'task.offers': 'Προσφορές', 'task.offers.none': 'Δεν υπάρχουν ακόμα προσφορές', // Create task 'create.title': 'Δημοσίευση εργασίας', 'create.field.title': 'Τίτλος', 'create.field.description': 'Περιγραφή', 'create.field.category': 'Κατηγορία', 'create.field.category.select': 'Επιλέξτε...', 'create.field.location': 'Τοποθεσία', 'create.field.location.any': 'Οπουδήποτε', 'create.field.location.all': 'Ολόκληρη η πόλη', 'create.field.budget': 'Προϋπολογισμός (€)', 'create.field.deadline': 'Ημερομηνία έναρξης', 'create.field.budget_negotiable': 'Η τιμή είναι διαπραγματεύσιμη', 'create.field.time_slot': 'Χρόνος εκτέλεσης', 'create.field.time_slot.any': 'Οποιαδήποτε', 'create.field.time_slot.morning': 'Πρωινό (08:00–13:00)', 'create.field.time_slot.afternoon': 'Μεσημέρι (13:00–18:00)', 'create.field.time_slot.evening': 'Βράδυ (18:00–22:00)', 'create.field.time_slot.weekend': 'Σαββατοκύριακο', 'create.field.address': 'Διεύθυνση (προαιρετικά)', 'create.field.address.district': 'Συνοικία', 'create.field.address.street': 'Οδός', 'create.field.address.house': 'Αριθμός', 'create.field.confidential': 'Εμπιστευτική σημείωση', 'create.field.confidential.placeholder': 'Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...', 'create.field.confidential.hint': 'Δεν εμφανίζεται δημόσια', 'create.field.photos': 'Φωτογραφίες', 'create.field.photos.add': 'Προσθήκη φωτογραφίας', 'create.field.photos.uploading': 'Ανέβασμα...', 'task.budget_negotiable': 'Τιμή διαπραγματεύσιμη', 'task.time_slot': 'Χρόνος', 'task.confidential': 'Εμπιστευτική σημείωση', 'create.field.title.placeholder': 'π.χ. Καθαρισμός διαμερίσματος 80τμ', 'create.field.description.placeholder': 'Περίγραψε λεπτομερώς τι χρειάζεσαι...', 'create.field.location.placeholder': 'π.χ. Αθήνα, Κολωνάκι', 'create.field.budget.placeholder': 'π.χ. 100', 'create.submit': 'Δημοσίευση εργασίας', 'create.submitting': 'Δημοσίευση...', // Auth 'login.title': 'Καλωσόρισες', 'login.subtitle': 'Σύνδεση στο CanHelp', 'login.email': 'Email', 'login.password': 'Κωδικός', 'login.submit': 'Σύνδεση', 'login.submitting': 'Σύνδεση...', 'login.error': 'Λάθος email ή κωδικός', 'login.unverified.title': 'Επιβεβαιώστε το email σας', 'login.unverified.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.', 'login.unverified.resend': 'Αποστολή νέου email επαλήθευσης', 'login.unverified.sending': 'Αποστολή...', 'login.unverified.sent': '✓ Εστάλη — ελέγξτε τα εισερχόμενα', 'profile.email.verified': 'Email επαληθεύτηκε', 'profile.email.not_verified': 'Email δεν επαληθεύτηκε', 'login.no_account': 'Δεν έχεις λογαριασμό;', 'login.register_link': 'Εγγραφή', 'login.forgot_password': 'Ξέχασα τον κωδικό', 'login.or_continue_with': 'ή συνεχίστε με', 'login.continue_google': 'Σύνδεση με Google', 'forgot.title': 'Ξέχασα τον κωδικό', 'forgot.subtitle': 'Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης', 'forgot.email': 'Email', 'forgot.submit': 'Αποστολή', 'forgot.submitting': 'Αποστολή...', 'forgot.sent.title': 'Ελέγξτε τα εισερχόμενά σας', 'forgot.sent.desc': 'Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.', 'forgot.back_to_login': 'Επιστροφή στη σύνδεση', 'forgot.error': 'Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.', 'forgot.error.not_found': 'Δεν βρέθηκε λογαριασμός με αυτό το email.', 'forgot.error.send_failed': 'Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα', 'reset.title': 'Νέος κωδικός', 'reset.subtitle': 'Εισάγετε τον νέο σας κωδικό', 'reset.password': 'Νέος κωδικός', 'reset.confirm': 'Επιβεβαίωση κωδικού', 'reset.submit': 'Αλλαγή κωδικού', 'reset.submitting': 'Αποθήκευση...', 'reset.success': 'Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...', 'reset.back_to_login': 'Επιστροφή στη σύνδεση', 'reset.error.mismatch': 'Οι κωδικοί δεν ταιριάζουν', 'reset.error.invalid': 'Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.', 'register.title': 'Εγγραφή', 'register.subtitle': 'Δημιουργία λογαριασμού στο CanHelp', 'register.first_name': 'Όνομα', 'register.last_name': 'Επώνυμο', 'register.email': 'Email', 'register.password': 'Κωδικός (min 8 χαρακτήρες)', 'register.role': 'Ρόλος', 'register.role.customer': 'Χρήστης', 'register.role.customer.desc': 'Δημοσιεύω εργασίες', 'register.role.specialist': 'Ειδικός', 'register.role.specialist.desc': 'Αναλαμβάνω εργασίες', 'register.submit': 'Δημιουργία λογαριασμού', 'register.submitting': 'Εγγραφή...', 'register.has_account': 'Έχεις ήδη λογαριασμό;', 'register.login_link': 'Σύνδεση', 'register.continue_google': 'Εγγραφή με Google', 'register.check_email.title': 'Ελέγξτε το email σας', 'register.check_email.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.', 'register.check_email.login': 'Επιστροφή στη σύνδεση', // Dashboard 'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.new_task': '+ Νέα εργασία', 'dashboard.my_tasks': 'Οι εργασίες μου', 'dashboard.my_offers': 'Οι προσφορές μου', 'dashboard.invitations': 'Προσκλήσεις για εργασία', 'dashboard.offers_count': 'προσφορές', 'dashboard.declined_count': 'απορρίφθηκαν', 'dashboard.completed_tasks': 'Ολοκληρωμένες εργασίες', 'dashboard.completed_offers': 'Ολοκληρωμένες προσφορές', 'dashboard.review_pending': 'Η αξιολόγηση δεν έχει υποβληθεί ακόμα', 'tasks.new.top_specialists': 'Κορυφαίοι ειδικοί', 'tasks.new.select_category': 'Επιλέξτε κατηγορία για να δείτε ειδικούς', 'tasks.new.invite': 'Πρόσκληση', 'tasks.new.invited': 'Επιλέχθηκε ✓', 'reviews.count': 'αξιολογήσεις', 'filter.location': 'Τοποθεσία', 'filter.language': 'Γλώσσες', 'filter.language.any': 'Οποιαδήποτε γλώσσα', 'filter.category.all': 'Όλες οι κατηγορίες', 'user.categories': 'Κατηγορίες', 'user.work_area': 'Περιοχή εργασίας', 'dashboard.tasks.empty': 'Δεν έχεις δημοσιεύσει εργασίες', 'dashboard.tasks.empty.cta': 'Δημοσίευσε την πρώτη σου', 'dashboard.tasks.add_new': 'Πρόσθεσε νέα εργασία', 'dashboard.offers.empty': 'Δεν έχεις υποβάλλει προσφορές', 'dashboard.offers.empty.cta': 'Βρες εργασίες', 'dashboard.customer.specialists_title': 'Ψάχνεις εκτελεστή;', 'dashboard.customer.specialists_hint': 'Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου', 'dashboard.customer.specialists_cta': 'Βρες ειδικό', 'dashboard.customer.how_title': 'Πώς λειτουργεί', 'dashboard.customer.step1': 'Δημιούργησε εργασία με περιγραφή και προϋπολογισμό', 'dashboard.customer.step2': 'Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο', 'dashboard.customer.step3': 'Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία', // Notifications 'notif.title': 'Ειδοποιήσεις', 'notif.mark_all': 'Σήμανση όλων ως αναγνωσμένα', 'notif.empty': 'Δεν υπάρχουν ειδοποιήσεις', 'notif.type.new_offer': 'Νέα προσφορά', 'notif.type.offer_accepted': 'Η προσφορά σας έγινε δεκτή', 'notif.type.offer_declined': 'Η προσφορά σας απορρίφθηκε', 'notif.type.task_completed': 'Η εργασία ολοκληρώθηκε', 'notif.type.task_cancelled': 'Η εργασία ακυρώθηκε', 'notif.type.new_message': 'Νέο μήνυμα', 'notif.type.new_review': 'Νέα αξιολόγηση', 'notif.type.task_invite': 'Πρόσκληση σε εργασία', 'notif.body.new_offer': 'Νέα προσφορά για «{title}»', 'notif.body.offer_accepted': 'Η προσφορά σας για «{title}» έγινε δεκτή', 'notif.body.offer_declined': 'Η προσφορά σας για «{title}» απορρίφθηκε', 'notif.body.task_invite': 'Σας προσκαλούν για «{title}»', 'notif.body.new_review': 'Λάβατε αξιολόγηση {rating}★', // Offer status 'offer.status.pending': 'Εκκρεμεί', 'offer.status.accepted': 'Αποδεκτή', 'offer.status.declined': 'Απορρίφθηκε', 'offer.status.withdrawn': 'Αποσύρθηκε', 'offer.status.other_accepted': 'Επιλέχθηκε άλλος ειδικός', // Common 'common.loading': 'Φόρτωση...', 'common.error': 'Σφάλμα', 'common.save': 'Αποθήκευση', 'common.saving': 'Αποθήκευση...', 'common.cancel': 'Ακύρωση', 'common.add': 'Προσθήκη', 'common.close': 'Κλείσιμο', 'common.edit': 'Επεξεργασία', 'common.delete': 'Διαγραφή', 'common.from': 'από', 'common.currency': '€', 'common.greece': 'Ελλάδα', // Chat 'chat.connected': 'Συνδεδεμένος', 'chat.disconnected': 'Αποσυνδεδεμένος', 'chat.no_rooms': 'Δεν υπάρχουν συνομιλίες ακόμα', 'chat.task_fallback': 'Εργασία', 'chat.select': 'Επίλεξε συνομιλία', 'chat.no_messages': 'Δεν υπάρχουν μηνύματα', 'chat.placeholder': 'Γράψε μήνυμα... (Enter για αποστολή)', 'chat.conversation_fallback': 'Συνομιλία', 'chat.direct_chat': 'Απευθείας συνομιλία', 'chat.linked_task': 'Συνδεδεμένη εργασία', 'chat.write_btn': 'Μήνυμα', 'chat.just_now': 'μόλις τώρα', 'chat.min_ago': 'λ', 'chat.write_specialist': 'Γράψε στον ειδικό', 'chat.write_customer': 'Γράψε στον πελάτη', 'chat.notif_settings': 'Ρυθμίσεις ειδοποιήσεων', 'chat.notif_messages': 'Ειδοποιήσεις για νέα μηνύματα', 'chat.toast_title': 'Νέο μήνυμα', 'chat.toast_open': 'Άνοιγμα συνομιλίας', // Offer form 'offer.price': 'Τιμή', 'offer.price.placeholder': 'π.χ. 80', 'offer.customer_budget': 'Προϋπολογισμός πελάτη', 'offer.message': 'Μήνυμα', 'offer.optional': 'προαιρετικό', 'offer.message.placeholder': 'Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...', 'offer.submitting': 'Αποστολή...', // Profile 'profile.photo': 'Φωτογραφία προφίλ', 'profile.photo.change': 'Αλλαγή φωτογραφίας', 'profile.photo.hint': 'JPEG, PNG, WebP · έως 5MB', 'profile.basic_info': 'Βασικά στοιχεία', 'profile.phone': 'Τηλέφωνο', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Σύντομη περιγραφή', 'profile.bio.placeholder': 'Πες μας λίγα λόγια για εσένα...', 'profile.language': 'Γλώσσα', 'profile.language.hint': 'Γλώσσα διεπαφής και email ειδοποιήσεων', 'profile.languages': 'Γλώσσες επικοινωνίας', 'profile.languages.hint': 'Επιλέξτε όλες τις γλώσσες που μιλάτε', 'profile.skills': 'Δεξιότητες', 'profile.skills.subtitle': 'Προσθέσε τις υπηρεσίες που προσφέρεις', 'profile.skills.placeholder': 'π.χ. Καθαρισμός, IT, Μαθήματα...', 'profile.role': 'Ρόλος λογαριασμού', 'profile.role.specialist': '🔧 Ειδικός', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Χρήστης', 'profile.role.change': 'Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.', 'profile.become_specialist': 'Γίνε Ειδικός', 'profile.become_specialist.desc': 'Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.', 'become_specialist.hero.title': 'Κέρδισε χρήματα κάνοντας αυτό που ξέρεις', 'become_specialist.hero.subtitle': 'Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα', 'become_specialist.how.title': 'Πώς λειτουργεί', 'become_specialist.step1.title': 'Δημιούργησε κάρτα ειδικού', 'become_specialist.step1.desc': 'Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα', 'become_specialist.step2.title': 'Βρες εργασίες', 'become_specialist.step2.desc': 'Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα «Αναζήτηση εργασιών»', 'become_specialist.step3.title': 'Στείλε προσφορά & κέρδισε', 'become_specialist.step3.desc': 'Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες', 'become_specialist.benefits.title': 'Πλεονεκτήματα προφίλ ειδικού', 'become_specialist.benefit1': 'Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία', 'become_specialist.benefit2': 'Δημόσιο προφίλ με αξιολογήσεις πελατών', 'become_specialist.benefit3': 'Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες', 'become_specialist.benefit4': 'Προσθήκη σε αγαπημένα από πελάτες', 'become_specialist.cta': 'Περισσότερα', 'become_specialist.free_badge': 'Δωρεάν εγγραφή', 'profile.tab.notifications': 'Ειδοποιήσεις', 'profile.tab.reviews': 'Αξιολογήσεις', 'profile.tab.referral': 'Παραπομπές', 'profile.tab.auto_response': 'Αυτόματη απάντηση', 'profile.tab.site': 'Site', 'profile.site.title': 'Προσωπική σελίδα', 'profile.site.url_label': 'Προσωπικό site', 'profile.site.copy': 'Αντιγραφή', 'profile.site.copied': 'Αντιγράφηκε', 'profile.site.visible_title': 'Τι εμφανίζεται στη σελίδα σας', 'profile.site.visible.name': 'Όνομα και φωτογραφία', 'profile.site.visible.bio': 'Βιογραφικό', 'profile.site.visible.rating': 'Αξιολόγηση και κριτικές', 'profile.site.visible.portfolio': 'Χαρτοφυλάκιο / Κάρτες', 'profile.site.visible.contacts': 'Στοιχεία επικοινωνίας', 'profile.site.visible.full_last_name': 'Πλήρες επώνυμο', 'profile.site.visible.services': 'Κάρτες υπηρεσιών', 'profile.site.visible.reviews': 'Ενότητα κριτικών', 'profile.site.visible.status': 'Κατάσταση «Έτοιμος να βοηθήσω»', 'profile.site.theme': 'Θέμα εμφάνισης', 'profile.site.theme.dark': 'Σκοτεινό', 'profile.site.theme.light': 'Φωτεινό', 'profile.site.slug_taken': 'Αυτή η διεύθυνση είναι ήδη κατειλημμένη', 'profile.site.stats.title': 'Στατιστικά επισκεψιμότητας', 'profile.site.stats.days': 'τελευταίες 30 ημέρες', 'profile.site.stats.views': 'Προβολές', 'profile.site.stats.unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.messages': 'Μηνύματα', 'profile.site.stats.total_views': 'Συνολικές προβολές', 'profile.site.stats.total_unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.total_messages': 'Μηνύματα', 'profile.site.stats.empty': 'Δεν υπάρχουν δεδομένα ακόμη', 'profile.site.stats.loading': 'Φόρτωση στατιστικών...', 'profile.site.stats.no_slug': 'Ορίστε τη διεύθυνση του site για να δείτε στατιστικά', 'profile.site.edit_bio_hint': 'Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα «Βασικά».', 'status.can_help_now_hint': 'Η κάρτα σου εμφανίζεται ψηλότερα', 'status.need_help_hint': 'Οι ειδικοί μπορούν να σε βοηθήσουν', 'profile.referral.title': 'Πρόγραμμα παραπομπών', 'profile.referral.desc': 'Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.', 'profile.referral.link_label': 'Ο σύνδεσμος παραπομπής σου', 'profile.referral.copy': 'Αντιγραφή', 'profile.referral.copied': 'Αντιγράφηκε!', 'profile.referral.invited_count': 'επιτυχείς παραπομπές', 'profile.referral.no_code': 'Ο κωδικός παραπομπής δεν είναι διαθέσιμος.', 'notifications.title': 'Ρυθμίσεις ειδοποιήσεων', 'notifications.email.new_tasks': 'Email για νέες εργασίες', 'notifications.email.new_tasks.desc': 'Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου', 'notifications.messages.desc': 'Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα', 'notifications.saved': 'Ρυθμίσεις αποθηκεύτηκαν', 'notifications.plan_required': 'Συνδρομή απαιτείται για αυτή τη λειτουργία', 'profile.tab.info': 'Βασικά στοιχεία', 'profile.tab.finance': 'Οικονομικά', 'profile.tab.skills': 'Δεξιότητες', 'profile.tab.categories': 'Κατηγορίες', 'profile.tab.geography': 'Γεωγραφία', 'profile.specialist.categories': 'Κατηγορίες εργασιών', 'profile.specialist.categories.desc': 'Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι', 'profile.specialist.geography': 'Περιοχές κάλυψης', 'profile.specialist.geography.desc': 'Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι', 'profile.saving': 'Αποθήκευση...', 'profile.upload.error': 'Σφάλμα κατά την αναφόρτωση', 'profile.saved': 'Αποθηκεύτηκε', 'profile.tab.cards': 'Χαρτοφυλάκιο', 'profile.cards.count': 'Χαρτοφυλάκια', 'profile.cards.add': 'Νέο χαρτοφυλάκιο', 'profile.cards.new_title': 'Τίτλος νέου χαρτοφυλακίου', 'profile.cards.placeholder': 'π.χ. Υδραυλικά', 'profile.cards.create': 'Δημιουργία', 'profile.cards.cancel': 'Ακύρωση', 'profile.cards.empty': 'Δεν έχετε χαρτοφυλάκιο', 'profile.cards.create_first': 'Δημιουργήστε το πρώτο σας χαρτοφυλάκιο', 'profile.cards.delete_confirm': 'Διαγραφή χαρτοφυλακίου;', 'profile.card.tab.main': 'Γενικά', 'profile.card.tab.skills': 'Δεξιότητες', 'profile.card.tab.categories': 'Κατηγορίες', 'profile.card.tab.geography': 'Γεωγραφία', 'profile.card.tab.portfolio': 'Γκαλερί', 'profile.card.active': 'Ενεργή', 'profile.card.save': 'Αποθήκευση', 'profile.card.saved': 'Αποθηκεύτηκε', 'profile.card.delete': 'Διαγραφή', 'profile.card.skill.add': 'Προσθήκη δεξιότητας', 'profile.card.photo.add': 'Προσθήκη φωτογραφίας', 'profile.card.photo.uploading': 'Μεταφόρτωση...', 'profile.card.photo.empty': 'Δεν υπάρχουν φωτογραφίες', 'profile.card.item.title': 'Τίτλος', 'profile.card.item.desc': 'Περιγραφή', 'profile.card.item.save': 'Αποθήκευση', 'profile.card.item.cancel': 'Ακύρωση', 'profile.card.item.edit': 'Επεξεργασία', 'profile.upgrade.cards_limit': 'Όριο χαρτοφυλακίων εξαντλήθηκε', 'profile.upgrade.plan': 'Τρέχον πλάνο:', 'profile.upgrade.contact': 'Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου', 'profile.upgrade.ok': 'Εντάξει', 'profile.plan.title': 'Πλάνο συνδρομής', 'profile.balance': 'Υπόλοιπο', 'profile.balance.topup': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.amount': 'Ποσό (σε EUR)', 'profile.balance.topup.hint': 'Επιλέξτε ποσό ή εισαγάγετε μανούαλα', 'profile.balance.topup.submit': 'Πληρωμή', 'profile.balance.topup.loading': 'Ρεδιρεκτάρισμα...', 'profile.balance.topup.error': 'Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.', 'payment.success.title': 'Πληρωμή επιτυχής!', 'payment.success.desc': 'Το υπόλοιπό σας ενημερώθηκε.', 'payment.cancelled.title': 'Ακύρωση πληρωμής', 'payment.cancelled.desc': 'Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.', 'payment.pending.title': 'Σε εξέλιξη...', 'payment.pending.desc': 'Επεξεργαζόμαστε την πληρωμή σας.', 'payment.back_to_profile': 'Επιστροφή στο προφίλ', 'profile.plan.basic': 'Βασικό (δωρεάν)', 'profile.plan.contact_upgrade': 'Επικοινωνήστε με τον διαχειριστή για αναβάθμιση', 'profile.plan.cards_up_to': 'Χαρτοφυλάκια: έως', 'profile.plan.cards_unlimited': 'Χαρτοφυλάκια: απεριόριστα', 'profile.plan.tasks_up_to': 'Εργασίες: έως', 'profile.plan.offers_up_to': 'Προσφορές: έως', 'profile.plan.valid_until': 'Ισχύει έως', 'profile.plan.no_expiry': 'Δεν λήγει', // Create task 'create.error': 'Σφάλμα κατά τη δημοσίευση', // Tasks list extras 'tasks.category.general': 'Γενικά', 'tasks.budget.range': 'Εύρος:', 'tasks.budget.from': 'από', 'tasks.budget.to': 'έως', 'tasks.filter.reset': 'Εκκαθάριση φίλτρων', 'tasks.load_more': 'Φόρτωση ακόμα', 'tasks.showing': 'Αποτελέσματα:', 'tasks.field.budget': 'Προϋπολογισμός, €', // Admin 'admin.title': 'Πίνακας Διαχείρισης', 'admin.tab.stats': 'Στατιστικά', 'admin.tab.users': 'Χρήστες', 'admin.tab.tasks': 'Εργασίες', 'admin.tab.reports': 'Αναφορές', 'admin.stats.users': 'Χρήστες', 'admin.stats.tasks': 'Εργασίες', 'admin.stats.offers': 'Προσφορές', 'admin.stats.reviews': 'Αξιολογήσεις', 'admin.tasks.by_status': 'Εργασίες ανά κατάσταση', 'admin.col.user': 'Χρήστης', 'admin.col.email': 'Email', 'admin.col.role': 'Ρόλος', 'admin.col.registered': 'Εγγραφή', 'admin.col.status': 'Κατάσταση', 'admin.col.title': 'Τίτλος', 'admin.col.budget': 'Προϋπολογισμός', 'admin.col.created': 'Δημιουργία', 'admin.users.active': 'Ενεργός', 'admin.users.inactive': 'Ανενεργός', 'admin.users.deactivate': 'Απενεργοποίηση', 'admin.users.activate': 'Ενεργοποίηση', 'admin.tasks.cancel': 'Ακύρωση', 'admin.reports.none': 'Δεν υπάρχουν αναφορές', 'admin.reports.reviewed': 'Αναθεωρήθηκε', 'admin.reports.dismiss': 'Απόρριψη', 'admin.pagination.total': 'Σύνολο', 'admin.users.role.change': 'Αλλαγή ρόλου', 'admin.users.search.placeholder': 'Αναζήτηση ονόματος ή email...', 'admin.tasks.delete': 'Διαγραφή', 'admin.tasks.delete.confirm': 'Διαγραφή αυτής της εργασίας μόνιμα;', 'admin.tasks.search.placeholder': 'Αναζήτηση τίτλου...', 'admin.col.customer': 'Πελάτης', 'admin.col.reporter': 'Καταγγέλλων', 'admin.col.target': 'Στόχος', 'admin.filter.all_roles': 'Όλοι οι ρόλοι', 'admin.filter.all_statuses': 'Όλες οι καταστάσεις', 'admin.reports.target.task': 'Εργασία', 'admin.reports.target.user': 'Χρήστης', 'admin.tab.categories': 'Κατηγορίες', 'admin.tab.locations': 'Πόλεις & Περιοχές', 'admin.tab.logs': 'Αρχεία', 'admin.tab.plans': 'Πακέτα', 'admin.tab.settings': 'Ρυθμίσεις', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Δραστηριότητα', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Ειδοποιήσεις', 'admin.notif_logs.type': 'Τύπος', 'admin.notif_logs.title': 'Τίτλος', 'admin.notif_logs.read': 'Διαβασμένο', 'admin.notif_logs.empty': 'Δεν υπάρχουν αρχεία ειδοποιήσεων', 'admin.stats.notif_chart_title': 'Ειδοποιήσεις ανά ημέρα', 'admin.stats.notif_label': 'Ειδοποιήσεις', 'admin.stats.mail_chart_title': 'Emails ανά ημέρα', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Όλα', 'admin.stats.specialists': 'Ειδικοί', 'admin.col.plan': 'Πακέτο', 'admin.back_home': 'Αρχική', 'admin.plans.title': 'Πακέτα συνδρομής', 'admin.plans.add': '+ Νέο πακέτο', 'admin.plans.empty': 'Δεν υπάρχουν πακέτα', 'admin.plans.form.new': 'Νέο πακέτο', 'admin.plans.form.edit': 'Επεξεργασία πακέτου', 'admin.plans.form.name': 'Όνομα', 'admin.plans.form.price': 'Τιμή (EUR)', 'admin.plans.form.old_price': 'Παλιά τιμή (EUR, προαιρετικό)', 'admin.plans.form.max_offers': 'Μέγ. προσφορές (κενό = χωρίς όριο)', 'admin.plans.form.max_cards': 'Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)', 'admin.plans.form.duration_days': 'Διάρκεια (ημέρες, κενό = χωρίς λήξη)', 'admin.plans.form.description': 'Περιγραφή', 'admin.plans.form.features': 'Δυνατότητες (μία ανά γραμμή)', 'admin.plans.form.notify': 'Ειδοποιήσεις νέων εργασιών', 'admin.plans.form.default': 'Προεπιλογή', 'admin.plans.form.active': 'Ενεργό', 'admin.plans.form.order': 'Σειρά', 'admin.plans.form.role': 'Ρόλος', 'admin.plans.form.tier': 'Επίπεδο', 'admin.plans.form.role.customer': 'Πελάτης', 'admin.plans.form.role.specialist': 'Ειδικός', 'admin.plans.form.tier.free': 'Δωρεάν', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Όρια (κενό = χωρίς όριο)', 'admin.plans.form.max_messages_day': 'Μέγ. μηνύματα/ημέρα', 'admin.plans.form.max_orders_day': 'Μέγ. παραγγελίες/ημέρα', 'admin.plans.form.max_skills': 'Μέγ. δεξιότητες', 'admin.plans.form.max_profiles': 'Μέγ. προφίλ', 'admin.plans.form.max_portfolio': 'Μέγ. στοιχεία χαρτοφυλακίου', 'admin.plans.form.section.boost': 'Πολλαπλασιαστές & Ενίσχυση', 'admin.plans.form.search_boost': 'Ενίσχυση αναζήτησης', 'admin.plans.form.offers_multiplier': 'Πολλαπλασιαστής προσφορών', 'admin.plans.form.section.contact': 'Δικαιώματα επικοινωνίας', 'admin.plans.form.can_contact_free': 'Επικοινωνία με δωρεάν χρήστες', 'admin.plans.form.can_contact_pro': 'Επικοινωνία με Pro χρήστες', 'admin.plans.form.can_contact_all': 'Επικοινωνία με όλους', 'admin.plans.form.can_show_contact': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.plans.form.can_view_phone': 'Προβολή τηλεφώνου', 'admin.plans.form.section.features': 'Λειτουργίες', 'admin.plans.form.upload_video': 'Μεταφόρτωση βίντεο', 'admin.plans.form.favorites': 'Αγαπημένα', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Σήμα επαλήθευσης', 'admin.plans.form.highlighted_reviews': 'Προβεβλημένες κριτικές', 'admin.plans.form.personal_site': 'Προσωπική σελίδα', 'admin.plans.form.can_help_now': 'Κατάσταση «Μπορώ να βοηθήσω»', 'admin.plans.form.need_help': 'Κατάσταση «Χρειάζομαι βοήθεια»', 'admin.plans.form.auto_response': 'Αυτόματη απάντηση', 'admin.plans.form.auto_match': 'Αυτόματη αντιστοίχιση', 'admin.plans.form.instant_dispatch_free': 'Άμεση αποστολή (δωρεάν)', 'admin.plans.form.instant_dispatch_pro': 'Άμεση αποστολή (Pro)', 'admin.plans.badge.default': 'Προεπιλογή', 'admin.plans.badge.inactive': 'Ανενεργό', 'admin.plans.make_default': 'Ορισμός ως προεπιλογή', 'admin.plans.tasks': 'Εργασίες', 'admin.plans.offers': 'Προσφορές', 'admin.plans.cards': 'Χαρτοφυλάκιο', 'admin.plans.notify_tasks': 'Ειδοποιήσεις εργασιών', 'admin.plans.delete.confirm': 'Διαγραφή πακέτου', 'admin.activity.title': 'Αρχείο δραστηριότητας', 'admin.activity.event': 'Γεγονός', 'admin.activity.all_events': 'Όλα τα γεγονότα', 'admin.activity.from': 'Από', 'admin.activity.to': 'Έως', 'admin.activity.reset': 'Επαναφορά', 'admin.activity.total': 'Σύνολο', 'admin.activity.empty': 'Δεν υπάρχουν εγγραφές', 'admin.mail.event': 'Συμβάν email', 'admin.mail.all_events': 'Όλα τα email συμβάντα', 'admin.mail.from': 'Από', 'admin.mail.to': 'Έως', 'admin.mail.reset': 'Επαναφορά', 'admin.mail.total': 'Σύνολο', 'admin.mail.empty': 'Δεν υπάρχουν email logs', 'admin.mail.recipient': 'Παραλήπτης', 'admin.mail.provider': 'Πάροχος', 'admin.mail.details': 'Λεπτομέρειες', 'admin.mail.status': 'Κατάσταση', 'admin.mail.success': 'Επιτυχία', 'admin.mail.failed': 'Σφάλμα', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'Δεν υπάρχουν εγγραφές', 'admin.logs.date': 'Ημερομηνία', 'admin.logs.provider': 'Πάροχος', 'admin.logs.model': 'Μοντέλο', 'admin.logs.action': 'Ενέργεια', 'admin.logs.langs': 'Γλώσσες', 'admin.logs.in': 'Είσοδος', 'admin.logs.out': 'Έξοδος', 'admin.logs.total': 'Σύνολο', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Κατάσταση', 'admin.stats.activity_30d': 'Δραστηριότητα 30 ημερών', 'admin.stats.tasks_label': 'Εργασίες', 'admin.stats.users_label': 'Χρήστες', 'admin.stats.specialists_label': 'Ειδικοί', 'admin.stats.tokens_title': 'Χρήση tokens (ανά μήνα)', 'admin.stats.tokens_out': 'Εξερχόμενα', 'admin.stats.tokens_in': 'Εισερχόμενα', 'admin.stats.tokens_out_label': 'Εξερχόμενα tokens', 'admin.stats.tokens_in_label': 'Εισερχόμενα tokens', 'admin.stats.cost_label': 'Κόστος (USD)', 'admin.stats.tasks_by_status': 'Εργασίες ανά κατάσταση', 'admin.task_status.open': 'Ανοιχτές', 'admin.task_status.in_progress': 'Σε εξέλιξη', 'admin.task_status.completed': 'Ολοκληρωμένες', 'admin.task_status.cancelled': 'Ακυρωμένες', 'admin.task_status.draft': 'Προσχέδια', 'admin.settings.tab.general': 'Γενικά', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Ειδοποιήσεις', 'admin.settings.tab.payment': 'Πληρωμή', 'admin.settings.tab.referral': 'Παραπομπές', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Κοινωνικά δίκτυα', 'admin.settings.socials.title': 'Σύνδεσμοι κοινωνικών δικτύων', 'admin.settings.socials.hint': 'Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο', 'admin.settings.seo.maintenance_label': 'Λειτουργία συντήρησης', 'admin.settings.seo.maintenance_hint': 'Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες', 'admin.settings.seo.indexing_label': 'Ευρετηρίαση από μηχανές αναζήτησης', 'admin.settings.seo.indexing_hint': 'Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο', 'admin.settings.seo.head_scripts_label': 'Scripts στο (JS)', 'admin.settings.seo.head_scripts_hint': 'Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)', 'admin.settings.seo.site_title_label': 'Τίτλος ιστότοπου', 'admin.settings.seo.site_description_label': 'Περιγραφή ιστότοπου (meta description)', 'admin.settings.referral.title': 'Πρόγραμμα παραπομπών', 'admin.settings.referral.hint': 'Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.', 'admin.settings.referral.enabled_label': 'Ενεργό', 'admin.settings.referral.enabled_hint': 'Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών', 'admin.settings.referral.customer_section': 'Για πελάτες', 'admin.settings.referral.specialist_section': 'Για ειδικούς', 'admin.settings.referral.plan_label': 'Πλάνο ανταμοιβής', 'admin.settings.referral.no_plan': '— χωρίς πλάνο —', 'admin.settings.referral.plan_hint': 'Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.', 'admin.settings.referral.days_label': 'Ημέρες ανταμοιβής', 'admin.settings.referral.days_hint': 'Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.', 'admin.settings.general.title': 'Γενικές ρυθμίσεις', 'admin.settings.general.site_name': 'Όνομα ιστότοπου', 'admin.settings.general.site_url': 'URL ιστότοπου', 'admin.settings.general.contact_email': 'Email επικοινωνίας', 'admin.settings.general.support_phone': 'Τηλέφωνο υποστήριξης', 'admin.settings.smtp.title': 'Ρυθμίσεις SMTP', 'admin.settings.smtp.hint': 'Χρησιμοποιείται για αποστολή ειδοποιήσεων email.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Θύρα', 'admin.settings.smtp.encryption': 'Κρυπτογράφηση', 'admin.settings.smtp.enc.none': 'Χωρίς', 'admin.settings.smtp.enc.tls': 'STARTTLS (θύρα 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (θύρα 465)', 'admin.settings.smtp.username': 'Όνομα χρήστη', 'admin.settings.smtp.password': 'Κωδικός / App Password', 'admin.settings.smtp.from_name': 'Όνομα αποστολέα', 'admin.settings.smtp.from_email': 'Email αποστολέα', 'admin.settings.smtp.test': 'Αποστολή δοκιμαστικού email', 'admin.settings.smtp.sending': 'Αποστολή...', 'admin.settings.payment.hint': 'Τα στοιχεία για ePay Piraeus Bank.', 'admin.settings.env.test': 'Δοκιμαστικό (sandbox)', 'admin.settings.env.prod': 'Παραγωγή', 'admin.settings.env.label': 'Περιβάλλον', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Ενεργό', 'admin.settings.saving': 'Αποθήκευση...', 'admin.settings.saved': '✓ Αποθηκεύτηκε', 'admin.notif.vars_hint': 'Διαθέσιμες μεταβλητές στα πρότυπα', 'admin.notif.tmpl.not_set': 'Πρότυπο δεν έχει οριστεί', 'admin.notif.tmpl.subject_label': 'Θέμα email', 'admin.notif.tmpl.body_label': 'Κείμενο email (HTML)', 'admin.notif.tmpl.save': 'Αποθήκευση', 'admin.notif.tmpl.close': 'Κλείσιμο', 'admin.notif.tmpl.translate': 'Αυτόματη μετάφραση', 'admin.notif.tmpl.translating': 'Μετάφραση...', 'admin.notif.tmpl.saving': 'Αποθήκευση...', 'admin.notif.email_verification': 'Επαλήθευση email', 'admin.notif.registration_success': 'Επιτυχής εγγραφή', 'admin.notif.password_reset': 'Επαναφορά κωδικού', 'admin.notif.new_offer': 'Νέα προσφορά', 'admin.notif.new_task': 'Νέα εργασία', 'admin.notif.offer_accepted': 'Προσφορά αποδεκτή', 'admin.notif.new_message': 'Νέο μήνυμα', 'admin.notif.offer_declined': 'Απόρριψη προσφοράς', 'admin.notif.offer_other_accepted': 'Επιλέχθηκε άλλος ειδικός', 'admin.notif.task_updated': 'Ενημέρωση εργασίας', 'admin.notif.deadline_reminder': 'Υπενθύμιση προθεσμίας', 'admin.notif.task_archived': 'Αυτόματη απόσυρση εργασίας', 'admin.notif.referral_reward': 'Ανταμοιβή παραπομπής', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Τιμολόγιο — ενεργοποίηση πλάνου', 'admin.email_template.plan_upgraded': 'Τιμολόγιο — αναβάθμιση πλάνου', 'admin.email_template.plan_downgrade_scheduled': 'Τιμολόγιο — προγραμματισμένη υποβάθμιση', 'admin.email_template.plan_downgrade_applied': 'Τιμολόγιο — εφαρμογή υποβάθμισης', 'admin.email_template.plan_renewal_reminder': 'Τιμολόγιο — υπενθύμιση ανανέωσης', 'admin.email_template.plan_insufficient_funds': 'Τιμολόγιο — ανεπαρκές υπόλοιπο', // Pricing confirm modal 'pricing.confirm.title': 'Επιβεβαίωση επιλογής πλάνου', 'pricing.confirm.plan': 'Πλάνο', 'pricing.confirm.prorated': 'Αναλογική έκπτωση', 'pricing.confirm.effective_price': 'Προς πληρωμή', 'pricing.confirm.your_balance': 'Το υπόλοιπό σας', 'pricing.confirm.downgrade_info': 'Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.', 'pricing.confirm.insufficient': 'Ανεπαρκές υπόλοιπο.', 'pricing.confirm.top_up': 'Ανανέωση', 'pricing.confirm.schedule_downgrade': 'Προγραμματισμός μετάβασης', 'pricing.confirm.pay': 'Πληρωμή', 'admin.user_edit.title': 'Επεξεργασία χρήστη', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Διευθυνση email επαληθεύτηκε', 'admin.user_edit.email_not_verified': 'Email δεν έχει επαληθευτεί', 'admin.user_edit.verify_email_btn': 'Χειροκίνητη επαλήθευση', 'admin.user_edit.verify_email_done': 'Email επαληθεύτηκε!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Εγγραφή', 'admin.user_edit.last_seen': 'Τελευταία σύνδεση', 'admin.user_edit.lang': 'Γλώσσα', 'admin.user_edit.first_name': 'Όνομα', 'admin.user_edit.last_name': 'Επώνυμο', 'admin.user_edit.phone': 'Τηλέφωνο', 'admin.user_edit.bio': 'Βιογραφικό', 'admin.user_edit.role': 'Ρόλος', 'admin.user_edit.plan': 'Πακέτο', 'admin.user_edit.no_plan': '— Χωρίς πακέτο —', 'admin.user_edit.active': 'Ενεργός λογαριασμός', 'admin.user_edit.balance': 'Υπόλοιπο (EUR)', 'admin.user_edit.skills': 'Δεξιότητες', 'admin.user_edit.tab.profile': 'Προφίλ', 'admin.user_edit.tab.account': 'Λογαριασμός', 'admin.user_edit.tab.balance': 'Υπόλοιπο', 'admin.user_edit.tab.settings': 'Ρυθμίσεις', 'admin.user_edit.tab.specialist': 'Χαρτοφυλάκιο', 'admin.user_edit.tab.site': 'Ιστοσελίδα', 'admin.user_edit.plan_expires': 'Λήξη πλάνου', 'admin.user_edit.interface_lang': 'Γλώσσα διεπαφής', 'admin.user_edit.comm_languages': 'Γλώσσες επικοινωνίας', 'admin.user_edit.personal_site_slug': 'Προσωπική σελίδα', 'admin.user_edit.show_contact_info': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.user_edit.show_contact_info.hint': 'Ορατό στους πελάτες', 'admin.user_edit.notify_new_tasks': 'Ειδοποίηση για νέες εργασίες', 'admin.user_edit.notify_new_tasks.hint': 'Push και email ειδοποιήσεις', 'admin.user_edit.notif_messages': 'Ειδοποιήσεις μηνυμάτων', 'admin.user_edit.notif_messages.hint': 'Νέα μηνύματα στη συνομιλία', 'admin.user_edit.site_settings': 'Ρυθμίσεις προσωπικής σελίδας', 'admin.user_edit.categories': 'Κατηγορίες υπηρεσιών', 'admin.user_edit.locations': 'Περιοχές εξυπηρέτησης', 'admin.user_edit.skill_placeholder': 'Νέα δεξιότητα...', 'admin.user_edit.add_category': '— Επιλέξτε κατηγορία —', 'admin.user_edit.add_location': '— Επιλέξτε περιοχή —', 'admin.user_edit.specialist_cards': 'Χαρτοφυλάκιο ειδικού', 'admin.user_edit.no_cards': 'Δεν βρέθηκαν στοιχεία χαρτοφυλακίου', 'admin.user_edit.card_title': 'Τίτλος χαρτοφυλακίου', 'admin.user_edit.card_description': 'Περιγραφή', 'admin.balance.topup.btn': 'Αναπλήρωση', 'admin.balance.withdraw.btn': 'Αφαίρεση', 'admin.balance.modal_hint': 'Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό', 'admin.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'admin.balance.topup.amount': 'Ποσό', 'admin.balance.topup.description': 'Σχόλιο', 'admin.balance.topup.description.placeholder': 'Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση', 'admin.balance.topup.submit': 'Αναπλήρωση υπολοίπου', 'admin.balance.withdraw.title': 'Αφαίρεση υπολοίπου', 'admin.balance.withdraw.amount': 'Ποσό', 'admin.balance.withdraw.description': 'Σχόλιο', 'admin.balance.withdraw.description.placeholder': 'Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση', 'admin.balance.withdraw.submit': 'Αφαίρεση από το υπόλοιπο', 'admin.user_edit.role.customer': 'Πελάτης', 'admin.user_edit.role.specialist': 'Ειδικός', 'admin.user_edit.role.admin': 'Διαχειριστής', 'common.refresh': 'Ανανέωση', 'common.back_home': 'Αρχική', 'admin.loc.hint': 'Διαχείριση πόλεων και συνοικιών', 'admin.loc.add_city': 'Νέα πόλη', 'admin.loc.add_district': 'Προσθήκη συνοικίας', 'admin.loc.new': 'Νέα τοποθεσία', 'admin.loc.edit': 'Επεξεργασία τοποθεσίας', 'admin.loc.district': 'συνοικία', 'admin.loc.empty': 'Δεν υπάρχουν τοποθεσίες', 'admin.loc.delete.confirm': 'Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.', 'admin.cat.add_root': 'Νέα κατηγορία', 'admin.cat.add_sub': 'Υποκατηγορία', 'admin.cat.edit': 'Επεξεργασία', 'admin.cat.delete': 'Διαγραφή', 'admin.cat.delete.confirm': 'Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Εικονίδιο', 'admin.cat.name_el': 'Ελληνικά', 'admin.cat.name_en': 'Αγγλικά', 'admin.cat.name_ru': 'Ρωσικά', 'admin.cat.order': 'Σειρά', 'admin.cat.active': 'Ενεργή', 'admin.cat.parent': 'Γονική κατηγορία', 'admin.cat.no_parent': 'Κορυφαίο επίπεδο', 'admin.cat.save': 'Αποθήκευση', 'admin.cat.cancel': 'Ακύρωση', 'admin.cat.empty': 'Δεν υπάρχουν κατηγορίες', 'admin.cat.hint': 'Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία', 'admin.cat.new': 'Νέα κατηγορία', 'admin.cat.subcategory': 'υποκατηγορία', 'admin.cat.add_child': 'Προσθήκη υποκατηγορίας', 'admin.cat.inactive': 'Ανενεργή', 'admin.event.user_login': 'Σύνδεση', 'admin.event.user_register': 'Εγγραφή', 'admin.event.admin_user_deactivate': 'Αποκλεισμός χρήστη', 'admin.event.admin_user_activate': 'Ενεργοποίηση χρήστη', 'admin.event.admin_user_role_changed': 'Αλλαγή ρόλου', 'admin.event.admin_task_cancelled': 'Ακύρωση εργασίας', 'admin.event.admin_task_deleted': 'Διαγραφή εργασίας', 'admin.event.admin_report_reviewed': 'Αναφορά εξετάστηκε', 'admin.event.admin_report_dismissed': 'Αναφορά απορρίφθηκε', 'admin.event.task_created': 'Δημιουργία εργασίας', 'user.online': 'Σε σύνδεση', 'user.seen_minutes': 'ήταν εδώ πριν {n} λεπτά', 'user.seen_hours': 'ήταν εδώ πριν {n} ώρες', 'user.seen_yesterday': 'ήταν εδώ χθες', 'user.seen_days': 'ήταν εδώ πριν {n} μέρες', // Specialists 'specialists.title': 'Ειδικοί', 'specialists.search': 'Αναζήτηση ειδικού...', 'specialists.search.btn': 'Αναζήτηση', 'specialists.empty': 'Δεν βρέθηκαν ειδικοί', 'specialists.no_bio': 'Χωρίς περιγραφή', 'specialists.view': 'Προβολή προφίλ', 'specialists.reviews': 'αξιολογήσεις', 'specialist.favorite': 'Προσθήκη στα αγαπημένα', 'specialist.unfavorite': 'Αφαίρεση από αγαπημένα', 'specialist.site_link': 'Προσωπικό site', 'favorites.specialists.title': 'Αγαπημένοι ειδικοί', 'favorites.specialists.empty': 'Δεν έχετε αγαπημένους ειδικούς', 'nav.favorites': 'Αγαπημένα', 'nav.schedule': 'Πρόγραμμα', 'nav.find_tasks': 'Αναζήτηση εργασιών', 'schedule.title': 'Το πρόγραμμά μου', 'schedule.subtitle': 'Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας', 'schedule.available': 'Ελεύθερος', 'schedule.busy': 'Απασχολημένος', 'schedule.unset': 'Μη ορισμένο', 'schedule.click_hint': '← κλικ για εναλλαγή κατάστασης', 'schedule.range_mode': 'Επιλογή εύρους', 'schedule.range_from': 'Από {date} — επιλέξτε τελική ημερομηνία', 'schedule.click_to_set': 'Κλικ για ορισμό', 'schedule.free': 'ελεύθερα', 'schedule.busy_count': 'απασχολημένα', 'schedule.free_days': 'ελεύθερες ημέρες', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Σύνδεση με Google Calendar', 'schedule.disconnectGoogle': 'Αποσύνδεση', 'schedule.connectedAs': 'Συνδεδεμένο ως', 'schedule.importFromGoogle': 'Συγχρονισμός από Google', 'schedule.gcalConnected': '✓ Google Calendar συνδέθηκε', 'schedule.gcalError': 'Σφάλμα σύνδεσης Google Calendar', 'schedule.gcalImportDone': 'Εισήχθησαν {n} ημερ. από Google Calendar', 'schedule.gcalAutoSyncNote': 'Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar', 'schedule.gcalConnectDesc': 'Συνδέστε το Google Calendar για αυτόματο συγχρονισμό', 'schedule.gcalDisconnectConfirm': 'Αποσύνδεση Google Calendar;', 'find_tasks.title': 'Αναζήτηση εργασιών', 'find_tasks.for_me': 'Για μένα', 'find_tasks.all': 'Όλες οι εργασίες', 'find_tasks.by_category': 'Ανά κατηγορία', 'find_tasks.list': 'Λίστα', 'find_tasks.already_offered': 'Προσφορά υποβλήθηκε', 'find_tasks.offer_now': 'Υποβολή προσφοράς', 'find_tasks.empty_for_me': 'Δεν βρέθηκαν εργασίες στις κατηγορίες σας', 'find_tasks.banner_hint': 'Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας', 'find_tasks.no_cards': 'Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς', 'find_tasks.add_card': 'Δημιουργία χαρτοφυλακίου', 'find_tasks.search': 'Αναζήτηση εργασιών...', 'find_tasks.tasks_count': 'εργασίες', // Footer 'footer.tagline': 'Η πλατφόρμα εργασιών για την Ελλάδα', 'footer.rights': 'Όλα τα δικαιώματα διατηρούνται.', // App download section 'app.download_title': 'Κατεβάστε την εφαρμογή CanHelp', 'app.download_desc': 'Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.', // Nav 'nav.pricing': 'Τιμές', // Pricing page 'pricing.title': 'Τιμολόγηση', 'pricing.subtitle': 'Επιλέξτε το κατάλληλο πρόγραμμα', 'pricing.role.customer': 'Πελάτης', 'pricing.role.specialist': 'Ειδικός', 'pricing.free': 'Δωρεάν', 'pricing.per_month': 'μήνα', 'pricing.duration': 'Διάρκεια', 'pricing.days': 'ημ.', 'pricing.current_plan': 'Το πρόγραμμά σας', 'pricing.popular': 'Δημοφιλές', 'pricing.choose': 'Επιλογή', 'pricing.your_plan': 'Ενεργό πρόγραμμα', 'pricing.free_default': 'Προεπιλογή', 'pricing.compare': 'Σύγκριση λειτουργιών', 'pricing.feature': 'Λειτουργία', 'pricing.faq_note': 'Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.', 'pricing.feat.messages': 'Μηνύματα / ημέρα', 'pricing.feat.orders': 'Παραγγελίες / ημέρα', 'pricing.feat.contact_all': 'Επικοινωνία με όλους', 'pricing.feat.view_phone': 'Εμφάνιση τηλεφώνου', 'pricing.feat.show_contact': 'Εμφάνιση στοιχείων επαφής', 'pricing.feat.favorites': 'Αγαπημένα', 'pricing.feat.verified_badge': 'Επαληθευμένο badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Προσωπικό site', 'pricing.feat.auto_response': 'Αυτόματη απάντηση', 'pricing.feat.auto_match': 'Αυτόματη αντιστοίχιση', 'pricing.feat.highlighted_reviews': 'Επισημασμένες αξιολογήσεις', 'pricing.feat.portfolio': 'Στοιχεία χαρτοφυλακίου', 'pricing.feat.cards': 'Κάρτες ειδικού', 'pricing.feat.notify_tasks': 'Ειδοποιήσεις νέων εργασιών', 'pricing.feat.video': 'Βίντεο στο χαρτοφυλάκιο', // Upgrade prompt 'upgrade.available_in': 'Διαθέσιμο στο', 'upgrade.cta': 'Αναβάθμιση', // Dashboard plan block 'dashboard.plan.title': 'Το πρόγραμμά μου', 'dashboard.plan.expires': 'Λήγει σε {n} ημέρες', 'dashboard.plan.upgrade': 'Αναβάθμιση προγράμματος', 'dashboard.plan.no_plan': 'Δωρεάν πρόγραμμα', 'dashboard.plan.messages': 'Μηνύματα σήμερα', 'dashboard.plan.orders': 'Παραγγελίες σήμερα', 'dashboard.plan.limits': 'Ημερήσια όρια', 'dashboard.plan.features': 'Λειτουργίες', 'dashboard.plan.stats': 'Στατιστικά', 'dashboard.stats.cards': 'Χαρτοφυλάκια', 'dashboard.stats.maxCards': 'Μέγ. χαρτοφυλάκια', 'dashboard.stats.portfolioItems': 'Στοιχεία portfolio', 'dashboard.stats.maxPortfolioItems': 'Μέγ. στοιχεία', 'dashboard.stats.activeOffers': 'Ενεργές προσφορές', 'dashboard.stats.reviewsReceived': 'Αξιολογήσεις', 'dashboard.stats.activeTasks': 'Ενεργές εργασίες', 'dashboard.stats.completedTasks': 'Ολοκληρωμένες', 'status.can_help_now': 'Είμαι διαθέσιμος τώρα', 'status.need_help': 'Χρειάζομαι βοήθεια', 'status.active': 'Ενεργό', 'status.toggle_on': 'Ενεργοποίηση', 'status.toggle_off': 'Απενεργοποίηση', // FOMO 'fomo.missed_orders': 'Χάσατε {n} παραγγελίες', 'fomo.missed_value': 'Αξία €{v}', 'fomo.upgrade_hint': 'Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες', 'fomo.conversion': 'Μετατροπές εργασιών', 'fomo.active': 'Ενεργές', 'fomo.with_offers': 'Με προσφορές', 'fomo.completed': 'Ολοκληρωμένες', 'fomo.already_offered': '{n} ειδικοί έχουν ήδη απαντήσει', 'fomo.specialist_missed': 'Χάσατε {n} παραγγελίες', 'fomo.top_categories': 'Κατηγορίες', 'fomo.offers_received': 'προσφορές ελήφθησαν', 'fomo.avg_offers': 'Μέσο {n}/εργασία', 'fomo.completion_rate': 'ολοκληρωμένες', // Task auto-match 'task.auto_match': 'Αυτόματη αντιστοίχιση', 'task.auto_match_results': 'Κορυφαίοι ειδικοί', 'task.no_offer_yet': 'Δεν έχετε στείλει προσφορά ακόμα', 'task.make_offer': 'Αποστολή προσφοράς', 'auto_response.title': 'Αυτόματη Απάντηση', 'auto_response.enabled': 'Ενεργοποίηση αυτόματης απάντησης', 'auto_response.min_budget': 'Ελάχ. προϋπολογισμός', 'auto_response.max_budget': 'Μέγ. προϋπολογισμός', 'auto_response.default_price': 'Προεπιλεγμένη τιμή', 'auto_response.default_message': 'Προεπιλεγμένο μήνυμα', 'auto_response.max_per_day': 'Μέγ. αυτόματες προσφορές/ημέρα', 'auto_response.save': 'Αποθήκευση', 'auto_response.saved': 'Αποθηκεύτηκε', 'auto_response.categories': 'Κατηγορίες', 'auto_response.locations': 'Τοποθεσίες', // Personal site 'profile.personal_site': 'Προσωπικό Site', 'profile.site_slug': 'Slug URL', 'profile.site_slug_hint': 'Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _', 'profile.site_open': 'Άνοιγμα site', 'profile.site_preview': 'Το site σας', 'profile.show_contact': 'Εμφάνιση στοιχείων επαφής', 'profile.show_contact_hint': 'Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας', // Google Calendar plan gate 'gcal.upgrade_required': 'Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα', // Chat limits 'chat.limit_warning': 'Απομένουν {n} μηνύματα σήμερα', 'chat.limit_reached': 'Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας', 'chat.upgrade': 'Αναβάθμιση', // Site page 'site.member_since': 'Μαζί μας από', 'site.rating': 'Βαθμολογία', 'site.completed_tasks': 'Ολοκληρώθηκαν', 'site.languages': 'Γλώσσες', 'site.photos': 'φωτ.', 'site.contact_form': 'Επικοινωνία', 'site.contact_sent': 'Το μήνυμα στάλθηκε!', 'site.contact_sent_desc': 'Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα', 'site.contact_name': 'Όνομα', 'site.contact_name_ph': 'Το όνομά σας', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Μήνυμα', 'site.contact_message_ph': 'Περιγράψτε την εργασία σας...', 'site.contact_send': 'Αποστολή', 'site.share': 'Κοινοποίηση', 'site.speaks_languages': 'Μιλάει', 'site.message_sent': 'Το μήνυμα εστάλη!', 'site.message_sent_desc': 'Ο ειδικός θα το λάβει στη συνομιλία', 'site.message_placeholder': 'Γράψτε το μήνυμά σας...', 'site.write_to_chat': 'Γράψτε στο chat', 'site.auth_required_title': 'Απαιτείται σύνδεση', 'site.auth_required_desc': 'Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.', 'site.auth_login_btn': 'Σύνδεση', 'site.auth_contact_form_btn': 'Επικοινωνία μέσω φόρμας', 'specialist.services': 'Υπηρεσίες', 'portfolio.title': 'Χαρτοφυλάκιο', 'common.not_found': 'Η σελίδα δεν βρέθηκε', 'common.anonymous': 'Ανώνυμα', 'specialist_setup.page_title': 'Ρύθμιση προφίλ ειδικού', 'specialist_setup.step_of': 'Βήμα {current} από {total}', 'specialist_setup.next': 'Επόμενο', 'specialist_setup.back': 'Πίσω', 'specialist_setup.skip': 'Παράλειψη', 'specialist_setup.finish': 'Ολοκλήρωση', 'specialist_setup.go_to_profile': 'Μεταβείτε στο προφίλ', 'specialist_setup.browse_tasks': 'Εξερεύνηση εργασιών', 'specialist_setup.step1.title': 'Καλωσήλθατε!', 'specialist_setup.step1.subtitle': 'Ας ρυθμίσουμε το προφίλ σας', 'specialist_setup.step1.desc': 'Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.', 'specialist_setup.step1.what_next': 'Τι θα κάνουμε:', 'specialist_setup.step1.item1': 'Συμπλήρωση βασικών πληροφοριών', 'specialist_setup.step1.item2': 'Δημιουργία κάρτας υπηρεσίας', 'specialist_setup.step1.item3': 'Προσθήκη δεξιοτήτων και κατηγοριών', 'specialist_setup.step1.item4': 'Επιλογή γεωγραφικής περιοχής', 'specialist_setup.step1.item5': 'Μεταφόρτωση φωτογραφιών χαρτοφυλακίου', 'specialist_setup.step2.title': 'Βασικό προφίλ', 'specialist_setup.step2.subtitle': 'Πείτε μας για σας', 'specialist_setup.step2.bio_label': 'Σχετικά με εμένα', 'specialist_setup.step2.bio_placeholder': 'Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...', 'specialist_setup.step2.phone_label': 'Τηλέφωνο', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Φωτογραφία προφίλ', 'specialist_setup.step2.photo_btn': 'Μεταφόρτωση φωτογραφίας', 'specialist_setup.step2.photo_uploading': 'Μεταφόρτωση...', 'specialist_setup.step2.photo_hint': 'Εμφανίζεται στο προφίλ σας', 'specialist_setup.step3.title': 'Κάρτα υπηρεσίας', 'specialist_setup.step3.subtitle': 'Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας', 'specialist_setup.step3.title_label': 'Τίτλος κάρτας', 'specialist_setup.step3.title_placeholder': 'Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...', 'specialist_setup.step3.desc_label': 'Περιγραφή', 'specialist_setup.step3.desc_placeholder': 'Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...', 'specialist_setup.step3.title_required': 'Απαιτείται τίτλος', 'specialist_setup.step4.title': 'Δεξιότητες & Κατηγορίες', 'specialist_setup.step4.subtitle': 'Προσθέστε δεξιότητες και επιλέξτε κατηγορίες', 'specialist_setup.step4.skills_label': 'Δεξιότητες', 'specialist_setup.step4.skills_placeholder': 'Π.χ. Εγκατάσταση σωληνώσεων...', 'specialist_setup.step4.skills_add': 'Προσθήκη', 'specialist_setup.step4.categories_label': 'Κατηγορίες', 'specialist_setup.step5.title': 'Γεωγραφική περιοχή', 'specialist_setup.step5.subtitle': 'Πού παρέχετε υπηρεσίες;', 'specialist_setup.step5.hint': 'Επιλέξτε πόλεις ή συγκεκριμένες περιοχές', 'specialist_setup.done.title': 'Το προφίλ σας είναι έτοιμο!', 'specialist_setup.done.subtitle': 'Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί', 'specialist_setup.done.desc': 'Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας.' }, en: { 'footer.slogan': 'Your task — our care! We solve any issue quickly and easily.', 'footer.links': 'Links', 'footer.socials': 'Socials', 'nav.home': 'Home', 'nav.tasks': 'Tasks', 'nav.post': '+ Post task', 'nav.dashboard': 'Dashboard', 'nav.chat': 'Messages', 'nav.notifications': 'Notifications', 'nav.profile': 'Profile', 'nav.admin': 'Admin Panel', 'nav.specialists': 'Specialists', 'nav.new_task': 'New task', 'nav.login': 'Login', 'nav.register': 'Register', 'nav.logout': 'Logout', 'hero.title': 'Find a specialist for any job', 'hero.subtitle': 'Post a task, receive offers and choose the best professional', 'hero.cta.post': 'Post a task', 'hero.cta.browse': 'Become a specialist', 'hero.search.placeholder': 'What do you need? e.g. electrician, cleaning...', 'stats.specialists': 'specialists', 'stats.tasks': 'tasks', 'stats.categories': 'categories', 'stats.free': 'free sign-up', 'section.categories': 'Create a task in any category', 'section.how': 'How it works', 'section.recent': 'Recent tasks', 'section.all': 'See all →', 'section.more': 'more', 'section.cities': 'Cities & Districts', 'section.community': 'A community project for everyone', 'community.subtitle': 'CanHelp is not just a marketplace — it\'s a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.', 'community.point1.title': 'Are you good at something?', 'community.point1.desc': 'Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.', 'community.point2.title': 'Need help with something?', 'community.point2.desc': 'Post a task in under a minute and receive offers from verified specialists in your city.', 'community.point3.title': 'Help the project grow', 'community.point3.desc': 'CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.', 'community.share': 'Share with friends', 'community.share.copied': 'Link copied!', // Referral section on home page 'section.referral': 'Referral Program', 'referral.home.subtitle': 'Share your link — every new user who signs up through it earns you a reward.', 'referral.home.step1.title': 'Sign up and get your link', 'referral.home.step1.desc': 'Create an account and find your unique referral link in your profile.', 'referral.home.step2.title': 'Share with friends', 'referral.home.step2.desc': 'Send the link to friends, acquaintances, or post it on social media.', 'referral.home.step3.title': 'Earn rewards', 'referral.home.step3.desc': 'Once your friend verifies their email, you automatically receive your reward.', 'referral.home.cta': 'Get your link', 'referral.home.badge': 'Referral Program', // FAQ section 'section.faq': 'Frequently Asked Questions', 'faq.q1': 'How does CanHelp work?', 'faq.a1': 'Post a task, receive offers from specialists, choose the best one and start working together. It\'s fast, simple and free for customers.', 'faq.q2': 'How much does it cost to use the platform?', 'faq.a2': 'Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.', 'faq.q3': 'How can I become a specialist?', 'faq.a3': 'Register, go to «Become a Specialist», fill in your profile with skills and categories, and start receiving tasks.', 'faq.q4': 'How do I choose the right specialist?', 'faq.a4': 'Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.', 'faq.q5': 'What if I am not satisfied?', 'faq.a5': 'You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.', 'faq.q6': 'Can I contact a specialist before accepting their offer?', 'faq.a6': 'Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.', 'faq.q7': 'How long does it take to receive offers?', 'faq.a7': 'Usually within a few hours. Specialists get notified about new tasks and can respond quickly.', 'faq.q8': 'Can I post a task in any city in Greece?', 'faq.a8': 'Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.', 'faq.q9': 'What types of tasks can I find on CanHelp?', 'faq.a9': 'Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.', 'faq.q10': 'Is there a mobile app?', 'faq.a10': 'Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.', 'how.step1.title': 'Post a task', 'how.step1.desc': 'Describe what you need and set your budget', 'how.step2.title': 'Receive offers', 'how.step2.desc': 'Specialists will send you offers with price and timeline', 'how.step3.title': 'Choose & start', 'how.step3.desc': 'Pick the best professional and start the collaboration', 'tasks.title': 'tasks', 'tasks.filters': 'Filters', 'tasks.search': 'Search', 'tasks.search.placeholder': 'Title or keyword...', 'tasks.search.btn': 'Search', 'tasks.publish': 'Post', 'tasks.category.all': 'All', 'tasks.category.all_in': 'All in', 'tasks.category.label': 'Category', 'tasks.location.label': 'City', 'tasks.location.placeholder': 'e.g. Athens', 'tasks.empty': 'No tasks found', 'tasks.empty.cta': 'Post the first one', 'task.status.open': 'Open', 'task.status.in_progress': 'In progress', 'task.status.completed': 'Completed', 'task.status.cancelled': 'Cancelled', 'task.status.draft': 'Draft', 'task.budget': 'Budget', 'task.location': 'Location', 'task.deadline': 'Start date', 'task.created_at': 'Created', 'task.customer': 'Customer', 'task.offer.btn': 'Submit offer', 'task.invite.banner_title': "You've been invited to this task", 'task.invite.banner_hint': 'The customer personally invited you', 'task.invite.accept': 'Send offer', 'task.invite.decline': 'Decline', 'offer.accept': 'Accept', 'offer.decline': 'Decline', 'task.complete': 'Complete task', 'task.complete.confirm': 'Mark this task as complete?', 'task.edit': 'Edit', 'task.status_label': 'Status', 'task.yours': 'Your task', 'task.offer.yours': 'Your offer', 'review.leave': 'Leave a review', 'review.rating': 'Rating', 'review.comment': 'Comment', 'review.comment.placeholder': 'Tell us about your experience...', 'review.submit': 'Submit review', 'review.submitting': 'Submitting...', 'review.done': 'Review submitted!', 'profile.reviews': 'Reviews', 'profile.no_reviews': 'No reviews yet', 'profile.rating': 'Rating', 'profile.skills.label': 'Skills', 'profile.member_since': 'Member since', 'task.offers': 'Offers', 'task.offers.none': 'No offers yet', 'create.title': 'Post a task', 'create.field.title': 'Title', 'create.field.description': 'Description', 'create.field.category': 'Category', 'create.field.category.select': 'Select...', 'create.field.location': 'Location', 'create.field.location.any': 'Anywhere', 'create.field.location.all': 'Entire city', 'create.field.budget': 'Budget (€)', 'create.field.deadline': 'Start date', 'create.field.budget_negotiable': 'Price is negotiable', 'create.field.time_slot': 'Time slot', 'create.field.time_slot.any': 'Anytime', 'create.field.time_slot.morning': 'Morning (08:00–13:00)', 'create.field.time_slot.afternoon': 'Afternoon (13:00–18:00)', 'create.field.time_slot.evening': 'Evening (18:00–22:00)', 'create.field.time_slot.weekend': 'Weekend', 'create.field.address': 'Address (optional)', 'create.field.address.district': 'District', 'create.field.address.street': 'Street', 'create.field.address.house': 'Number', 'create.field.confidential': 'Confidential note', 'create.field.confidential.placeholder': 'Details visible only to the assigned specialist...', 'create.field.confidential.hint': 'Not shown publicly', 'create.field.photos': 'Photos', 'create.field.photos.add': 'Add photo', 'create.field.photos.uploading': 'Uploading...', 'task.budget_negotiable': 'Price negotiable', 'task.time_slot': 'Time slot', 'task.confidential': 'Confidential note', 'create.field.title.placeholder': 'e.g. Clean 80sqm apartment', 'create.field.description.placeholder': 'Describe in detail what you need...', 'create.field.location.placeholder': 'e.g. Athens, Kolonaki', 'create.field.budget.placeholder': 'e.g. 100', 'create.submit': 'Post task', 'create.submitting': 'Posting...', 'login.title': 'Welcome back', 'login.subtitle': 'Sign in to CanHelp', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.submitting': 'Signing in...', 'login.error': 'Invalid email or password', 'login.unverified.title': 'Verify your email address', 'login.unverified.desc': 'We sent a verification link to your email. Check your inbox (or spam) and click the link.', 'login.unverified.resend': 'Resend verification email', 'login.unverified.sending': 'Sending...', 'login.unverified.sent': '✓ Sent — check your inbox', 'profile.email.verified': 'Email verified', 'profile.email.not_verified': 'Email not verified', 'login.no_account': "Don't have an account?", 'login.register_link': 'Register', 'login.forgot_password': 'Forgot password?', 'login.or_continue_with': 'or continue with', 'login.continue_google': 'Continue with Google', 'forgot.title': 'Forgot password', 'forgot.subtitle': 'Enter your email to receive a reset link', 'forgot.email': 'Email', 'forgot.submit': 'Send reset link', 'forgot.submitting': 'Sending...', 'forgot.sent.title': 'Check your inbox', 'forgot.sent.desc': 'If an account exists with that email, we\'ll send you a password reset link.', 'forgot.back_to_login': 'Back to sign in', 'forgot.error': 'Could not send reset link. Check the email address and try again.', 'forgot.error.not_found': 'No account found with this email address.', 'forgot.error.send_failed': 'Failed to send email. Please try again later.', 'reset.title': 'New password', 'reset.subtitle': 'Enter your new password', 'reset.password': 'New password', 'reset.confirm': 'Confirm password', 'reset.submit': 'Change password', 'reset.submitting': 'Saving...', 'reset.success': 'Password changed successfully. Redirecting to sign in...', 'reset.back_to_login': 'Back to sign in', 'reset.error.mismatch': 'Passwords do not match', 'reset.error.invalid': 'Invalid or expired link. Please request a new one.', 'register.title': 'Register', 'register.subtitle': 'Create a CanHelp account', 'register.first_name': 'First name', 'register.last_name': 'Last name', 'register.email': 'Email', 'register.password': 'Password (min 8 characters)', 'register.role': 'Role', 'register.role.customer': 'User', 'register.role.customer.desc': 'I post tasks', 'register.role.specialist': 'Specialist', 'register.role.specialist.desc': 'I take on tasks', 'register.submit': 'Create account', 'register.submitting': 'Registering...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Sign in', 'register.continue_google': 'Continue with Google', 'register.check_email.title': 'Check your email', 'register.check_email.desc': 'We sent a verification link to your email address. Check your inbox (or spam) and click the link.', 'register.check_email.login': 'Back to sign in', 'dashboard.title': 'Dashboard', 'dashboard.new_task': '+ New task', 'dashboard.my_tasks': 'My tasks', 'dashboard.my_offers': 'My offers', 'dashboard.invitations': 'Job invitations', 'dashboard.offers_count': 'offers', 'dashboard.declined_count': 'declined', 'dashboard.completed_tasks': 'Completed tasks', 'dashboard.completed_offers': 'Completed offers', 'dashboard.review_pending': 'Review not yet submitted', 'tasks.new.top_specialists': 'Top specialists', 'tasks.new.select_category': 'Select a category to see matching specialists', 'tasks.new.invite': 'Offer work', 'tasks.new.invited': 'Selected ✓', 'reviews.count': 'reviews', 'filter.location': 'Location', 'filter.language': 'Languages', 'filter.language.any': 'Any language', 'filter.category.all': 'All categories', 'user.categories': 'Categories', 'user.work_area': 'Work area', 'dashboard.tasks.empty': "You haven't posted any tasks", 'dashboard.tasks.empty.cta': 'Post your first one', 'dashboard.tasks.add_new': 'Add a new task', 'dashboard.offers.empty': "You haven't submitted any offers", 'dashboard.offers.empty.cta': 'Find tasks', 'dashboard.customer.specialists_title': 'Looking for a specialist?', 'dashboard.customer.specialists_hint': 'Browse specialist profiles, read reviews and invite them to your tasks', 'dashboard.customer.specialists_cta': 'Find a specialist', 'dashboard.customer.how_title': 'How it works', 'dashboard.customer.step1': 'Create a task with a description and budget', 'dashboard.customer.step2': 'Specialists will send offers with price and timeline', 'dashboard.customer.step3': 'Choose the right one and start working', 'notif.title': 'Notifications', 'notif.mark_all': 'Mark all as read', 'notif.empty': 'No notifications', 'notif.type.new_offer': 'New offer', 'notif.type.offer_accepted': 'Your offer was accepted', 'notif.type.offer_declined': 'Your offer was declined', 'notif.type.task_completed': 'Task completed', 'notif.type.task_cancelled': 'Task cancelled', 'notif.type.new_message': 'New message', 'notif.type.new_review': 'New review', 'notif.type.task_invite': 'Job invitation', 'notif.body.new_offer': 'New offer for «{title}»', 'notif.body.offer_accepted': 'Your offer for «{title}» was accepted', 'notif.body.offer_declined': 'Your offer for «{title}» was declined', 'notif.body.task_invite': 'You\'ve been invited for «{title}»', 'notif.body.new_review': 'You received a {rating}★ review', 'offer.status.pending': 'Pending', 'offer.status.accepted': 'Accepted', 'offer.status.declined': 'Declined', 'offer.status.withdrawn': 'Withdrawn', 'offer.status.other_accepted': 'Another specialist was chosen', 'common.loading': 'Loading...', 'common.error': 'Error', 'common.save': 'Save', 'common.saving': 'Saving...', 'common.cancel': 'Cancel', 'common.add': 'Add', 'common.close': 'Close', 'common.edit': 'Edit', 'common.delete': 'Delete', 'common.from': 'by', 'common.currency': '€', 'common.greece': 'Greece', // Chat 'chat.connected': 'Connected', 'chat.disconnected': 'Disconnected', 'chat.no_rooms': 'No conversations yet', 'chat.task_fallback': 'Task', 'chat.select': 'Select a conversation', 'chat.no_messages': 'No messages yet', 'chat.placeholder': 'Write a message... (Enter to send)', 'chat.conversation_fallback': 'Conversation', 'chat.direct_chat': 'Direct chat', 'chat.linked_task': 'Linked task', 'chat.write_btn': 'Message', 'chat.just_now': 'just now', 'chat.min_ago': 'm', 'chat.write_specialist': 'Write to specialist', 'chat.write_customer': 'Write to customer', 'chat.notif_settings': 'Notification settings', 'chat.notif_messages': 'Notifications for new messages', 'chat.toast_title': 'New message', 'chat.toast_open': 'Open chat', // Offer form 'offer.price': 'Price', 'offer.price.placeholder': 'e.g. 80', 'offer.customer_budget': 'Client budget', 'offer.message': 'Message', 'offer.optional': 'optional', 'offer.message.placeholder': 'Introduce yourself, your experience and why you are the best choice...', 'offer.submitting': 'Sending...', // Profile 'profile.photo': 'Profile photo', 'profile.photo.change': 'Change photo', 'profile.photo.hint': 'JPEG, PNG, WebP · up to 5MB', 'profile.basic_info': 'Basic info', 'profile.phone': 'Phone', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Short bio', 'profile.bio.placeholder': 'Tell us a bit about yourself...', 'profile.language': 'Language', 'profile.language.hint': 'App interface and email notification language', 'profile.languages': 'Languages spoken', 'profile.languages.hint': 'Select all languages you speak', 'profile.skills': 'Skills', 'profile.skills.subtitle': 'Add the services you offer', 'profile.skills.placeholder': 'e.g. Cleaning, IT, Tutoring...', 'profile.role': 'Account role', 'profile.role.specialist': '🔧 Specialist', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 User', 'profile.role.change': 'To change your role please contact support.', 'profile.become_specialist': 'Become a Specialist', 'profile.become_specialist.desc': 'Upgrade to Specialist to take on tasks and build your profile.', 'become_specialist.hero.title': 'Earn money doing what you do best', 'become_specialist.hero.subtitle': 'Create a specialist profile and receive orders from clients across Greece', 'become_specialist.how.title': 'How it works', 'become_specialist.step1.title': 'Create a specialist portfolio', 'become_specialist.step1.desc': 'Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks', 'become_specialist.step2.title': 'Find tasks', 'become_specialist.step2.desc': 'Discover tasks in your categories in the "Find Orders" section', 'become_specialist.step3.title': 'Send an offer & earn', 'become_specialist.step3.desc': 'Submit offers with price and timeline, chat with clients and complete tasks', 'become_specialist.benefits.title': 'Specialist profile advantages', 'become_specialist.benefit1': 'Task search filtered by your categories and location', 'become_specialist.benefit2': 'Public profile with client reviews', 'become_specialist.benefit3': 'Availability schedule visible to clients', 'become_specialist.benefit4': 'Saved to favourites by clients', 'become_specialist.cta': 'Learn more', 'become_specialist.free_badge': 'Free registration', 'profile.tab.notifications': 'Notifications', 'profile.tab.reviews': 'Reviews', 'profile.tab.referral': 'Referrals', 'profile.tab.auto_response': 'Auto-response', 'profile.tab.site': 'Site', 'profile.site.title': 'Personal page', 'profile.site.url_label': 'Personal site', 'profile.site.copy': 'Copy', 'profile.site.copied': 'Copied', 'profile.site.visible_title': "What's on your page", 'profile.site.visible.name': 'Name and photo', 'profile.site.visible.bio': 'Bio', 'profile.site.visible.rating': 'Rating and reviews', 'profile.site.visible.portfolio': 'Portfolio / Cards', 'profile.site.visible.contacts': 'Contact info', 'profile.site.visible.full_last_name': 'Full last name', 'profile.site.visible.services': 'Service cards', 'profile.site.visible.reviews': 'Reviews section', 'profile.site.visible.status': '"Ready to help" status', 'profile.site.theme': 'Appearance theme', 'profile.site.theme.dark': 'Dark', 'profile.site.theme.light': 'Light', 'profile.site.slug_taken': 'This address is already taken', 'profile.site.stats.title': 'Site analytics', 'profile.site.stats.days': 'last 30 days', 'profile.site.stats.views': 'Views', 'profile.site.stats.unique': 'Unique visitors', 'profile.site.stats.messages': 'Messages', 'profile.site.stats.total_views': 'Total views', 'profile.site.stats.total_unique': 'Unique visitors', 'profile.site.stats.total_messages': 'Messages', 'profile.site.stats.empty': 'No data yet', 'profile.site.stats.loading': 'Loading analytics...', 'profile.site.stats.no_slug': 'Set your site URL to see analytics', 'profile.site.edit_bio_hint': 'Bio and photo are edited in the "Basic info" tab.', 'status.title': 'Status', 'status.can_help_now_hint': 'Your card is shown higher in search', 'status.need_help_hint': 'Specialists can offer you help', 'profile.referral.title': 'Referral program', 'profile.referral.desc': 'Share your link and earn rewards for every new user you invite.', 'profile.referral.link_label': 'Your referral link', 'profile.referral.copy': 'Copy', 'profile.referral.copied': 'Copied!', 'profile.referral.invited_count': 'successful referrals', 'profile.referral.no_code': 'Referral code is not available.', 'notifications.title': 'Notification settings', 'notifications.email.new_tasks': 'Email for new tasks', 'notifications.email.new_tasks.desc': 'Receive an email when a new task is posted in your categories', 'notifications.messages.desc': 'Receive a notification when a new message arrives', 'notifications.saved': 'Settings saved', 'notifications.plan_required': 'Not available in your plan', 'profile.tab.info': 'Basic info', 'profile.tab.finance': 'Finance', 'profile.tab.skills': 'Skills', 'profile.tab.categories': 'Categories', 'profile.tab.geography': 'Geography', 'profile.specialist.categories': 'Work categories', 'profile.specialist.categories.desc': 'Select the categories you work in', 'profile.specialist.geography': 'Coverage areas', 'profile.specialist.geography.desc': 'Select the cities / districts where you are active', 'profile.saving': 'Saving...', 'profile.upload.error': 'Error uploading photo', 'profile.saved': 'Saved', 'profile.tab.cards': 'Portfolio', 'profile.cards.count': 'Portfolio', 'profile.cards.add': 'Add portfolio', 'profile.cards.new_title': 'New portfolio title', 'profile.cards.placeholder': 'e.g. Plumbing', 'profile.cards.create': 'Create', 'profile.cards.cancel': 'Cancel', 'profile.cards.empty': 'No portfolio yet', 'profile.cards.create_first': 'Create your first portfolio', 'profile.cards.delete_confirm': 'Delete portfolio?', 'profile.card.tab.main': 'General', 'profile.card.tab.skills': 'Skills', 'profile.card.tab.categories': 'Categories', 'profile.card.tab.geography': 'Geography', 'profile.card.tab.portfolio': 'Portfolio', 'profile.card.active': 'Active', 'profile.card.save': 'Save', 'profile.card.saved': 'Saved', 'profile.card.delete': 'Delete', 'profile.card.skill.add': 'Add skill', 'profile.card.photo.add': 'Add photo', 'profile.card.photo.uploading': 'Uploading...', 'profile.card.photo.empty': 'No photos yet', 'profile.card.item.title': 'Title', 'profile.card.item.desc': 'Description', 'profile.card.item.save': 'Save', 'profile.card.item.cancel': 'Cancel', 'profile.card.item.edit': 'Edit', 'profile.upgrade.cards_limit': 'Portfolio limit reached', 'profile.upgrade.plan': 'Current plan:', 'profile.upgrade.contact': 'Contact the administrator to change your plan', 'profile.upgrade.ok': 'Got it', 'profile.plan.title': 'Subscription plan', 'profile.balance': 'Balance', 'profile.balance.topup': 'Top Up Balance', 'profile.balance.topup.title': 'Top Up Balance', 'profile.balance.topup.amount': 'Amount (EUR)', 'profile.balance.topup.hint': 'Choose a preset or enter a custom amount', 'profile.balance.topup.submit': 'Proceed to Payment', 'profile.balance.topup.loading': 'Redirecting...', 'profile.balance.topup.error': 'Payment initiation failed. Please try again.', 'payment.success.title': 'Payment Successful!', 'payment.success.desc': 'Your balance has been updated.', 'payment.cancelled.title': 'Payment Cancelled', 'payment.cancelled.desc': 'Payment was cancelled. No charges were made.', 'payment.pending.title': 'Processing...', 'payment.pending.desc': 'Your payment is being processed.', 'payment.back_to_profile': 'Back to Profile', 'profile.plan.basic': 'Basic (free)', 'profile.plan.contact_upgrade': 'Contact admin to upgrade your plan', 'profile.plan.cards_up_to': 'Portfolio: up to', 'profile.plan.cards_unlimited': 'Portfolio: unlimited', 'profile.plan.tasks_up_to': 'Tasks: up to', 'profile.plan.offers_up_to': 'Offers: up to', 'profile.plan.valid_until': 'Valid until', 'profile.plan.no_expiry': 'No expiry', // Create task 'create.error': 'Error posting task', // Tasks list extras 'tasks.category.general': 'General', 'tasks.budget.range': 'Range:', 'tasks.budget.from': 'from', 'tasks.budget.to': 'to', 'tasks.filter.reset': 'Reset filters', 'tasks.load_more': 'Load more', 'tasks.showing': 'Results:', 'tasks.field.budget': 'Budget, €', // Admin 'admin.title': 'Admin Panel', 'admin.tab.stats': 'Statistics', 'admin.tab.users': 'Users', 'admin.tab.tasks': 'Tasks', 'admin.tab.reports': 'Reports', 'admin.stats.users': 'Users', 'admin.stats.tasks': 'Tasks', 'admin.stats.offers': 'Offers', 'admin.stats.reviews': 'Reviews', 'admin.tasks.by_status': 'Tasks by status', 'admin.col.user': 'User', 'admin.col.email': 'Email', 'admin.col.role': 'Role', 'admin.col.registered': 'Registered', 'admin.col.status': 'Status', 'admin.col.title': 'Title', 'admin.col.budget': 'Budget', 'admin.col.created': 'Created', 'admin.users.active': 'Active', 'admin.users.inactive': 'Inactive', 'admin.users.deactivate': 'Deactivate', 'admin.users.activate': 'Activate', 'admin.tasks.cancel': 'Cancel', 'admin.reports.none': 'No reports', 'admin.reports.reviewed': 'Reviewed', 'admin.reports.dismiss': 'Dismiss', 'admin.pagination.total': 'Total', 'admin.users.role.change': 'Change role', 'admin.users.search.placeholder': 'Search name or email...', 'admin.tasks.delete': 'Delete', 'admin.tasks.delete.confirm': 'Permanently delete this task?', 'admin.tasks.search.placeholder': 'Search title...', 'admin.col.customer': 'Customer', 'admin.col.reporter': 'Reporter', 'admin.col.target': 'Target', 'admin.filter.all_roles': 'All roles', 'admin.filter.all_statuses': 'All statuses', 'admin.reports.target.task': 'Task', 'admin.reports.target.user': 'User', 'admin.tab.categories': 'Categories', 'admin.tab.locations': 'Cities & Districts', 'admin.tab.logs': 'Logs', 'admin.tab.plans': 'Plans', 'admin.tab.settings': 'Settings', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Activity', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Notifications', 'admin.notif_logs.type': 'Type', 'admin.notif_logs.title': 'Title', 'admin.notif_logs.read': 'Read', 'admin.notif_logs.empty': 'No notification logs', 'admin.stats.notif_chart_title': 'Notifications per day', 'admin.stats.notif_label': 'Notifications', 'admin.stats.mail_chart_title': 'Emails per day', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'All', 'admin.stats.specialists': 'Specialists', 'admin.col.plan': 'Plan', 'admin.back_home': 'Home', 'admin.plans.title': 'Subscription plans', 'admin.plans.add': '+ New plan', 'admin.plans.empty': 'No plans created', 'admin.plans.form.new': 'New plan', 'admin.plans.form.edit': 'Edit plan', 'admin.plans.form.name': 'Name', 'admin.plans.form.price': 'Price (EUR)', 'admin.plans.form.old_price': 'Old price (EUR, optional)', 'admin.plans.form.max_offers': 'Max offers (empty = no limit)', 'admin.plans.form.max_cards': 'Max portfolio (empty = no limit)', 'admin.plans.form.duration_days': 'Duration (days, empty = no expiry)', 'admin.plans.form.description': 'Description', 'admin.plans.form.features': 'Features (one per line)', 'admin.plans.form.notify': 'Notify about new tasks', 'admin.plans.form.default': 'Default', 'admin.plans.form.active': 'Active', 'admin.plans.form.order': 'Order', 'admin.plans.form.role': 'Role', 'admin.plans.form.tier': 'Tier', 'admin.plans.form.role.customer': 'Customer', 'admin.plans.form.role.specialist': 'Specialist', 'admin.plans.form.tier.free': 'Free', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Limits (empty = unlimited)', 'admin.plans.form.max_messages_day': 'Max Messages/Day', 'admin.plans.form.max_orders_day': 'Max Orders/Day', 'admin.plans.form.max_skills': 'Max Skills', 'admin.plans.form.max_profiles': 'Max Profiles', 'admin.plans.form.max_portfolio': 'Max Portfolio Items', 'admin.plans.form.section.boost': 'Multipliers & Boost', 'admin.plans.form.search_boost': 'Search Boost', 'admin.plans.form.offers_multiplier': 'Offers Multiplier', 'admin.plans.form.section.contact': 'Contact Permissions', 'admin.plans.form.can_contact_free': 'Contact Free Plan users', 'admin.plans.form.can_contact_pro': 'Contact Pro Plan users', 'admin.plans.form.can_contact_all': 'Contact All users', 'admin.plans.form.can_show_contact': 'Show Contact Info', 'admin.plans.form.can_view_phone': 'View Phone', 'admin.plans.form.section.features': 'Feature Flags', 'admin.plans.form.upload_video': 'Upload Video', 'admin.plans.form.favorites': 'Favorites', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Verified Badge', 'admin.plans.form.highlighted_reviews': 'Highlighted Reviews', 'admin.plans.form.personal_site': 'Personal Site', 'admin.plans.form.can_help_now': 'Can Help Now Status', 'admin.plans.form.need_help': 'Need Help Status', 'admin.plans.form.auto_response': 'Auto Response', 'admin.plans.form.auto_match': 'Auto Match', 'admin.plans.form.instant_dispatch_free': 'Instant Dispatch (Free)', 'admin.plans.form.instant_dispatch_pro': 'Instant Dispatch (Pro)', 'admin.plans.badge.default': 'Default', 'admin.plans.badge.inactive': 'Inactive', 'admin.plans.make_default': 'Set as default', 'admin.plans.tasks': 'Tasks', 'admin.plans.offers': 'Offers', 'admin.plans.cards': 'Portfolio', 'admin.plans.notify_tasks': 'Task notifications', 'admin.plans.delete.confirm': 'Delete plan', 'admin.activity.title': 'Activity log', 'admin.activity.event': 'Event', 'admin.activity.all_events': 'All events', 'admin.activity.from': 'From', 'admin.activity.to': 'To', 'admin.activity.reset': 'Reset', 'admin.activity.total': 'Total', 'admin.activity.empty': 'No records', 'admin.mail.event': 'Email event', 'admin.mail.all_events': 'All email events', 'admin.mail.from': 'From', 'admin.mail.to': 'To', 'admin.mail.reset': 'Reset', 'admin.mail.total': 'Total', 'admin.mail.empty': 'No email logs', 'admin.mail.recipient': 'Recipient', 'admin.mail.provider': 'Provider', 'admin.mail.details': 'Details', 'admin.mail.status': 'Status', 'admin.mail.success': 'Success', 'admin.mail.failed': 'Failed', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'No records', 'admin.logs.date': 'Date', 'admin.logs.provider': 'Provider', 'admin.logs.model': 'Model', 'admin.logs.action': 'Action', 'admin.logs.langs': 'Languages', 'admin.logs.in': 'In', 'admin.logs.out': 'Out', 'admin.logs.total': 'Total', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Status', 'admin.stats.activity_30d': 'Activity over 30 days', 'admin.stats.tasks_label': 'Tasks', 'admin.stats.users_label': 'Users', 'admin.stats.specialists_label': 'Specialists', 'admin.stats.tokens_title': 'Token usage (by month)', 'admin.stats.tokens_out': 'Output', 'admin.stats.tokens_in': 'Input', 'admin.stats.tokens_out_label': 'Output tokens', 'admin.stats.tokens_in_label': 'Input tokens', 'admin.stats.cost_label': 'Cost (USD)', 'admin.stats.tasks_by_status': 'Tasks by status', 'admin.task_status.open': 'Open', 'admin.task_status.in_progress': 'In progress', 'admin.task_status.completed': 'Completed', 'admin.task_status.cancelled': 'Cancelled', 'admin.task_status.draft': 'Drafts', 'admin.settings.tab.general': 'General', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Notifications', 'admin.settings.tab.payment': 'Payment', 'admin.settings.tab.referral': 'Referrals', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Socials', 'admin.settings.socials.title': 'Social Network Links', 'admin.settings.socials.hint': 'Filled links are displayed in the site footer', 'admin.settings.seo.maintenance_label': 'Maintenance Mode', 'admin.settings.seo.maintenance_hint': 'Show a maintenance page to all visitors', 'admin.settings.seo.indexing_label': 'Search Engine Indexing', 'admin.settings.seo.indexing_hint': 'Allow search engines to index the site', 'admin.settings.seo.head_scripts_label': ' Scripts (JS)', 'admin.settings.seo.head_scripts_hint': 'Runs on every page (Google Tag Manager, analytics, etc.)', 'admin.settings.seo.site_title_label': 'Site Title', 'admin.settings.seo.site_description_label': 'Site Description (meta description)', 'admin.settings.referral.title': 'Referral program', 'admin.settings.referral.hint': 'Reward users who bring new registrations.', 'admin.settings.referral.enabled_label': 'Enabled', 'admin.settings.referral.enabled_hint': 'Enable / disable reward application', 'admin.settings.referral.customer_section': 'For customers', 'admin.settings.referral.specialist_section': 'For specialists', 'admin.settings.referral.plan_label': 'Reward plan', 'admin.settings.referral.no_plan': '— no plan —', 'admin.settings.referral.plan_hint': 'This plan will be assigned to the referrer. If their current plan is higher, only days will be added.', 'admin.settings.referral.days_label': 'Reward days', 'admin.settings.referral.days_hint': 'Number of days added to the plan expiry.', 'admin.settings.general.title': 'General settings', 'admin.settings.general.site_name': 'Site name', 'admin.settings.general.site_url': 'Site URL', 'admin.settings.general.contact_email': 'Contact email', 'admin.settings.general.support_phone': 'Support phone', 'admin.settings.smtp.title': 'SMTP settings', 'admin.settings.smtp.hint': 'Used to send email notifications.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Port', 'admin.settings.smtp.encryption': 'Encryption', 'admin.settings.smtp.enc.none': 'None', 'admin.settings.smtp.enc.tls': 'STARTTLS (port 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (port 465)', 'admin.settings.smtp.username': 'Username', 'admin.settings.smtp.password': 'Password / App Password', 'admin.settings.smtp.from_name': 'Sender name', 'admin.settings.smtp.from_email': 'Sender email', 'admin.settings.smtp.test': 'Send test email', 'admin.settings.smtp.sending': 'Sending...', 'admin.settings.payment.hint': 'ePay Piraeus Bank credentials.', 'admin.settings.env.test': 'Test (sandbox)', 'admin.settings.env.prod': 'Production', 'admin.settings.env.label': 'Environment', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Active', 'admin.settings.saving': 'Saving...', 'admin.settings.saved': 'Saved', 'admin.notif.vars_hint': 'Available variables in templates', 'admin.notif.tmpl.not_set': 'Template not configured', 'admin.notif.tmpl.subject_label': 'Email subject', 'admin.notif.tmpl.body_label': 'Email body (HTML)', 'admin.notif.tmpl.save': 'Save', 'admin.notif.tmpl.close': 'Close', 'admin.notif.tmpl.translate': 'Auto-translate to other languages', 'admin.notif.tmpl.translating': 'Translating...', 'admin.notif.tmpl.saving': 'Saving...', 'admin.notif.email_verification': 'Email verification', 'admin.notif.registration_success': 'Successful registration', 'admin.notif.password_reset': 'Password reset', 'admin.notif.new_offer': 'New offer', 'admin.notif.new_task': 'New task', 'admin.notif.offer_accepted': 'Offer accepted', 'admin.notif.new_message': 'New message', 'admin.notif.offer_declined': 'Offer declined', 'admin.notif.offer_other_accepted': 'Another specialist chosen', 'admin.notif.task_updated': 'Task updated', 'admin.notif.deadline_reminder': 'Deadline reminder', 'admin.notif.task_archived': 'Task unpublished automatically', 'admin.notif.referral_reward': 'Referral reward', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Plan activated', 'admin.email_template.plan_upgraded': 'Plan upgraded', 'admin.email_template.plan_downgrade_scheduled': 'Downgrade scheduled', 'admin.email_template.plan_downgrade_applied': 'Downgrade applied', 'admin.email_template.plan_renewal_reminder': 'Renewal reminder', 'admin.email_template.plan_insufficient_funds': 'Insufficient funds warning', // Pricing confirm modal 'pricing.confirm.title': 'Confirm plan selection', 'pricing.confirm.plan': 'Plan', 'pricing.confirm.prorated': 'Prorated credit', 'pricing.confirm.effective_price': 'Amount due', 'pricing.confirm.your_balance': 'Your balance', 'pricing.confirm.downgrade_info': 'The switch to the new plan will happen automatically after the current period ends.', 'pricing.confirm.insufficient': 'Insufficient balance.', 'pricing.confirm.top_up': 'Top up', 'pricing.confirm.schedule_downgrade': 'Schedule downgrade', 'pricing.confirm.pay': 'Pay', 'admin.user_edit.title': 'Edit user', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email verified', 'admin.user_edit.email_not_verified': 'Email not verified', 'admin.user_edit.verify_email_btn': 'Verify manually', 'admin.user_edit.verify_email_done': 'Email verified!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Registered', 'admin.user_edit.last_seen': 'Last seen', 'admin.user_edit.lang': 'Language', 'admin.user_edit.first_name': 'First name', 'admin.user_edit.last_name': 'Last name', 'admin.user_edit.phone': 'Phone', 'admin.user_edit.bio': 'Bio', 'admin.user_edit.role': 'Role', 'admin.user_edit.plan': 'Plan', 'admin.user_edit.no_plan': '— No plan —', 'admin.user_edit.active': 'Active account', 'admin.user_edit.balance': 'Balance (EUR)', 'admin.user_edit.skills': 'Skills', 'admin.user_edit.tab.profile': 'Profile', 'admin.user_edit.tab.account': 'Account', 'admin.user_edit.tab.balance': 'Balance', 'admin.user_edit.tab.settings': 'Settings', 'admin.user_edit.tab.specialist': 'Portfolio', 'admin.user_edit.tab.site': 'Website', 'admin.user_edit.plan_expires': 'Plan expires', 'admin.user_edit.interface_lang': 'Interface language', 'admin.user_edit.comm_languages': 'Communication languages', 'admin.user_edit.personal_site_slug': 'Personal page', 'admin.user_edit.show_contact_info': 'Show contact info', 'admin.user_edit.show_contact_info.hint': 'Visible to customers', 'admin.user_edit.notify_new_tasks': 'Notify about new tasks', 'admin.user_edit.notify_new_tasks.hint': 'Push and email notifications', 'admin.user_edit.notif_messages': 'Message notifications', 'admin.user_edit.notif_messages.hint': 'New messages in chat', 'admin.user_edit.site_settings': 'Personal page settings', 'admin.user_edit.categories': 'Service categories', 'admin.user_edit.locations': 'Service areas', 'admin.user_edit.skill_placeholder': 'New skill...', 'admin.user_edit.add_category': '— Select category —', 'admin.user_edit.add_location': '— Select location —', 'admin.user_edit.specialist_cards': 'Portfolio', 'admin.user_edit.no_cards': 'No portfolio found', 'admin.user_edit.card_title': 'Portfolio title', 'admin.user_edit.card_description': 'Description', 'admin.balance.topup.btn': 'Top up', 'admin.balance.withdraw.btn': 'Withdraw', 'admin.balance.modal_hint': 'Changes take effect immediately and are recorded in history', 'admin.balance.topup.title': 'Top up balance', 'admin.balance.topup.amount': 'Amount', 'admin.balance.topup.description': 'Comment', 'admin.balance.topup.description.placeholder': 'For example: bonus or manual top-up', 'admin.balance.topup.submit': 'Top up balance', 'admin.balance.withdraw.title': 'Withdraw balance', 'admin.balance.withdraw.amount': 'Amount', 'admin.balance.withdraw.description': 'Comment', 'admin.balance.withdraw.description.placeholder': 'For example: refund or manual debit', 'admin.balance.withdraw.submit': 'Withdraw from balance', 'admin.user_edit.role.customer': 'Customer', 'admin.user_edit.role.specialist': 'Specialist', 'admin.user_edit.role.admin': 'Administrator', 'common.refresh': 'Refresh', 'common.back_home': 'Home', 'admin.loc.hint': 'Manage cities and districts', 'admin.loc.add_city': 'New city', 'admin.loc.add_district': 'Add district', 'admin.loc.new': 'New location', 'admin.loc.edit': 'Edit location', 'admin.loc.district': 'district', 'admin.loc.empty': 'No locations', 'admin.loc.delete.confirm': 'Delete location? All districts will also be deleted.', 'admin.cat.add_root': 'New category', 'admin.cat.add_sub': 'Subcategory', 'admin.cat.edit': 'Edit', 'admin.cat.delete': 'Delete', 'admin.cat.delete.confirm': 'Delete category? All subcategories will also be deleted.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Icon', 'admin.cat.name_el': 'Greek', 'admin.cat.name_en': 'English', 'admin.cat.name_ru': 'Russian', 'admin.cat.order': 'Order', 'admin.cat.active': 'Active', 'admin.cat.parent': 'Parent category', 'admin.cat.no_parent': 'Top level', 'admin.cat.save': 'Save', 'admin.cat.cancel': 'Cancel', 'admin.cat.empty': 'No categories', 'admin.cat.hint': 'Manage categories with multi-level hierarchy', 'admin.cat.new': 'New category', 'admin.cat.subcategory': 'subcategory', 'admin.cat.add_child': 'Add subcategory', 'admin.cat.inactive': 'Inactive', 'admin.event.user_login': 'Login', 'admin.event.user_register': 'Registration', 'admin.event.admin_user_deactivate': 'User blocked', 'admin.event.admin_user_activate': 'User activated', 'admin.event.admin_user_role_changed': 'Role changed', 'admin.event.admin_task_cancelled': 'Task cancelled', 'admin.event.admin_task_deleted': 'Task deleted', 'admin.event.admin_report_reviewed': 'Report reviewed', 'admin.event.admin_report_dismissed': 'Report dismissed', 'admin.event.task_created': 'Task created', // User status 'user.online': 'Online', 'user.seen_minutes': 'was here {n} min ago', 'user.seen_hours': 'was here {n} hr ago', 'user.seen_yesterday': 'was here yesterday', 'user.seen_days': 'was here {n} days ago', // Specialists 'specialists.title': 'Specialists', 'specialists.search': 'Search specialist...', 'specialists.search.btn': 'Search', 'specialists.empty': 'No specialists found', 'specialists.no_bio': 'No description', 'specialists.view': 'View profile', 'specialists.reviews': 'reviews', 'specialist.favorite': 'Add to favorites', 'specialist.unfavorite': 'Remove from favorites', 'specialist.site_link': 'Personal site', 'favorites.specialists.title': 'Favourite specialists', 'favorites.specialists.empty': 'No favourite specialists yet', 'nav.favorites': 'Favourites', 'nav.schedule': 'Schedule', 'nav.find_tasks': 'Find Orders', 'schedule.title': 'My Schedule', 'schedule.subtitle': 'Mark the days when you are free or busy — clients will see your availability', 'schedule.available': 'Available', 'schedule.busy': 'Busy', 'schedule.unset': 'Not set', 'schedule.click_hint': '← click to cycle status', 'schedule.range_mode': 'Select range', 'schedule.range_from': 'From {date} — select end date', 'schedule.click_to_set': 'Click to set', 'schedule.free': 'free', 'schedule.busy_count': 'busy', 'schedule.free_days': 'free days', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Connect Google Calendar', 'schedule.disconnectGoogle': 'Disconnect', 'schedule.connectedAs': 'Connected as', 'schedule.importFromGoogle': 'Sync from Google', 'schedule.gcalConnected': '\u2713 Google Calendar connected', 'schedule.gcalError': 'Google Calendar connection error', 'schedule.gcalImportDone': 'Imported {n} days from Google Calendar', 'schedule.gcalAutoSyncNote': 'Availability changes are automatically synced to Google Calendar', 'schedule.gcalConnectDesc': 'Connect Google Calendar to automatically sync your availability', 'schedule.gcalDisconnectConfirm': 'Disconnect Google Calendar?', 'find_tasks.title': 'Find Orders', 'find_tasks.for_me': 'For me', 'find_tasks.all': 'All orders', 'find_tasks.by_category': 'By category', 'find_tasks.list': 'List', 'find_tasks.already_offered': 'Offer sent', 'find_tasks.offer_now': 'Make an offer', 'find_tasks.empty_for_me': 'No tasks found in your categories', 'find_tasks.banner_hint': 'Find tasks matching your portfolio categories', 'find_tasks.no_cards': 'Create a specialist portfolio to see tasks matched to you', 'find_tasks.add_card': 'Create portfolio', 'find_tasks.search': 'Search tasks...', 'find_tasks.tasks_count': 'tasks', 'footer.tagline': 'The task platform for Greece', 'footer.rights': 'All rights reserved.', // App download section 'app.download_title': 'Download the CanHelp mobile app', 'app.download_desc': 'All of CanHelp — always at your fingertips. Available for Android and iOS.', // Nav 'nav.pricing': 'Pricing', // Pricing page 'pricing.title': 'Pricing', 'pricing.subtitle': 'Choose the right plan for you', 'pricing.role.customer': 'Customer', 'pricing.role.specialist': 'Specialist', 'pricing.free': 'Free', 'pricing.per_month': 'mo', 'pricing.duration': 'Duration', 'pricing.days': 'days', 'pricing.current_plan': 'Your plan', 'pricing.popular': 'Popular', 'pricing.choose': 'Choose', 'pricing.your_plan': 'Active plan', 'pricing.free_default': 'Default', 'pricing.compare': 'Compare features', 'pricing.feature': 'Feature', 'pricing.faq_note': 'Payment is deducted from your CanHelp balance. Top up available in Payments.', 'pricing.feat.messages': 'Messages / day', 'pricing.feat.orders': 'Orders / day', 'pricing.feat.contact_all': 'Contact everyone', 'pricing.feat.view_phone': 'View phone number', 'pricing.feat.show_contact': 'Show contact info', 'pricing.feat.favorites': 'Favorites', 'pricing.feat.verified_badge': 'Verified badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Personal site', 'pricing.feat.auto_response': 'Auto-response', 'pricing.feat.auto_match': 'Auto-match', 'pricing.feat.highlighted_reviews': 'Highlighted reviews', 'pricing.feat.portfolio': 'Portfolio items', 'pricing.feat.cards': 'Specialist cards', 'pricing.feat.notify_tasks': 'New task notifications', 'pricing.feat.video': 'Video in portfolio', // Upgrade prompt 'upgrade.available_in': 'Available in', 'upgrade.cta': 'Upgrade', // Dashboard plan block 'dashboard.plan.title': 'My Plan', 'dashboard.plan.expires': 'Expires in {n} days', 'dashboard.plan.upgrade': 'Upgrade plan', 'dashboard.plan.no_plan': 'Free plan', 'dashboard.plan.messages': 'Messages today', 'dashboard.plan.orders': 'Orders today', 'dashboard.plan.limits': 'Daily limits', 'dashboard.plan.features': 'Features', 'dashboard.plan.stats': 'Stats', 'dashboard.stats.cards': 'Portfolios', 'dashboard.stats.maxCards': 'Max portfolios', 'dashboard.stats.portfolioItems': 'Portfolio items', 'dashboard.stats.maxPortfolioItems': 'Max items', 'dashboard.stats.activeOffers': 'Active offers', 'dashboard.stats.reviewsReceived': 'Reviews', 'dashboard.stats.activeTasks': 'Active tasks', 'dashboard.stats.completedTasks': 'Completed', 'status.need_help': 'I need help', 'status.active': 'Active', 'status.toggle_on': 'Enable', 'status.toggle_off': 'Disable', // FOMO 'fomo.missed_orders': 'Missed {n} orders', 'fomo.missed_value': 'Worth €{v}', 'fomo.upgrade_hint': 'Upgrade to receive more orders', 'fomo.conversion': 'Task conversion', 'fomo.active': 'Active', 'fomo.with_offers': 'With offers', 'fomo.completed': 'Completed', 'fomo.already_offered': '{n} specialists have already responded', 'fomo.specialist_missed': 'You missed {n} orders', 'fomo.top_categories': 'Categories', 'fomo.offers_received': 'offers received', 'fomo.avg_offers': 'Avg {n}/task', 'fomo.completion_rate': 'completed', // Task auto-match 'task.auto_match': 'Auto-match', 'task.auto_match_results': 'Top specialists', 'task.no_offer_yet': 'You haven\'t sent an offer yet', 'task.make_offer': 'Send offer', 'auto_response.title': 'Auto-Response', 'auto_response.enabled': 'Enable auto-response', 'auto_response.min_budget': 'Min budget', 'auto_response.max_budget': 'Max budget', 'auto_response.default_price': 'Default price', 'auto_response.default_message': 'Default message', 'auto_response.max_per_day': 'Max auto-offers per day', 'auto_response.save': 'Save', 'auto_response.saved': 'Saved', 'auto_response.categories': 'Categories', 'auto_response.locations': 'Locations', // Personal site 'profile.personal_site': 'Personal Site', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Only latin letters, numbers, - and _', 'profile.site_open': 'Open site', 'profile.site_preview': 'Your site', 'profile.show_contact': 'Show contact info', 'profile.show_contact_hint': 'Customers with Pro/Ultimate plans will see your phone number', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Calendar requires a Pro or Ultimate plan', // Chat limits 'chat.limit_warning': '{n} messages left today', 'chat.limit_reached': 'Message limit reached. Upgrade your plan', 'chat.upgrade': 'Upgrade', // Site page 'site.member_since': 'Member since', 'site.rating': 'Rating', 'site.completed_tasks': 'Completed', 'site.languages': 'Languages', 'site.photos': 'photos', 'site.contact_form': 'Get in touch', 'site.contact_sent': 'Message sent!', 'site.contact_sent_desc': 'The specialist will contact you soon', 'site.contact_name': 'Name', 'site.contact_name_ph': 'Your name', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Message', 'site.contact_message_ph': 'Describe your task...', 'site.contact_send': 'Send', 'site.share': 'Share', 'site.speaks_languages': 'Speaks', 'site.message_sent': 'Message sent!', 'site.message_sent_desc': 'The specialist will receive it in the chat', 'site.message_placeholder': 'Write your message...', 'site.write_to_chat': 'Write to chat', 'site.auth_required_title': 'Sign in required', 'site.auth_required_desc': 'To write in the chat, you need to sign in to your CanHelp account.', 'site.auth_login_btn': 'Sign in', 'site.auth_contact_form_btn': 'Contact via feedback form', 'specialist.services': 'Services', 'portfolio.title': 'Portfolio', 'status.can_help_now': 'Available now', 'common.not_found': 'Page not found', 'common.anonymous': 'Anonymous', 'specialist_setup.page_title': 'Specialist profile setup', 'specialist_setup.step_of': 'Step {current} of {total}', 'specialist_setup.next': 'Next', 'specialist_setup.back': 'Back', 'specialist_setup.skip': 'Skip', 'specialist_setup.finish': 'Finish', 'specialist_setup.go_to_profile': 'Go to profile', 'specialist_setup.browse_tasks': 'Browse tasks', 'specialist_setup.step1.title': 'Welcome!', 'specialist_setup.step1.subtitle': "Let's set up your profile", 'specialist_setup.step1.desc': 'A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.', 'specialist_setup.step1.what_next': 'What we will do:', 'specialist_setup.step1.item1': 'Fill in basic information', 'specialist_setup.step1.item2': 'Create a service card', 'specialist_setup.step1.item3': 'Add skills and categories', 'specialist_setup.step1.item4': 'Select service area', 'specialist_setup.step1.item5': 'Upload portfolio photos', 'specialist_setup.step2.title': 'Basic profile', 'specialist_setup.step2.subtitle': 'Tell us about yourself', 'specialist_setup.step2.bio_label': 'About me', 'specialist_setup.step2.bio_placeholder': 'Describe your experience, services you offer...', 'specialist_setup.step2.phone_label': 'Phone', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Profile photo', 'specialist_setup.step2.photo_btn': 'Upload photo', 'specialist_setup.step2.photo_uploading': 'Uploading...', 'specialist_setup.step2.photo_hint': 'Shown on your profile', 'specialist_setup.step3.title': 'Service card', 'specialist_setup.step3.subtitle': 'Create your first service card', 'specialist_setup.step3.title_label': 'Card title', 'specialist_setup.step3.title_placeholder': 'E.g. Plumber, Electrician, Cleaning...', 'specialist_setup.step3.desc_label': 'Description', 'specialist_setup.step3.desc_placeholder': 'Describe in detail what you offer, your experience, advantages...', 'specialist_setup.step3.title_required': 'Title is required', 'specialist_setup.step4.title': 'Skills & Categories', 'specialist_setup.step4.subtitle': 'Add skills and select categories', 'specialist_setup.step4.skills_label': 'Skills', 'specialist_setup.step4.skills_placeholder': 'E.g. Pipe installation...', 'specialist_setup.step4.skills_add': 'Add', 'specialist_setup.step4.categories_label': 'Categories', 'specialist_setup.step5.title': 'Service area', 'specialist_setup.step5.subtitle': 'Where do you provide services?', 'specialist_setup.step5.hint': 'Select cities or specific areas', 'specialist_setup.done.title': 'Your profile is ready!', 'specialist_setup.done.subtitle': 'Congratulations! Your profile has been set up', 'specialist_setup.done.desc': 'You can now receive orders from clients. Browse tasks that match your skills.' }, ru: { 'footer.slogan': 'Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.', 'footer.links': 'Ссылки', 'footer.socials': 'Мы в соцсетях', 'nav.home': 'Главная', 'nav.tasks': 'Задачи', 'nav.post': '+ Опубликовать', 'nav.dashboard': 'Панель управления', 'nav.chat': 'Сообщения', 'nav.notifications': 'Уведомления', 'nav.profile': 'Профиль', 'nav.admin': 'Админка', 'nav.specialists': 'Специалисты', 'nav.new_task': 'Новая задача', 'nav.login': 'Войти', 'nav.register': 'Регистрация', 'nav.logout': 'Выйти', 'hero.title': 'Найди специалиста для любой работы', 'hero.subtitle': 'Опубликуй задачу, получи предложения и выбери лучшего профессионала', 'hero.cta.post': 'Опубликовать задачу', 'hero.cta.browse': 'Стать специалистом', 'hero.search.placeholder': 'Что нужно? напр. электрик, уборка...', 'stats.specialists': 'специалистов', 'stats.tasks': 'задач', 'stats.categories': 'категорий', 'stats.free': 'бесплатная регистрация', 'section.categories': 'Создай задачу в любой категории', 'section.how': 'Как это работает', 'section.recent': 'Последние задачи', 'section.all': 'Смотреть все →', 'section.more': 'ещё', 'section.cities': 'Города и районы', 'section.community': 'Общественный проект для всех', 'community.subtitle': 'CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.', 'community.point1.title': 'Умеете что-то делать?', 'community.point1.desc': 'Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.', 'community.point2.title': 'Нужна помощь?', 'community.point2.desc': 'Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.', 'community.point3.title': 'Помогите проекту расти', 'community.point3.desc': 'CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.', 'community.share': 'Поделиться с друзьями', 'community.share.copied': 'Ссылка скопирована!', // Referral section on home page 'section.referral': 'Реферальная программа', 'referral.home.subtitle': 'Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.', 'referral.home.step1.title': 'Зарегистрируйтесь и получите ссылку', 'referral.home.step1.desc': 'Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.', 'referral.home.step2.title': 'Поделитесь с друзьями', 'referral.home.step2.desc': 'Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.', 'referral.home.step3.title': 'Получайте награды', 'referral.home.step3.desc': 'Как только друг подтвердит email, вы автоматически получите свою награду.', 'referral.home.cta': 'Получить ссылку', 'referral.home.badge': 'Реферальная программа', // FAQ section 'section.faq': 'Частые вопросы', 'faq.q1': 'Как работает CanHelp?', 'faq.a1': 'Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.', 'faq.q2': 'Сколько стоит использование платформы?', 'faq.a2': 'Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.', 'faq.q3': 'Как стать специалистом?', 'faq.a3': 'Зарегистрируйтесь, перейдите в «Стать специалистом», заполните профиль навыками и категориями и начните получать задачи.', 'faq.q4': 'Как выбрать подходящего специалиста?', 'faq.a4': 'Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.', 'faq.q5': 'Что если я не доволен результатом?', 'faq.a5': 'Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.', 'faq.q6': 'Можно ли связаться со специалистом до принятия предложения?', 'faq.a6': 'Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.', 'faq.q7': 'Сколько времени ждать предложений?', 'faq.a7': 'Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.', 'faq.q8': 'Можно ли разместить задачу в любом городе Греции?', 'faq.a8': 'Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.', 'faq.q9': 'Какие виды задач есть на CanHelp?', 'faq.a9': 'Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.', 'faq.q10': 'Есть ли мобильное приложение?', 'faq.a10': 'Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.', 'how.step1.title': 'Опубликуй задачу', 'how.step1.desc': 'Опиши что нужно и установи бюджет', 'how.step2.title': 'Получи предложения', 'how.step2.desc': 'Специалисты пришлют предложения с ценой и сроками', 'how.step3.title': 'Выбери и начни', 'how.step3.desc': 'Выбери лучшего профессионала и начни сотрудничество', 'tasks.title': 'задач', 'tasks.filters': 'Фильтры', 'tasks.search': 'Поиск', 'tasks.search.placeholder': 'Название или ключевое слово...', 'tasks.search.btn': 'Поиск', 'tasks.publish': 'Опубликовать', 'tasks.category.all': 'Все', 'tasks.category.all_in': 'Все в', 'tasks.category.label': 'Категория', 'tasks.location.label': 'Город', 'tasks.location.placeholder': 'напр. Афины', 'tasks.empty': 'Задачи не найдены', 'tasks.empty.cta': 'Опубликуй первую', 'task.status.open': 'Открыта', 'task.status.in_progress': 'В работе', 'task.status.completed': 'Завершена', 'task.status.cancelled': 'Отменена', 'task.status.draft': 'Черновик', 'task.budget': 'Бюджет', 'task.location': 'Местоположение', 'task.deadline': 'Дата начала', 'task.created_at': 'Создано', 'task.customer': 'Заказчик', 'task.offer.btn': 'Отправить предложение', 'task.invite.banner_title': 'Вас пригласили на это задание', 'task.invite.banner_hint': 'Заказчик лично пригласил вас', 'task.invite.accept': 'Отправить предложение', 'task.invite.decline': 'Отказаться', 'offer.accept': 'Принять', 'offer.decline': 'Отклонить', 'task.complete': 'Завершить задачу', 'task.complete.confirm': 'Отметить задачу как выполненную?', 'task.edit': 'Редактировать', 'task.status_label': 'Статус', 'task.yours': 'Ваша задача', 'task.offer.yours': 'Ваше предложение', 'review.leave': 'Оставить отзыв', 'review.rating': 'Оценка', 'review.comment': 'Комментарий', 'review.comment.placeholder': 'Расскажите о своём опыте...', 'review.submit': 'Отправить отзыв', 'review.submitting': 'Отправка...', 'review.done': 'Отзыв отправлен!', 'profile.reviews': 'Отзывы', 'profile.no_reviews': 'Отзывов пока нет', 'profile.rating': 'Рейтинг', 'profile.skills.label': 'Навыки', 'profile.member_since': 'Участник с', 'task.offers': 'Предложения', 'task.offers.none': 'Предложений пока нет', 'create.title': 'Опубликовать задачу', 'create.field.title': 'Название', 'create.field.description': 'Описание', 'create.field.category': 'Категория', 'create.field.category.select': 'Выберите...', 'create.field.location': 'Местоположение', 'create.field.location.any': 'Где угодно', 'create.field.location.all': 'Весь город', 'create.field.budget': 'Бюджет (€)', 'create.field.deadline': 'Дата начала', 'create.field.budget_negotiable': 'Цена обсуждается', 'create.field.time_slot': 'Время выполнения', 'create.field.time_slot.any': 'В любое время', 'create.field.time_slot.morning': 'Утром (08:00–13:00)', 'create.field.time_slot.afternoon': 'Днём (13:00–18:00)', 'create.field.time_slot.evening': 'Вечером (18:00–22:00)', 'create.field.time_slot.weekend': 'Выходной', 'create.field.address': 'Адрес (необязательно)', 'create.field.address.district': 'Квартал', 'create.field.address.street': 'Улица', 'create.field.address.house': 'Дом', 'create.field.confidential': 'Конфиденциальная заметка', 'create.field.confidential.placeholder': 'Детали, видные только назначенному специалисту...', 'create.field.confidential.hint': 'Не отображается публично', 'create.field.photos': 'Фотографии', 'create.field.photos.add': 'Добавить фото', 'create.field.photos.uploading': 'Загрузка...', 'task.budget_negotiable': 'Цена обсуждается', 'task.time_slot': 'Время', 'task.confidential': 'Конфид. заметка', 'create.field.title.placeholder': 'напр. Уборка квартиры 80кв', 'create.field.description.placeholder': 'Подробно опишите что нужно...', 'create.field.location.placeholder': 'напр. Афины, Колонаки', 'create.field.budget.placeholder': 'напр. 100', 'create.submit': 'Опубликовать задачу', 'create.submitting': 'Публикация...', 'login.title': 'Добро пожаловать', 'login.subtitle': 'Вход в CanHelp', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.submitting': 'Вход...', 'login.error': 'Неверный email или пароль', 'login.unverified.title': 'Подтвердите ваш email', 'login.unverified.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'login.unverified.resend': 'Отправить письмо повторно', 'login.unverified.sending': 'Отправка...', 'login.unverified.sent': '✓ Отправлено — проверьте входящие', 'profile.email.verified': 'Email подтверждён', 'profile.email.not_verified': 'Email не подтверждён', 'login.no_account': 'Нет аккаунта?', 'login.register_link': 'Зарегистрироваться', 'login.forgot_password': 'Забыл пароль?', 'login.or_continue_with': 'или продолжите через', 'login.continue_google': 'Войти через Google', 'forgot.title': 'Забыл пароль', 'forgot.subtitle': 'Введите email для получения ссылки восстановления', 'forgot.email': 'Email', 'forgot.submit': 'Отправить ссылку', 'forgot.submitting': 'Отправка...', 'forgot.sent.title': 'Проверьте входящие', 'forgot.sent.desc': 'Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.', 'forgot.back_to_login': 'Вернуться ко входу', 'forgot.error': 'Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.', 'forgot.error.not_found': 'Аккаунт с таким email не найден.', 'forgot.error.send_failed': 'Ошибка отправки письма. Попробуйте позже.', 'reset.title': 'Новый пароль', 'reset.subtitle': 'Введите новый пароль', 'reset.password': 'Новый пароль', 'reset.confirm': 'Подтвердите пароль', 'reset.submit': 'Изменить пароль', 'reset.submitting': 'Сохранение...', 'reset.success': 'Пароль успешно изменён. Перенаправление ко входу...', 'reset.back_to_login': 'Вернуться ко входу', 'reset.error.mismatch': 'Пароли не совпадают', 'reset.error.invalid': 'Недействительная или устаревшая ссылка. Запросите новую.', 'register.title': 'Регистрация', 'register.subtitle': 'Создать аккаунт в CanHelp', 'register.first_name': 'Имя', 'register.last_name': 'Фамилия', 'register.email': 'Email', 'register.password': 'Пароль (мин. 8 символов)', 'register.role': 'Роль', 'register.role.customer': 'Пользователь', 'register.role.customer.desc': 'Публикую задачи', 'register.role.specialist': 'Специалист', 'register.role.specialist.desc': 'Беру задачи', 'register.submit': 'Создать аккаунт', 'register.submitting': 'Регистрация...', 'register.has_account': 'Уже есть аккаунт?', 'register.login_link': 'Войти', 'register.continue_google': 'Зарегистрироваться через Google', 'register.check_email.title': 'Проверьте почту', 'register.check_email.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'register.check_email.login': 'Вернуться к входу', 'dashboard.title': 'Панель управления', 'dashboard.new_task': '+ Новая задача', 'dashboard.my_tasks': 'Мои задачи', 'dashboard.my_offers': 'Мои предложения', 'dashboard.invitations': 'Приглашения на задания', 'dashboard.offers_count': 'предл.', 'dashboard.declined_count': 'откл.', 'dashboard.completed_tasks': 'Завершённые задачи', 'dashboard.completed_offers': 'Завершённые предложения', 'dashboard.review_pending': 'Оценка ещё не оставлена', 'tasks.new.top_specialists': 'Топ специалисты', 'tasks.new.select_category': 'Выберите категорию, чтобы увидеть специалистов', 'tasks.new.invite': 'Предложить работу', 'tasks.new.invited': 'Выбран ✓', 'reviews.count': 'отзывов', 'filter.location': 'Локация', 'filter.language': 'Языки', 'filter.language.any': 'Любой язык', 'filter.category.all': 'Все категории', 'user.categories': 'Категории', 'user.work_area': 'Район работы', 'dashboard.tasks.empty': 'Вы не публиковали задачи', 'dashboard.tasks.empty.cta': 'Опубликуйте первую', 'dashboard.tasks.add_new': 'Добавить новую задачу', 'dashboard.offers.empty': 'Вы не отправляли предложений', 'dashboard.offers.empty.cta': 'Найти задачи', 'dashboard.customer.specialists_title': 'Ищете исполнителя?', 'dashboard.customer.specialists_hint': 'Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи', 'dashboard.customer.specialists_cta': 'Найти исполнителя', 'dashboard.customer.how_title': 'Как это работает', 'dashboard.customer.step1': 'Создайте задачу с описанием и бюджетом', 'dashboard.customer.step2': 'Специалисты пришлют предложения с ценой и сроками', 'dashboard.customer.step3': 'Выберите подходящего и начните работу', 'notif.title': 'Уведомления', 'notif.mark_all': 'Отметить все как прочитанные', 'notif.empty': 'Нет уведомлений', 'notif.type.new_offer': 'Новое предложение', 'notif.type.offer_accepted': 'Ваше предложение принято', 'notif.type.offer_declined': 'Ваше предложение отклонено', 'notif.type.task_completed': 'Задание выполнено', 'notif.type.task_cancelled': 'Задание отменено', 'notif.type.new_message': 'Новое сообщение', 'notif.type.new_review': 'Новый отзыв', 'notif.type.task_invite': 'Приглашение на задание', 'notif.body.new_offer': 'Новое предложение на «{title}»', 'notif.body.offer_accepted': 'Ваше предложение на «{title}» принято', 'notif.body.offer_declined': 'Ваше предложение на «{title}» отклонено', 'notif.body.task_invite': 'Вас приглашают на «{title}»', 'notif.body.new_review': 'Вы получили оценку {rating}★', 'offer.status.pending': 'Ожидает', 'offer.status.accepted': 'Принято', 'offer.status.declined': 'Отклонено', 'offer.status.withdrawn': 'Отозвано', 'offer.status.other_accepted': 'Выбран другой исполнитель', 'common.loading': 'Загрузка...', 'common.error': 'Ошибка', 'common.save': 'Сохранить', 'common.saving': 'Сохранение...', 'common.cancel': 'Отмена', 'common.add': 'Добавить', 'common.close': 'Закрыть', 'common.edit': 'Редактировать', 'common.delete': 'Удалить', 'common.from': 'от', 'common.currency': '€', 'common.greece': 'Греция', // Chat 'chat.connected': 'Подключено', 'chat.disconnected': 'Отключено', 'chat.no_rooms': 'Переписок пока нет', 'chat.task_fallback': 'Задача', 'chat.select': 'Выберите переписку', 'chat.no_messages': 'Сообщений пока нет', 'chat.placeholder': 'Напишите сообщение... (Enter для отправки)', 'chat.conversation_fallback': 'Переписка', 'chat.direct_chat': 'Личный чат', 'chat.linked_task': 'Прикреплённый заказ', 'chat.write_btn': 'Написать', 'chat.just_now': 'только что', 'chat.min_ago': 'м', 'chat.write_specialist': 'Написать специалисту', 'chat.write_customer': 'Написать заказчику', 'chat.notif_settings': 'Настройки уведомлений', 'chat.notif_messages': 'Уведомления о новых сообщениях', 'chat.toast_title': 'Новое сообщение', 'chat.toast_open': 'Открыть чат', // Offer form 'offer.price': 'Цена', 'offer.price.placeholder': 'напр. 80', 'offer.customer_budget': 'Бюджет заказчика', 'offer.message': 'Сообщение', 'offer.optional': 'необязательно', 'offer.message.placeholder': 'Представьтесь, расскажите об опыте и почему вы лучший выбор...', 'offer.submitting': 'Отправка...', // Profile 'profile.photo': 'Фото профиля', 'profile.photo.change': 'Изменить фото', 'profile.photo.hint': 'JPEG, PNG, WebP · до 5MB', 'profile.basic_info': 'Основная информация', 'profile.phone': 'Телефон', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Краткое описание', 'profile.bio.placeholder': 'Расскажите немного о себе...', 'profile.language': 'Язык', 'profile.language.hint': 'Язык интерфейса и email-уведомлений', 'profile.languages': 'Языки общения', 'profile.languages.hint': 'Выберите все языки, на которых вы общаетесь', 'profile.skills': 'Навыки', 'profile.skills.subtitle': 'Добавьте услуги, которые вы предлагаете', 'profile.skills.placeholder': 'напр. Уборка, IT, Репетиторство...', 'profile.role': 'Роль аккаунта', 'profile.role.specialist': '🔧 Специалист', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Пользователь', 'profile.role.change': 'Для смены роли обратитесь в службу поддержки.', 'profile.become_specialist': 'Стать специалистом', 'profile.become_specialist.desc': 'Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.', 'become_specialist.hero.title': 'Зарабатывай, делая то, что умеешь', 'become_specialist.hero.subtitle': 'Создай профиль специалиста и получай заказы от клиентов по всей Греции', 'become_specialist.how.title': 'Как это работает', 'become_specialist.step1.title': 'Создай портфолио специалиста', 'become_specialist.step1.desc': 'Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы', 'become_specialist.step2.title': 'Ищи заказы', 'become_specialist.step2.desc': 'Просматривай задачи по своим категориям в разделе «Поиск заказов»', 'become_specialist.step3.title': 'Откликайся и зарабатывай', 'become_specialist.step3.desc': 'Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы', 'become_specialist.benefits.title': 'Преимущества профиля специалиста', 'become_specialist.benefit1': 'Поиск заказов по вашим категориям и локации', 'become_specialist.benefit2': 'Публичный профиль с отзывами клиентов', 'become_specialist.benefit3': 'Расписание доступности, видимое клиентам', 'become_specialist.benefit4': 'Добавление в избранное клиентами', 'become_specialist.cta': 'Подробнее', 'become_specialist.free_badge': 'Бесплатная регистрация', 'profile.tab.notifications': 'Уведомления', 'profile.tab.reviews': 'Отзывы', 'profile.tab.referral': 'Рефералы', 'profile.tab.auto_response': 'Авто-ответ', 'profile.tab.site': 'Сайт', 'profile.site.title': 'Персональная страница', 'profile.site.url_label': 'Личный сайт', 'profile.site.copy': 'Копировать', 'profile.site.copied': 'Скопировано', 'profile.site.visible_title': 'Что отображается на вашей странице', 'profile.site.visible.name': 'Имя и фото', 'profile.site.visible.bio': 'Биография', 'profile.site.visible.rating': 'Рейтинг и отзывы', 'profile.site.visible.portfolio': 'Портфолио / Карточки', 'profile.site.visible.contacts': 'Контактные данные', 'profile.site.visible.full_last_name': 'Фамилия полностью', 'profile.site.visible.services': 'Карточки услуг', 'profile.site.visible.reviews': 'Раздел с отзывами', 'profile.site.visible.status': 'Статус «Готов помочь»', 'profile.site.theme': 'Тема оформления', 'profile.site.theme.dark': 'Тёмная', 'profile.site.theme.light': 'Светлая', 'profile.site.slug_taken': 'Этот адрес уже занят', 'profile.site.stats.title': 'Аналитика сайта', 'profile.site.stats.days': 'последние 30 дней', 'profile.site.stats.views': 'Просмотры', 'profile.site.stats.unique': 'Уникальные посетители', 'profile.site.stats.messages': 'Сообщения', 'profile.site.stats.total_views': 'Просмотры', 'profile.site.stats.total_unique': 'Уник. посетители', 'profile.site.stats.total_messages': 'Сообщения', 'profile.site.stats.empty': 'Данных пока нет', 'profile.site.stats.loading': 'Загрузка аналитики...', 'profile.site.stats.no_slug': 'Укажите адрес сайта, чтобы видеть статистику', 'profile.site.edit_bio_hint': 'Биография и фото настраиваются во вкладке «Основное».', 'status.title': 'Статус', 'status.can_help_now_hint': 'Ваша карточка показывается выше в поиске', 'status.need_help_hint': 'Специалисты могут предложить вам помощь', 'profile.referral.title': 'Партнёрская программа', 'profile.referral.desc': 'Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.', 'profile.referral.link_label': 'Ваша реферальная ссылка', 'profile.referral.copy': 'Копировать', 'profile.referral.copied': 'Скопировано!', 'profile.referral.invited_count': 'успешных приглашений', 'profile.referral.no_code': 'Реферальный код недоступен.', 'notifications.title': 'Настройки уведомлений', 'notifications.email.new_tasks': 'Email о новых заказах', 'notifications.email.new_tasks.desc': 'Получать email, когда в ваших категориях публикуется новый заказ', 'notifications.messages.desc': 'Получать уведомление при новом входящем сообщении', 'notifications.saved': 'Настройки сохранены', 'notifications.plan_required': 'Недоступно в вашем тарифе', 'profile.tab.info': 'Основное', 'profile.tab.finance': 'Финансы', 'profile.tab.skills': 'Навыки', 'profile.tab.categories': 'Категории', 'profile.tab.geography': 'География', 'profile.specialist.categories': 'Категории работ', 'profile.specialist.categories.desc': 'Выберите категории, в которых вы работаете', 'profile.specialist.geography': 'Города покрытия', 'profile.specialist.geography.desc': 'Выберите города / районы, где вы работаете', 'profile.saving': 'Сохранение...', 'profile.upload.error': 'Ошибка загрузки фото', 'profile.saved': 'Сохранено', 'profile.tab.cards': 'Портфолио', 'profile.cards.count': 'Портфолио', 'profile.cards.add': 'Добавить портфолио', 'profile.cards.new_title': 'Название нового портфолио', 'profile.cards.placeholder': 'Например: Сантехника', 'profile.cards.create': 'Создать', 'profile.cards.cancel': 'Отмена', 'profile.cards.empty': 'У вас нет портфолио', 'profile.cards.create_first': 'Создать первое портфолио', 'profile.cards.delete_confirm': 'Удалить портфолио?', 'profile.card.tab.main': 'Основное', 'profile.card.tab.skills': 'Навыки', 'profile.card.tab.categories': 'Категории', 'profile.card.tab.geography': 'География', 'profile.card.tab.portfolio': 'Галерея', 'profile.card.active': 'Активна', 'profile.card.save': 'Сохранить', 'profile.card.saved': 'Сохранено', 'profile.card.delete': 'Удалить', 'profile.card.skill.add': 'Добавить навык', 'profile.card.photo.add': 'Добавить фото', 'profile.card.photo.uploading': 'Загрузка...', 'profile.card.photo.empty': 'Нет фотографий', 'profile.card.item.title': 'Заголовок', 'profile.card.item.desc': 'Описание', 'profile.card.item.save': 'Сохранить', 'profile.card.item.cancel': 'Отмена', 'profile.card.item.edit': 'Описание работы', 'profile.upgrade.cards_limit': 'Лимит портфолио исчерпан', 'profile.upgrade.plan': 'Текущий тариф:', 'profile.upgrade.contact': 'Обратитесь к администратору для смены тарифа', 'profile.upgrade.ok': 'Понятно', 'profile.plan.title': 'Тарифный план', 'profile.balance': 'Баланс', 'profile.balance.topup': 'Пополнить баланс', 'profile.balance.topup.title': 'Пополнить баланс', 'profile.balance.topup.amount': 'Сумма (в EUR)', 'profile.balance.topup.hint': 'Выберите сумму или введите вручную', 'profile.balance.topup.submit': 'Перейти к оплате', 'profile.balance.topup.loading': 'Перенаправление...', 'profile.balance.topup.error': 'Ошибка инициализации платежа. Попробуйте снова.', 'payment.success.title': 'Оплата прошла успешно!', 'payment.success.desc': 'Ваш баланс обновлён.', 'payment.cancelled.title': 'Оплата отменена', 'payment.cancelled.desc': 'Оплата была отменена. Средства не списаны.', 'payment.pending.title': 'Обрабатывается...', 'payment.pending.desc': 'Ваш платёж в обработке.', 'payment.back_to_profile': 'Вернуться в профиль', 'profile.plan.basic': 'Базовый (бесплатный)', 'profile.plan.contact_upgrade': 'Обратитесь к администратору для подключения тарифа', 'profile.plan.cards_up_to': 'Портфолио: до', 'profile.plan.cards_unlimited': 'Портфолио: безлимитно', 'profile.plan.tasks_up_to': 'Задач: до', 'profile.plan.offers_up_to': 'Откликов: до', 'profile.plan.valid_until': 'Действителен до', 'profile.plan.no_expiry': 'Бессрочно', // Create task 'create.error': 'Ошибка при публикации', // Tasks list extras 'tasks.category.general': 'Общее', 'tasks.budget.range': 'Диапазон:', 'tasks.budget.from': 'от', 'tasks.budget.to': 'до', 'tasks.filter.reset': 'Сбросить фильтры', 'tasks.load_more': 'Загрузить ещё', 'tasks.showing': 'Результатов:', 'tasks.field.budget': 'Бюджет, €', // Admin 'admin.title': 'Панель администратора', 'admin.tab.stats': 'Статистика', 'admin.tab.users': 'Пользователи', 'admin.tab.tasks': 'Задачи', 'admin.tab.reports': 'Жалобы', 'admin.stats.users': 'Пользователи', 'admin.stats.tasks': 'Задачи', 'admin.stats.offers': 'Предложения', 'admin.stats.reviews': 'Отзывы', 'admin.tasks.by_status': 'Задачи по статусу', 'admin.col.user': 'Пользователь', 'admin.col.email': 'Email', 'admin.col.role': 'Роль', 'admin.col.registered': 'Регистрация', 'admin.col.status': 'Статус', 'admin.col.title': 'Название', 'admin.col.budget': 'Бюджет', 'admin.col.created': 'Создано', 'admin.users.active': 'Активен', 'admin.users.inactive': 'Неактивен', 'admin.users.deactivate': 'Деактивировать', 'admin.users.activate': 'Активировать', 'admin.tasks.cancel': 'Отменить', 'admin.reports.none': 'Жалоб нет', 'admin.reports.reviewed': 'Рассмотрено', 'admin.reports.dismiss': 'Отклонить', 'admin.pagination.total': 'Всего', 'admin.users.role.change': 'Изменить роль', 'admin.users.search.placeholder': 'Поиск по имени или email...', 'admin.tasks.delete': 'Удалить', 'admin.tasks.delete.confirm': 'Удалить эту задачу навсегда?', 'admin.tasks.search.placeholder': 'Поиск по названию...', 'admin.col.customer': 'Заказчик', 'admin.col.reporter': 'Жалобщик', 'admin.col.target': 'Цель', 'admin.filter.all_roles': 'Все роли', 'admin.filter.all_statuses': 'Все статусы', 'admin.reports.target.task': 'Задача', 'admin.reports.target.user': 'Пользователь', 'admin.tab.categories': 'Категории', 'admin.tab.locations': 'Города и районы', 'admin.tab.logs': 'Логи', 'admin.tab.plans': 'Тарифы', 'admin.tab.settings': 'Настройки', 'admin.logs.subtab.ai': 'AI логи', 'admin.logs.subtab.activity': 'Активность', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Уведомления', 'admin.notif_logs.type': 'Тип', 'admin.notif_logs.title': 'Заголовок', 'admin.notif_logs.read': 'Прочитано', 'admin.notif_logs.empty': 'Логи уведомлений пусты', 'admin.stats.notif_chart_title': 'Уведомления по дням', 'admin.stats.notif_label': 'Уведомления', 'admin.stats.mail_chart_title': 'Email по дням', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Все', 'admin.stats.specialists': 'Исполнители', 'admin.col.plan': 'Тариф', 'admin.back_home': 'На главную', 'admin.plans.title': 'Тарифные пакеты', 'admin.plans.add': '+ Добавить тариф', 'admin.plans.empty': 'Тарифы не созданы', 'admin.plans.form.new': 'Новый тариф', 'admin.plans.form.edit': 'Редактировать тариф', 'admin.plans.form.name': 'Название', 'admin.plans.form.price': 'Цена (EUR)', 'admin.plans.form.old_price': 'Старая цена (EUR, необязательно)', 'admin.plans.form.max_offers': 'Макс. откликов (пусто = без лимита)', 'admin.plans.form.max_cards': 'Макс. портфолио (пусто = без лимита)', 'admin.plans.form.duration_days': 'Срок (дней, пусто = без истечения)', 'admin.plans.form.description': 'Описание', 'admin.plans.form.features': 'Возможности (по одной на строку)', 'admin.plans.form.notify': 'Уведомления о новых заказах', 'admin.plans.form.default': 'По умолчанию', 'admin.plans.form.active': 'Активен', 'admin.plans.form.order': 'Порядок', 'admin.plans.form.role': 'Роль', 'admin.plans.form.tier': 'Уровень', 'admin.plans.form.role.customer': 'Заказчик', 'admin.plans.form.role.specialist': 'Специалист', 'admin.plans.form.tier.free': 'Бесплатный', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Лимиты (пусто = без ограничений)', 'admin.plans.form.max_messages_day': 'Макс. сообщений/день', 'admin.plans.form.max_orders_day': 'Макс. заказов/день', 'admin.plans.form.max_skills': 'Макс. навыков', 'admin.plans.form.max_profiles': 'Макс. профилей', 'admin.plans.form.max_portfolio': 'Макс. элементов портфолио', 'admin.plans.form.section.boost': 'Множители & Буст', 'admin.plans.form.search_boost': 'Буст в поиске', 'admin.plans.form.offers_multiplier': 'Множитель откликов', 'admin.plans.form.section.contact': 'Права контактов', 'admin.plans.form.can_contact_free': 'Контакт с бесплатными пользователями', 'admin.plans.form.can_contact_pro': 'Контакт с Pro пользователями', 'admin.plans.form.can_contact_all': 'Контакт со всеми', 'admin.plans.form.can_show_contact': 'Показывать контакты', 'admin.plans.form.can_view_phone': 'Просмотр телефона', 'admin.plans.form.section.features': 'Возможности', 'admin.plans.form.upload_video': 'Загрузка видео', 'admin.plans.form.favorites': 'Избранное', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Знак верификации', 'admin.plans.form.highlighted_reviews': 'Выделенные отзывы', 'admin.plans.form.personal_site': 'Личный сайт', 'admin.plans.form.can_help_now': 'Статус «Могу помочь»', 'admin.plans.form.need_help': 'Статус «Нужна помощь»', 'admin.plans.form.auto_response': 'Автоответ', 'admin.plans.form.auto_match': 'Автоподбор', 'admin.plans.form.instant_dispatch_free': 'Мгновенная рассылка (бесплатно)', 'admin.plans.form.instant_dispatch_pro': 'Мгновенная рассылка (Pro)', 'admin.plans.badge.default': 'По умолчанию', 'admin.plans.badge.inactive': 'Неактивен', 'admin.plans.make_default': 'Сделать по умолчанию', 'admin.plans.tasks': 'Задач', 'admin.plans.offers': 'Откликов', 'admin.plans.cards': 'Портфолио', 'admin.plans.notify_tasks': 'Уведомления о заказах', 'admin.plans.delete.confirm': 'Удалить тариф', 'admin.activity.title': 'Журнал активности', 'admin.activity.event': 'Событие', 'admin.activity.all_events': 'Все события', 'admin.activity.from': 'От', 'admin.activity.to': 'До', 'admin.activity.reset': 'Сбросить', 'admin.activity.total': 'Всего', 'admin.activity.empty': 'Нет записей', 'admin.mail.event': 'Email событие', 'admin.mail.all_events': 'Все email события', 'admin.mail.from': 'От', 'admin.mail.to': 'До', 'admin.mail.reset': 'Сбросить', 'admin.mail.total': 'Всего', 'admin.mail.empty': 'Нет email логов', 'admin.mail.recipient': 'Получатель', 'admin.mail.provider': 'Провайдер', 'admin.mail.details': 'Детали', 'admin.mail.status': 'Статус', 'admin.mail.success': 'Успешно', 'admin.mail.failed': 'Ошибка', 'admin.event.email_sent': 'Email отправлен', 'admin.event.email_failed': 'Email не отправлен', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Тестовый email отправлен', 'admin.event.admin_email_test_failed': 'Тестовый email не отправлен', 'admin.logs.empty': 'Нет записей', 'admin.logs.date': 'Дата', 'admin.logs.provider': 'Провайдер', 'admin.logs.model': 'Модель', 'admin.logs.action': 'Действие', 'admin.logs.langs': 'Языки', 'admin.logs.in': 'Вход', 'admin.logs.out': 'Выход', 'admin.logs.total': 'Итого', 'admin.logs.ms': 'мс', 'admin.logs.status': 'Статус', 'admin.stats.activity_30d': 'Активность за 30 дней', 'admin.stats.tasks_label': 'Заявки', 'admin.stats.users_label': 'Пользователи', 'admin.stats.specialists_label': 'Исполнители', 'admin.stats.tokens_title': 'Расход токенов (по месяцам)', 'admin.stats.tokens_out': 'Исходящие', 'admin.stats.tokens_in': 'Входящие', 'admin.stats.tokens_out_label': 'Исходящие токены', 'admin.stats.tokens_in_label': 'Входящие токены', 'admin.stats.cost_label': 'Стоимость (USD)', 'admin.stats.tasks_by_status': 'Заявки по статусам', 'admin.task_status.open': 'Открытые', 'admin.task_status.in_progress': 'В работе', 'admin.task_status.completed': 'Завершённые', 'admin.task_status.cancelled': 'Отменённые', 'admin.task_status.draft': 'Черновики', 'admin.settings.tab.general': 'Общие', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Уведомления', 'admin.settings.tab.payment': 'Оплата', 'admin.settings.tab.referral': 'Реферальная', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Соцсети', 'admin.settings.socials.title': 'Ссылки на социальные сети', 'admin.settings.socials.hint': 'Заполненные ссылки отображаются в подвале сайта', 'admin.settings.seo.maintenance_label': 'Режим обслуживания', 'admin.settings.seo.maintenance_hint': 'Показывать страницу обслуживания всем посетителям', 'admin.settings.seo.indexing_label': 'Индексация поисковыми системами', 'admin.settings.seo.indexing_hint': 'Разрешить поисковым системам индексировать сайт', 'admin.settings.seo.head_scripts_label': 'Скрипты в (JS)', 'admin.settings.seo.head_scripts_hint': 'Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)', 'admin.settings.seo.site_title_label': 'Заголовок сайта', 'admin.settings.seo.site_description_label': 'Описание сайта (meta description)', 'admin.settings.referral.title': 'Партнёрская программа', 'admin.settings.referral.hint': 'Награждайте пользователей, приводящих новых участников.', 'admin.settings.referral.enabled_label': 'Включено', 'admin.settings.referral.enabled_hint': 'Включить / отключить выдачу наград', 'admin.settings.referral.customer_section': 'Для клиентов', 'admin.settings.referral.specialist_section': 'Для специалистов', 'admin.settings.referral.plan_label': 'Тарифный план за реферала', 'admin.settings.referral.no_plan': '— без плана —', 'admin.settings.referral.plan_hint': 'Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.', 'admin.settings.referral.days_label': 'Дней награды', 'admin.settings.referral.days_hint': 'Количество дней, добавляемых к сроку действия плана.', 'admin.settings.general.title': 'Общие настройки', 'admin.settings.general.site_name': 'Название сайта', 'admin.settings.general.site_url': 'URL сайта', 'admin.settings.general.contact_email': 'Email для связи', 'admin.settings.general.support_phone': 'Телефон поддержки', 'admin.settings.smtp.title': 'Настройки SMTP сервера', 'admin.settings.smtp.hint': 'Используется для отправки email-уведомлений.', 'admin.settings.smtp.host': 'SMTP Хост', 'admin.settings.smtp.port': 'Порт', 'admin.settings.smtp.encryption': 'Шифрование', 'admin.settings.smtp.enc.none': 'Нет', 'admin.settings.smtp.enc.tls': 'STARTTLS (порт 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (порт 465)', 'admin.settings.smtp.username': 'Имя пользователя', 'admin.settings.smtp.password': 'Пароль / App Password', 'admin.settings.smtp.from_name': 'Имя отправителя', 'admin.settings.smtp.from_email': 'Email отправителя', 'admin.settings.smtp.test': 'Отправить тестовый email', 'admin.settings.smtp.sending': 'Отправка...', 'admin.settings.payment.hint': 'Данные для подключения к ePay Piraeus Bank.', 'admin.settings.env.test': 'Тест (sandbox)', 'admin.settings.env.prod': 'Боевой режим', 'admin.settings.env.label': 'Среда', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Активен', 'admin.settings.saving': 'Сохранение...', 'admin.settings.saved': 'Сохранено', 'admin.notif.vars_hint': 'Доступные переменные в шаблонах', 'admin.notif.tmpl.not_set': 'Шаблон не настроен', 'admin.notif.tmpl.subject_label': 'Тема письма', 'admin.notif.tmpl.body_label': 'Текст письма (HTML)', 'admin.notif.tmpl.save': 'Сохранить', 'admin.notif.tmpl.close': 'Закрыть', 'admin.notif.tmpl.translate': 'Авто-перевод на другие языки', 'admin.notif.tmpl.translating': 'Перевод...', 'admin.notif.tmpl.saving': 'Сохранение...', 'admin.notif.email_verification': 'Подтверждение email адреса', 'admin.notif.registration_success': 'Успешная регистрация', 'admin.notif.password_reset': 'Восстановление пароля', 'admin.notif.new_offer': 'Новое предложение', 'admin.notif.new_task': 'Новая задача', 'admin.notif.offer_accepted': 'Предложение принято', 'admin.notif.new_message': 'Новое сообщение', 'admin.notif.offer_declined': 'Отклонение предложения', 'admin.notif.offer_other_accepted': 'Выбран другой исполнитель', 'admin.notif.task_updated': 'Изменение задания', 'admin.notif.deadline_reminder': 'Напоминание о дедлайне', 'admin.notif.task_archived': 'Автоснятие задания', 'admin.notif.referral_reward': 'Реферальная награда', // Шаблоны email для тарифов 'admin.email_template.plan_activated': 'Тарифы — активация тарифа', 'admin.email_template.plan_upgraded': 'Тарифы — повышение тарифа', 'admin.email_template.plan_downgrade_scheduled': 'Тарифы — запланированное понижение', 'admin.email_template.plan_downgrade_applied': 'Тарифы — применение понижения', 'admin.email_template.plan_renewal_reminder': 'Тарифы — напоминание о продлении', 'admin.email_template.plan_insufficient_funds': 'Тарифы — нехватка средств', // Модальное окно подтверждения тарифа 'pricing.confirm.title': 'Подтвердите выбор тарифа', 'pricing.confirm.plan': 'Тариф', 'pricing.confirm.prorated': 'Зачёт остатка', 'pricing.confirm.effective_price': 'К оплате', 'pricing.confirm.your_balance': 'Ваш баланс', 'pricing.confirm.downgrade_info': 'Переход на новый тариф произойдёт автоматически после окончания текущего периода.', 'pricing.confirm.insufficient': 'Недостаточно средств на балансе.', 'pricing.confirm.top_up': 'Пополнить', 'pricing.confirm.schedule_downgrade': 'Запланировать переход', 'pricing.confirm.pay': 'Оплатить', 'admin.user_edit.title': 'Редактирование пользователя', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email подтверждён', 'admin.user_edit.email_not_verified': 'Email не подтверждён', 'admin.user_edit.verify_email_btn': 'Подтвердить вручную', 'admin.user_edit.verify_email_done': 'Email подтверждён!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Регистрация', 'admin.user_edit.last_seen': 'Последний визит', 'admin.user_edit.lang': 'Язык', 'admin.user_edit.first_name': 'Имя', 'admin.user_edit.last_name': 'Фамилия', 'admin.user_edit.phone': 'Телефон', 'admin.user_edit.bio': 'О себе', 'admin.user_edit.role': 'Роль', 'admin.user_edit.plan': 'Тариф', 'admin.user_edit.no_plan': '— Без тарифа —', 'admin.user_edit.active': 'Активный аккаунт', 'admin.user_edit.balance': 'Баланс (EUR)', 'admin.user_edit.skills': 'Навыки', 'admin.user_edit.tab.profile': 'Профиль', 'admin.user_edit.tab.account': 'Аккаунт', 'admin.user_edit.tab.balance': 'Баланс', 'admin.user_edit.tab.settings': 'Настройки', 'admin.user_edit.tab.specialist': 'Портфолио', 'admin.user_edit.tab.site': 'Сайт', 'admin.user_edit.plan_expires': 'Тариф истекает', 'admin.user_edit.interface_lang': 'Язык интерфейса', 'admin.user_edit.comm_languages': 'Языки общения', 'admin.user_edit.personal_site_slug': 'Персональная страница', 'admin.user_edit.show_contact_info': 'Показывать контакты', 'admin.user_edit.show_contact_info.hint': 'Видно заказчикам', 'admin.user_edit.notify_new_tasks': 'Уведомлять о новых задачах', 'admin.user_edit.notify_new_tasks.hint': 'Push и email уведомления', 'admin.user_edit.notif_messages': 'Уведомления о сообщениях', 'admin.user_edit.notif_messages.hint': 'Новые сообщения в чате', 'admin.user_edit.site_settings': 'Настройки персональной страницы', 'admin.user_edit.categories': 'Категории услуг', 'admin.user_edit.locations': 'Районы обслуживания', 'admin.user_edit.skill_placeholder': 'Новый навык...', 'admin.user_edit.add_category': '— Выберите категорию —', 'admin.user_edit.add_location': '— Выберите район —', 'admin.user_edit.specialist_cards': 'Портфолио специалиста', 'admin.user_edit.no_cards': 'Портфолио не найдено', 'admin.user_edit.card_title': 'Заголовок портфолио', 'admin.user_edit.card_description': 'Описание', 'admin.balance.topup.btn': 'Пополнить', 'admin.balance.withdraw.btn': 'Списать', 'admin.balance.modal_hint': 'Изменения применяются сразу и фиксируются в истории', 'admin.balance.topup.title': 'Пополнение баланса', 'admin.balance.topup.amount': 'Сумма', 'admin.balance.topup.description': 'Комментарий', 'admin.balance.topup.description.placeholder': 'Например: бонус или ручное пополнение', 'admin.balance.topup.submit': 'Пополнить баланс', 'admin.balance.withdraw.title': 'Снятие баланса', 'admin.balance.withdraw.amount': 'Сумма', 'admin.balance.withdraw.description': 'Комментарий', 'admin.balance.withdraw.description.placeholder': 'Например: возврат или ручное списание', 'admin.balance.withdraw.submit': 'Списать баланс', 'admin.user_edit.role.customer': 'Заказчик', 'admin.user_edit.role.specialist': 'Исполнитель', 'admin.user_edit.role.admin': 'Администратор', 'common.refresh': 'Обновить', 'common.back_home': 'На главную', 'admin.loc.hint': 'Управление городами и районами', 'admin.loc.add_city': 'Новый город', 'admin.loc.add_district': 'Добавить район', 'admin.loc.new': 'Новая локация', 'admin.loc.edit': 'Редактировать локацию', 'admin.loc.district': 'район', 'admin.loc.empty': 'Нет локаций', 'admin.loc.delete.confirm': 'Удалить локацию? Все районы также будут удалены.', 'admin.cat.add_root': 'Новая категория', 'admin.cat.add_sub': 'Подкатегория', 'admin.cat.edit': 'Редактировать', 'admin.cat.delete': 'Удалить', 'admin.cat.delete.confirm': 'Удалить категорию? Все подкатегории также будут удалены.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Иконка', 'admin.cat.name_el': 'Греческий', 'admin.cat.name_en': 'Английский', 'admin.cat.name_ru': 'Русский', 'admin.cat.order': 'Порядок', 'admin.cat.active': 'Активна', 'admin.cat.parent': 'Родительская категория', 'admin.cat.no_parent': 'Верхний уровень', 'admin.cat.save': 'Сохранить', 'admin.cat.cancel': 'Отмена', 'admin.cat.empty': 'Нет категорий', 'admin.cat.hint': 'Управление категориями с многоуровневой иерархией', 'admin.cat.new': 'Новая категория', 'admin.cat.subcategory': 'подкатегория', 'admin.cat.add_child': 'Добавить подкатегорию', 'admin.cat.inactive': 'Неактивна', 'admin.event.user_login': 'Вход', 'admin.event.user_register': 'Регистрация', 'admin.event.admin_user_deactivate': 'Блокировка юзера', 'admin.event.admin_user_activate': 'Разблокировка юзера', 'admin.event.admin_user_role_changed': 'Смена роли', 'admin.event.admin_task_cancelled': 'Отмена задачи', 'admin.event.admin_task_deleted': 'Удаление задачи', 'admin.event.admin_report_reviewed': 'Жалоба рассмотрена', 'admin.event.admin_report_dismissed': 'Жалоба отклонена', 'admin.event.task_created': 'Создана задача', // User status 'user.online': 'Онлайн', 'user.seen_minutes': 'был здесь {n} мин назад', 'user.seen_hours': 'был здесь {n} ч назад', 'user.seen_yesterday': 'был здесь вчера', 'user.seen_days': 'был здесь {n} дн назад', // Specialists 'specialists.title': 'Специалисты', 'specialists.search': 'Поиск специалиста...', 'specialists.search.btn': 'Поиск', 'specialists.empty': 'Специалисты не найдены', 'specialists.no_bio': 'Без описания', 'specialists.view': 'Смотреть профиль', 'specialists.reviews': 'отзывов', 'specialist.favorite': 'Добавить в избранное', 'specialist.unfavorite': 'Убрать из избранного', 'specialist.site_link': 'Личный сайт', 'favorites.specialists.title': 'Избранные специалисты', 'favorites.specialists.empty': 'Вы ещё не добавили специалистов в избранное', 'nav.favorites': 'Избранное', 'nav.schedule': 'Расписание', 'nav.find_tasks': 'Поиск заказов', 'schedule.title': 'Моё расписание', 'schedule.subtitle': 'Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность', 'schedule.available': 'Свободен', 'schedule.busy': 'Занят', 'schedule.unset': 'Не указано', 'schedule.click_hint': '← клик меняет статус по кругу', 'schedule.range_mode': 'Выделить диапазон', 'schedule.range_from': 'С {date} — выберите конечную дату', 'schedule.click_to_set': 'Нажмите чтобы отметить', 'schedule.free': 'свободно', 'schedule.busy_count': 'занято', 'schedule.free_days': 'свободных дней', 'schedule.googleCalendar': 'Google Календарь', 'schedule.connectGoogle': 'Подключить Google Календарь', 'schedule.disconnectGoogle': 'Отключить', 'schedule.connectedAs': 'Подключено как', 'schedule.importFromGoogle': 'Синхр. из Google', 'schedule.gcalConnected': '\u2713 Google Календарь подключён', 'schedule.gcalError': 'Ошибка подключения Google Календарь', 'schedule.gcalImportDone': 'Импортировано {n} дней из Google Календарь', 'schedule.gcalAutoSyncNote': 'Изменения доступности автоматически отправляются в Google Календарь', 'schedule.gcalConnectDesc': 'Подключите Google Календарь для автоматической синхронизации расписания', 'schedule.gcalDisconnectConfirm': 'Отключить Google Календарь?', 'find_tasks.title': 'Поиск заказов', 'find_tasks.for_me': 'Для меня', 'find_tasks.all': 'Все заказы', 'find_tasks.by_category': 'По категориям', 'find_tasks.list': 'Списком', 'find_tasks.already_offered': 'Предложение отправлено', 'find_tasks.offer_now': 'Откликнуться', 'find_tasks.empty_for_me': 'Нет заказов в ваших категориях', 'find_tasks.banner_hint': 'Найдите заказы по категориям вашего портфолио', 'find_tasks.no_cards': 'Создайте портфолио специалиста, чтобы видеть подходящие заказы', 'find_tasks.add_card': 'Создать портфолио', 'find_tasks.search': 'Поиск заказов...', 'find_tasks.tasks_count': 'заданий', 'footer.tagline': 'Платформа задач для Греции', 'footer.rights': 'Все права защищены.', // App download section 'app.download_title': 'Скачайте мобильное приложение CanHelp', 'app.download_desc': 'Всё CanHelp — всегда под рукой. Доступно для Android и iOS.', // Nav 'nav.pricing': 'Тарифы', // Pricing page 'pricing.title': 'Тарифы', 'pricing.subtitle': 'Выберите подходящий план', 'pricing.role.customer': 'Заказчик', 'pricing.role.specialist': 'Специалист', 'pricing.free': 'Бесплатно', 'pricing.per_month': 'мес', 'pricing.duration': 'Срок', 'pricing.days': 'дн.', 'pricing.current_plan': 'Ваш план', 'pricing.popular': 'Популярный', 'pricing.choose': 'Выбрать', 'pricing.your_plan': 'Активный план', 'pricing.free_default': 'По умолчанию', 'pricing.compare': 'Сравнение функций', 'pricing.feature': 'Функция', 'pricing.faq_note': 'Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.', 'pricing.feat.messages': 'Сообщений / день', 'pricing.feat.orders': 'Заказов / день', 'pricing.feat.contact_all': 'Связь со всеми', 'pricing.feat.view_phone': 'Просмотр телефона', 'pricing.feat.show_contact': 'Показывать контакты', 'pricing.feat.favorites': 'Избранное', 'pricing.feat.verified_badge': 'Верифицированный бейдж', 'pricing.feat.google_calendar': 'Google Календарь', 'pricing.feat.personal_site': 'Персональный сайт', 'pricing.feat.auto_response': 'Авто-ответ', 'pricing.feat.auto_match': 'Авто-подбор', 'pricing.feat.highlighted_reviews': 'Выделенные отзывы', 'pricing.feat.portfolio': 'Элементов портфолио', 'pricing.feat.cards': 'Карточки специалиста', 'pricing.feat.notify_tasks': 'Уведомления о новых задачах', 'pricing.feat.video': 'Видео в портфолио', // Upgrade prompt 'upgrade.available_in': 'Доступно в', 'upgrade.cta': 'Улучшить', // Dashboard plan block 'dashboard.plan.title': 'Мой план', 'dashboard.plan.expires': 'Истекает через {n} дней', 'dashboard.plan.upgrade': 'Улучшить план', 'dashboard.plan.no_plan': 'Бесплатный план', 'dashboard.plan.messages': 'Сообщений сегодня', 'dashboard.plan.orders': 'Заказов сегодня', 'dashboard.plan.limits': 'Дневные лимиты', 'dashboard.plan.features': 'Функции', 'dashboard.plan.stats': 'Статистика', 'dashboard.stats.cards': 'Портфолио', 'dashboard.stats.maxCards': 'Макс. портфолио', 'dashboard.stats.portfolioItems': 'Элементы портфолио', 'dashboard.stats.maxPortfolioItems': 'Макс. элементы', 'dashboard.stats.activeOffers': 'Активные отклики', 'dashboard.stats.reviewsReceived': 'Отзывы', 'dashboard.stats.activeTasks': 'Активные задачи', 'dashboard.stats.completedTasks': 'Завершённые', 'status.need_help': 'Нужна помощь', 'status.active': 'Активен', 'status.toggle_on': 'Включить', 'status.toggle_off': 'Выключить', // FOMO 'fomo.missed_orders': 'Пропущено {n} заказов', 'fomo.missed_value': 'На сумму €{v}', 'fomo.upgrade_hint': 'Улучшите план — получайте больше заказов', 'fomo.conversion': 'Конверсия задач', 'fomo.active': 'Активные', 'fomo.with_offers': 'С офертами', 'fomo.completed': 'Завершённые', 'fomo.already_offered': '{n} специалистов уже откликнулись', 'fomo.specialist_missed': 'Вы пропустили {n} заказов', 'fomo.top_categories': 'Категории', 'fomo.offers_received': 'предложений получено', 'fomo.avg_offers': 'В среднем {n}/задача', 'fomo.completion_rate': 'завершено', // Task auto-match 'task.auto_match': 'Авто-матч', 'task.auto_match_results': 'Топ специалисты', 'task.no_offer_yet': 'Вы ещё не отправили предложение', 'task.make_offer': 'Отправить предложение', 'auto_response.title': 'Авто-ответ', 'auto_response.enabled': 'Включить авто-ответ', 'auto_response.min_budget': 'Мин. бюджет', 'auto_response.max_budget': 'Макс. бюджет', 'auto_response.default_price': 'Цена по умолчанию', 'auto_response.default_message': 'Сообщение по умолчанию', 'auto_response.max_per_day': 'Макс. авто-офертов в день', 'auto_response.save': 'Сохранить', 'auto_response.saved': 'Сохранено', 'auto_response.categories': 'Категории', 'auto_response.locations': 'Локации', // Personal site 'profile.personal_site': 'Персональный сайт', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Только латинские буквы, цифры, - и _', 'profile.site_open': 'Открыть сайт', 'profile.site_preview': 'Ваш сайт', 'profile.show_contact': 'Показывать контакты', 'profile.show_contact_hint': 'Заказчики с Pro/Ultimate-планом увидят ваш телефон', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Календарь требует план Pro или Ultimate', // Chat limits 'chat.limit_warning': 'Осталось {n} сообщений сегодня', 'chat.limit_reached': 'Лимит сообщений исчерпан. Улучшите план', 'chat.upgrade': 'Улучшить', // Site page 'site.member_since': 'С нами с', 'site.rating': 'Рейтинг', 'site.completed_tasks': 'Выполнено', 'site.languages': 'Языков', 'site.photos': 'фото', 'site.contact_form': 'Связаться', 'site.contact_sent': 'Сообщение отправлено!', 'site.contact_sent_desc': 'Специалист свяжется с вами в ближайшее время', 'site.contact_name': 'Имя', 'site.contact_name_ph': 'Ваше имя', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Сообщение', 'site.contact_message_ph': 'Опишите вашу задачу...', 'site.contact_send': 'Отправить', 'site.share': 'Поделиться', 'site.speaks_languages': 'Говорит на языках', 'site.message_sent': 'Сообщение отправлено!', 'site.message_sent_desc': 'Специалист получит его в чате', 'site.message_placeholder': 'Напишите сообщение...', 'site.write_to_chat': 'Написать в чат', 'site.auth_required_title': 'Нужна авторизация', 'site.auth_required_desc': 'Чтобы написать в чат, необходимо войти в аккаунт CanHelp.', 'site.auth_login_btn': 'Войти в аккаунт', 'site.auth_contact_form_btn': 'Написать через форму обратной связи', 'specialist.services': 'Услуги', 'portfolio.title': 'Портфолио', 'status.can_help_now': 'Готов помочь', 'common.not_found': 'Страница не найдена', 'common.anonymous': 'Анонимно', 'specialist_setup.page_title': 'Настройка профиля специалиста', 'specialist_setup.step_of': 'Шаг {current} из {total}', 'specialist_setup.next': 'Далее', 'specialist_setup.back': 'Назад', 'specialist_setup.skip': 'Пропустить', 'specialist_setup.finish': 'Завершить', 'specialist_setup.go_to_profile': 'Перейти в профиль', 'specialist_setup.browse_tasks': 'Найти задачи', 'specialist_setup.step1.title': 'Добро пожаловать!', 'specialist_setup.step1.subtitle': 'Давайте настроим ваш профиль', 'specialist_setup.step1.desc': 'Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.', 'specialist_setup.step1.what_next': 'Что мы сделаем:', 'specialist_setup.step1.item1': 'Заполним основную информацию', 'specialist_setup.step1.item2': 'Создадим карточку услуги', 'specialist_setup.step1.item3': 'Добавим навыки и категории', 'specialist_setup.step1.item4': 'Выберем географию обслуживания', 'specialist_setup.step1.item5': 'Загрузим фото портфолио', 'specialist_setup.step2.title': 'Базовый профиль', 'specialist_setup.step2.subtitle': 'Расскажите о себе', 'specialist_setup.step2.bio_label': 'О себе', 'specialist_setup.step2.bio_placeholder': 'Опишите ваш опыт, услуги которые вы предлагаете...', 'specialist_setup.step2.phone_label': 'Телефон', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Фото профиля', 'specialist_setup.step2.photo_btn': 'Загрузить фото', 'specialist_setup.step2.photo_uploading': 'Загрузка...', 'specialist_setup.step2.photo_hint': 'Отображается в вашем профиле', 'specialist_setup.step3.title': 'Карточка услуги', 'specialist_setup.step3.subtitle': 'Создайте вашу первую карточку услуги', 'specialist_setup.step3.title_label': 'Название карточки', 'specialist_setup.step3.title_placeholder': 'Напр. Сантехник, Электрик, Уборка...', 'specialist_setup.step3.desc_label': 'Описание', 'specialist_setup.step3.desc_placeholder': 'Подробно опишите что вы предлагаете, опыт, преимущества...', 'specialist_setup.step3.title_required': 'Название обязательно', 'specialist_setup.step4.title': 'Навыки и категории', 'specialist_setup.step4.subtitle': 'Добавьте навыки и выберите категории', 'specialist_setup.step4.skills_label': 'Навыки', 'specialist_setup.step4.skills_placeholder': 'Напр. Монтаж труб...', 'specialist_setup.step4.skills_add': 'Добавить', 'specialist_setup.step4.categories_label': 'Категории', 'specialist_setup.step5.title': 'География обслуживания', 'specialist_setup.step5.subtitle': 'Где вы оказываете услуги?', 'specialist_setup.step5.hint': 'Выберите города или конкретные районы', 'specialist_setup.done.title': 'Ваш профиль готов!', 'specialist_setup.done.subtitle': 'Поздравляем! Профиль настроен', 'specialist_setup.done.desc': 'Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам.' } }; export function getTranslations(locale) { const t = translations[locale] ?? translations.el; return (key, fallback)=>t[key] ?? translations.el[key] ?? fallback ?? key; } /06undefined268274undefined187763187769undefined /***/ }) p/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ getTranslations), /* harmony export */ YZ: () => (/* binding */ LOCALES) /* harmony export */ }); /* unused harmony export translations */ const LOCALES = [ { code: 'el', label: 'Ελληνικά', flag: '🇬🇷' }, { code: 'en', label: 'English', flag: '🇬🇧' }, { code: 'ru', label: 'Русский', flag: '🇷🇺' } ]; const translations = { el: { 'footer.slogan': 'Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.', 'footer.links': 'Σύνδεσμοι', 'footer.socials': 'Στα κοινωνικά δίκτυα', // Nav 'nav.home': 'Αρχική', 'nav.tasks': 'Εργασίες', 'nav.post': '+ Δημοσίευση', 'nav.dashboard': 'Πίνακας', 'nav.chat': 'Μηνύματα', 'nav.notifications': 'Ειδοποιήσεις', 'nav.profile': 'Προφίλ', 'nav.admin': 'Διαχείριση', 'nav.specialists': 'Ειδικοί', 'nav.new_task': 'Νέα εργασία', 'nav.login': 'Σύνδεση', 'nav.register': 'Εγγραφή', 'nav.logout': 'Έξοδος', // Hero 'hero.title': 'Βρες ειδικό για κάθε δουλειά', 'hero.subtitle': 'Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία', 'hero.cta.post': 'Δημοσίευσε εργασία', 'hero.cta.browse': 'Γίνε ειδικός', 'hero.search.placeholder': 'Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...', 'stats.specialists': 'ειδικοί', 'stats.tasks': 'εργασίες', 'stats.categories': 'κατηγορίες', 'stats.free': 'δωρεάν εγγραφή', // Sections 'section.categories': 'Δημιούργησε εργασία σε οποιαδήποτε κατηγορία', 'section.how': 'Πώς λειτουργεί', 'section.recent': 'Πρόσφατες εργασίες', 'section.all': 'Δες όλες →', 'section.more': 'ακόμα', 'section.cities': 'Πόλεις & Περιοχές', 'section.community': 'Ένα κοινοτικό έργο για όλους', 'community.subtitle': 'Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.', 'community.point1.title': 'Είσαι ειδικός σε κάτι;', 'community.point1.desc': 'Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.', 'community.point2.title': 'Χρειάζεσαι βοήθεια;', 'community.point2.desc': 'Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.', 'community.point3.title': 'Βοήθησε το έργο να αναπτυχθεί', 'community.point3.desc': 'Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.', 'community.share': 'Μοιράσου με φίλους', 'community.share.copied': 'Σύνδεσμος αντιγράφηκε!', // Referral section on home page 'section.referral': 'Πρόγραμμα παραπομπών', 'referral.home.subtitle': 'Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.', 'referral.home.step1.title': 'Εγγραφείσε και λάβε σύνδεσμο', 'referral.home.step1.desc': 'Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.', 'referral.home.step2.title': 'Μοιράσου με φίλους', 'referral.home.step2.desc': 'Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.', 'referral.home.step3.title': 'Κέρδισε ανταμοιβές', 'referral.home.step3.desc': 'Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.', 'referral.home.cta': 'Πάρε τον σύνδεσμό σου', 'referral.home.badge': 'Πρόγραμμα παραπομπών', // FAQ section 'section.faq': 'Συχνές Ερωτήσεις', 'faq.q1': 'Πώς λειτουργεί το CanHelp;', 'faq.a1': 'Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.', 'faq.q2': 'Πόσο κοστίζει η χρήση της πλατφόρμας;', 'faq.a2': 'Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.', 'faq.q3': 'Πώς μπορώ να γίνω ειδικός;', 'faq.a3': 'Κάνε εγγραφή, πήγαινε στο «Γίνε Ειδικός», συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.', 'faq.q4': 'Πώς επιλέγω τον κατάλληλο ειδικό;', 'faq.a4': 'Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q5': 'Τι γίνεται αν δεν είμαι ικανοποιημένος;', 'faq.a5': 'Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.', 'faq.q6': 'Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;', 'faq.a6': 'Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q7': 'Πόσος χρόνος χρειάζεται για να λάβω προσφορές;', 'faq.a7': 'Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.', 'faq.q8': 'Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;', 'faq.a8': 'Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.', 'faq.q9': 'Τι είδη εργασιών μπορώ να βρω στο CanHelp;', 'faq.a9': 'Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.', 'faq.q10': 'Υπάρχει εφαρμογή για κινητό;', 'faq.a10': 'Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.', // How it works 'how.step1.title': 'Δημοσίευσε εργασία', 'how.step1.desc': 'Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου', 'how.step2.title': 'Λάβε προσφορές', 'how.step2.desc': 'Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο', 'how.step3.title': 'Επίλεξε & ξεκίνα', 'how.step3.desc': 'Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία', // Tasks page 'tasks.title': 'εργασίες', 'tasks.filters': 'Φίλτρα', 'tasks.search': 'Αναζήτηση', 'tasks.search.placeholder': 'Τίτλος ή λέξη κλειδί...', 'tasks.search.btn': 'Αναζήτηση', 'tasks.publish': 'Δημοσίευση', 'tasks.category.all': 'Όλες', 'tasks.category.all_in': 'Όλα στην', 'tasks.category.label': 'Κατηγορία', 'tasks.location.label': 'Πόλη', 'tasks.location.placeholder': 'π.χ. Αθήνα', 'tasks.empty': 'Δεν βρέθηκαν εργασίες', 'tasks.empty.cta': 'Δημοσίευσε την πρώτη', // Task detail 'task.status.open': 'Ανοιχτή', 'task.status.in_progress': 'Σε εξέλιξη', 'task.status.completed': 'Ολοκληρωμένη', 'task.status.cancelled': 'Ακυρωμένη', 'task.status.draft': 'Πρόχειρο', 'task.budget': 'Προϋπολογισμός', 'task.location': 'Τοποθεσία', 'task.deadline': 'Ημερομηνία έναρξης', 'task.created_at': 'Δημιουργήθηκε', 'task.customer': 'Πελάτης', 'task.offer.btn': 'Υποβολή προσφοράς', 'task.invite.banner_title': 'Σας προσκαλούν σε αυτήν την εργασία', 'task.invite.banner_hint': 'Ο πελάτης σας πρόσκαλεσε προσωπικά', 'task.invite.accept': 'Αποστολή προσφοράς', 'task.invite.decline': 'Άρνηση', 'offer.accept': 'Αποδοχή', 'offer.decline': 'Απόρριψη', 'task.complete': 'Ολοκλήρωση εργασίας', 'task.complete.confirm': 'Να ολοκληρωθεί η εργασία;', 'task.edit': 'Επεξεργασία', 'task.status_label': 'Κατάσταση', 'task.yours': 'Η εργασία σου', 'task.offer.yours': 'Η προσφορά σου', 'review.leave': 'Άφησε αξιολόγηση', 'review.rating': 'Βαθμολογία', 'review.comment': 'Σχόλιο', 'review.comment.placeholder': 'Πες μας για την εμπειρία σου...', 'review.submit': 'Υποβολή αξιολόγησης', 'review.submitting': 'Αποστολή...', 'review.done': 'Η αξιολόγηση καταχωρήθηκε!', 'profile.reviews': 'Αξιολογήσεις', 'profile.no_reviews': 'Δεν υπάρχουν αξιολογήσεις ακόμα', 'profile.rating': 'Βαθμολογία', 'profile.skills.label': 'Δεξιότητες', 'profile.member_since': 'Μέλος από', 'task.offers': 'Προσφορές', 'task.offers.none': 'Δεν υπάρχουν ακόμα προσφορές', // Create task 'create.title': 'Δημοσίευση εργασίας', 'create.field.title': 'Τίτλος', 'create.field.description': 'Περιγραφή', 'create.field.category': 'Κατηγορία', 'create.field.category.select': 'Επιλέξτε...', 'create.field.location': 'Τοποθεσία', 'create.field.location.any': 'Οπουδήποτε', 'create.field.location.all': 'Ολόκληρη η πόλη', 'create.field.budget': 'Προϋπολογισμός (€)', 'create.field.deadline': 'Ημερομηνία έναρξης', 'create.field.budget_negotiable': 'Η τιμή είναι διαπραγματεύσιμη', 'create.field.time_slot': 'Χρόνος εκτέλεσης', 'create.field.time_slot.any': 'Οποιαδήποτε', 'create.field.time_slot.morning': 'Πρωινό (08:00–13:00)', 'create.field.time_slot.afternoon': 'Μεσημέρι (13:00–18:00)', 'create.field.time_slot.evening': 'Βράδυ (18:00–22:00)', 'create.field.time_slot.weekend': 'Σαββατοκύριακο', 'create.field.address': 'Διεύθυνση (προαιρετικά)', 'create.field.address.district': 'Συνοικία', 'create.field.address.street': 'Οδός', 'create.field.address.house': 'Αριθμός', 'create.field.confidential': 'Εμπιστευτική σημείωση', 'create.field.confidential.placeholder': 'Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...', 'create.field.confidential.hint': 'Δεν εμφανίζεται δημόσια', 'create.field.photos': 'Φωτογραφίες', 'create.field.photos.add': 'Προσθήκη φωτογραφίας', 'create.field.photos.uploading': 'Ανέβασμα...', 'task.budget_negotiable': 'Τιμή διαπραγματεύσιμη', 'task.time_slot': 'Χρόνος', 'task.confidential': 'Εμπιστευτική σημείωση', 'create.field.title.placeholder': 'π.χ. Καθαρισμός διαμερίσματος 80τμ', 'create.field.description.placeholder': 'Περίγραψε λεπτομερώς τι χρειάζεσαι...', 'create.field.location.placeholder': 'π.χ. Αθήνα, Κολωνάκι', 'create.field.budget.placeholder': 'π.χ. 100', 'create.submit': 'Δημοσίευση εργασίας', 'create.submitting': 'Δημοσίευση...', // Auth 'login.title': 'Καλωσόρισες', 'login.subtitle': 'Σύνδεση στο CanHelp', 'login.email': 'Email', 'login.password': 'Κωδικός', 'login.submit': 'Σύνδεση', 'login.submitting': 'Σύνδεση...', 'login.error': 'Λάθος email ή κωδικός', 'login.unverified.title': 'Επιβεβαιώστε το email σας', 'login.unverified.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.', 'login.unverified.resend': 'Αποστολή νέου email επαλήθευσης', 'login.unverified.sending': 'Αποστολή...', 'login.unverified.sent': '✓ Εστάλη — ελέγξτε τα εισερχόμενα', 'profile.email.verified': 'Email επαληθεύτηκε', 'profile.email.not_verified': 'Email δεν επαληθεύτηκε', 'login.no_account': 'Δεν έχεις λογαριασμό;', 'login.register_link': 'Εγγραφή', 'login.forgot_password': 'Ξέχασα τον κωδικό', 'login.or_continue_with': 'ή συνεχίστε με', 'login.continue_google': 'Σύνδεση με Google', 'forgot.title': 'Ξέχασα τον κωδικό', 'forgot.subtitle': 'Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης', 'forgot.email': 'Email', 'forgot.submit': 'Αποστολή', 'forgot.submitting': 'Αποστολή...', 'forgot.sent.title': 'Ελέγξτε τα εισερχόμενά σας', 'forgot.sent.desc': 'Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.', 'forgot.back_to_login': 'Επιστροφή στη σύνδεση', 'forgot.error': 'Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.', 'forgot.error.not_found': 'Δεν βρέθηκε λογαριασμός με αυτό το email.', 'forgot.error.send_failed': 'Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα', 'reset.title': 'Νέος κωδικός', 'reset.subtitle': 'Εισάγετε τον νέο σας κωδικό', 'reset.password': 'Νέος κωδικός', 'reset.confirm': 'Επιβεβαίωση κωδικού', 'reset.submit': 'Αλλαγή κωδικού', 'reset.submitting': 'Αποθήκευση...', 'reset.success': 'Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...', 'reset.back_to_login': 'Επιστροφή στη σύνδεση', 'reset.error.mismatch': 'Οι κωδικοί δεν ταιριάζουν', 'reset.error.invalid': 'Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.', 'register.title': 'Εγγραφή', 'register.subtitle': 'Δημιουργία λογαριασμού στο CanHelp', 'register.first_name': 'Όνομα', 'register.last_name': 'Επώνυμο', 'register.email': 'Email', 'register.password': 'Κωδικός (min 8 χαρακτήρες)', 'register.role': 'Ρόλος', 'register.role.customer': 'Χρήστης', 'register.role.customer.desc': 'Δημοσιεύω εργασίες', 'register.role.specialist': 'Ειδικός', 'register.role.specialist.desc': 'Αναλαμβάνω εργασίες', 'register.submit': 'Δημιουργία λογαριασμού', 'register.submitting': 'Εγγραφή...', 'register.has_account': 'Έχεις ήδη λογαριασμό;', 'register.login_link': 'Σύνδεση', 'register.continue_google': 'Εγγραφή με Google', 'register.check_email.title': 'Ελέγξτε το email σας', 'register.check_email.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.', 'register.check_email.login': 'Επιστροφή στη σύνδεση', // Dashboard 'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.new_task': '+ Νέα εργασία', 'dashboard.my_tasks': 'Οι εργασίες μου', 'dashboard.my_offers': 'Οι προσφορές μου', 'dashboard.invitations': 'Προσκλήσεις για εργασία', 'dashboard.offers_count': 'προσφορές', 'dashboard.declined_count': 'απορρίφθηκαν', 'dashboard.completed_tasks': 'Ολοκληρωμένες εργασίες', 'dashboard.completed_offers': 'Ολοκληρωμένες προσφορές', 'dashboard.review_pending': 'Η αξιολόγηση δεν έχει υποβληθεί ακόμα', 'tasks.new.top_specialists': 'Κορυφαίοι ειδικοί', 'tasks.new.select_category': 'Επιλέξτε κατηγορία για να δείτε ειδικούς', 'tasks.new.invite': 'Πρόσκληση', 'tasks.new.invited': 'Επιλέχθηκε ✓', 'reviews.count': 'αξιολογήσεις', 'filter.location': 'Τοποθεσία', 'filter.language': 'Γλώσσες', 'filter.language.any': 'Οποιαδήποτε γλώσσα', 'filter.category.all': 'Όλες οι κατηγορίες', 'user.categories': 'Κατηγορίες', 'user.work_area': 'Περιοχή εργασίας', 'dashboard.tasks.empty': 'Δεν έχεις δημοσιεύσει εργασίες', 'dashboard.tasks.empty.cta': 'Δημοσίευσε την πρώτη σου', 'dashboard.tasks.add_new': 'Πρόσθεσε νέα εργασία', 'dashboard.offers.empty': 'Δεν έχεις υποβάλλει προσφορές', 'dashboard.offers.empty.cta': 'Βρες εργασίες', 'dashboard.customer.specialists_title': 'Ψάχνεις εκτελεστή;', 'dashboard.customer.specialists_hint': 'Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου', 'dashboard.customer.specialists_cta': 'Βρες ειδικό', 'dashboard.customer.how_title': 'Πώς λειτουργεί', 'dashboard.customer.step1': 'Δημιούργησε εργασία με περιγραφή και προϋπολογισμό', 'dashboard.customer.step2': 'Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο', 'dashboard.customer.step3': 'Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία', // Notifications 'notif.title': 'Ειδοποιήσεις', 'notif.mark_all': 'Σήμανση όλων ως αναγνωσμένα', 'notif.empty': 'Δεν υπάρχουν ειδοποιήσεις', 'notif.type.new_offer': 'Νέα προσφορά', 'notif.type.offer_accepted': 'Η προσφορά σας έγινε δεκτή', 'notif.type.offer_declined': 'Η προσφορά σας απορρίφθηκε', 'notif.type.task_completed': 'Η εργασία ολοκληρώθηκε', 'notif.type.task_cancelled': 'Η εργασία ακυρώθηκε', 'notif.type.new_message': 'Νέο μήνυμα', 'notif.type.new_review': 'Νέα αξιολόγηση', 'notif.type.task_invite': 'Πρόσκληση σε εργασία', 'notif.body.new_offer': 'Νέα προσφορά για «{title}»', 'notif.body.offer_accepted': 'Η προσφορά σας για «{title}» έγινε δεκτή', 'notif.body.offer_declined': 'Η προσφορά σας για «{title}» απορρίφθηκε', 'notif.body.task_invite': 'Σας προσκαλούν για «{title}»', 'notif.body.new_review': 'Λάβατε αξιολόγηση {rating}★', // Offer status 'offer.status.pending': 'Εκκρεμεί', 'offer.status.accepted': 'Αποδεκτή', 'offer.status.declined': 'Απορρίφθηκε', 'offer.status.withdrawn': 'Αποσύρθηκε', 'offer.status.other_accepted': 'Επιλέχθηκε άλλος ειδικός', // Common 'common.loading': 'Φόρτωση...', 'common.error': 'Σφάλμα', 'common.save': 'Αποθήκευση', 'common.saving': 'Αποθήκευση...', 'common.cancel': 'Ακύρωση', 'common.add': 'Προσθήκη', 'common.close': 'Κλείσιμο', 'common.edit': 'Επεξεργασία', 'common.delete': 'Διαγραφή', 'common.from': 'από', 'common.currency': '€', 'common.greece': 'Ελλάδα', // Chat 'chat.connected': 'Συνδεδεμένος', 'chat.disconnected': 'Αποσυνδεδεμένος', 'chat.no_rooms': 'Δεν υπάρχουν συνομιλίες ακόμα', 'chat.task_fallback': 'Εργασία', 'chat.select': 'Επίλεξε συνομιλία', 'chat.no_messages': 'Δεν υπάρχουν μηνύματα', 'chat.placeholder': 'Γράψε μήνυμα... (Enter για αποστολή)', 'chat.conversation_fallback': 'Συνομιλία', 'chat.direct_chat': 'Απευθείας συνομιλία', 'chat.linked_task': 'Συνδεδεμένη εργασία', 'chat.write_btn': 'Μήνυμα', 'chat.just_now': 'μόλις τώρα', 'chat.min_ago': 'λ', 'chat.write_specialist': 'Γράψε στον ειδικό', 'chat.write_customer': 'Γράψε στον πελάτη', 'chat.notif_settings': 'Ρυθμίσεις ειδοποιήσεων', 'chat.notif_messages': 'Ειδοποιήσεις για νέα μηνύματα', 'chat.toast_title': 'Νέο μήνυμα', 'chat.toast_open': 'Άνοιγμα συνομιλίας', // Offer form 'offer.price': 'Τιμή', 'offer.price.placeholder': 'π.χ. 80', 'offer.customer_budget': 'Προϋπολογισμός πελάτη', 'offer.message': 'Μήνυμα', 'offer.optional': 'προαιρετικό', 'offer.message.placeholder': 'Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...', 'offer.submitting': 'Αποστολή...', // Profile 'profile.photo': 'Φωτογραφία προφίλ', 'profile.photo.change': 'Αλλαγή φωτογραφίας', 'profile.photo.hint': 'JPEG, PNG, WebP · έως 5MB', 'profile.basic_info': 'Βασικά στοιχεία', 'profile.phone': 'Τηλέφωνο', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Σύντομη περιγραφή', 'profile.bio.placeholder': 'Πες μας λίγα λόγια για εσένα...', 'profile.language': 'Γλώσσα', 'profile.language.hint': 'Γλώσσα διεπαφής και email ειδοποιήσεων', 'profile.languages': 'Γλώσσες επικοινωνίας', 'profile.languages.hint': 'Επιλέξτε όλες τις γλώσσες που μιλάτε', 'profile.skills': 'Δεξιότητες', 'profile.skills.subtitle': 'Προσθέσε τις υπηρεσίες που προσφέρεις', 'profile.skills.placeholder': 'π.χ. Καθαρισμός, IT, Μαθήματα...', 'profile.role': 'Ρόλος λογαριασμού', 'profile.role.specialist': '🔧 Ειδικός', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Χρήστης', 'profile.role.change': 'Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.', 'profile.become_specialist': 'Γίνε Ειδικός', 'profile.become_specialist.desc': 'Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.', 'become_specialist.hero.title': 'Κέρδισε χρήματα κάνοντας αυτό που ξέρεις', 'become_specialist.hero.subtitle': 'Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα', 'become_specialist.how.title': 'Πώς λειτουργεί', 'become_specialist.step1.title': 'Δημιούργησε κάρτα ειδικού', 'become_specialist.step1.desc': 'Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα', 'become_specialist.step2.title': 'Βρες εργασίες', 'become_specialist.step2.desc': 'Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα «Αναζήτηση εργασιών»', 'become_specialist.step3.title': 'Στείλε προσφορά & κέρδισε', 'become_specialist.step3.desc': 'Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες', 'become_specialist.benefits.title': 'Πλεονεκτήματα προφίλ ειδικού', 'become_specialist.benefit1': 'Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία', 'become_specialist.benefit2': 'Δημόσιο προφίλ με αξιολογήσεις πελατών', 'become_specialist.benefit3': 'Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες', 'become_specialist.benefit4': 'Προσθήκη σε αγαπημένα από πελάτες', 'become_specialist.cta': 'Περισσότερα', 'become_specialist.free_badge': 'Δωρεάν εγγραφή', 'profile.tab.notifications': 'Ειδοποιήσεις', 'profile.tab.reviews': 'Αξιολογήσεις', 'profile.tab.referral': 'Παραπομπές', 'profile.tab.auto_response': 'Αυτόματη απάντηση', 'profile.tab.site': 'Site', 'profile.site.title': 'Προσωπική σελίδα', 'profile.site.url_label': 'Προσωπικό site', 'profile.site.copy': 'Αντιγραφή', 'profile.site.copied': 'Αντιγράφηκε', 'profile.site.visible_title': 'Τι εμφανίζεται στη σελίδα σας', 'profile.site.visible.name': 'Όνομα και φωτογραφία', 'profile.site.visible.bio': 'Βιογραφικό', 'profile.site.visible.rating': 'Αξιολόγηση και κριτικές', 'profile.site.visible.portfolio': 'Χαρτοφυλάκιο / Κάρτες', 'profile.site.visible.contacts': 'Στοιχεία επικοινωνίας', 'profile.site.visible.full_last_name': 'Πλήρες επώνυμο', 'profile.site.visible.services': 'Κάρτες υπηρεσιών', 'profile.site.visible.reviews': 'Ενότητα κριτικών', 'profile.site.visible.status': 'Κατάσταση «Έτοιμος να βοηθήσω»', 'profile.site.theme': 'Θέμα εμφάνισης', 'profile.site.theme.dark': 'Σκοτεινό', 'profile.site.theme.light': 'Φωτεινό', 'profile.site.slug_taken': 'Αυτή η διεύθυνση είναι ήδη κατειλημμένη', 'profile.site.stats.title': 'Στατιστικά επισκεψιμότητας', 'profile.site.stats.days': 'τελευταίες 30 ημέρες', 'profile.site.stats.views': 'Προβολές', 'profile.site.stats.unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.messages': 'Μηνύματα', 'profile.site.stats.total_views': 'Συνολικές προβολές', 'profile.site.stats.total_unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.total_messages': 'Μηνύματα', 'profile.site.stats.empty': 'Δεν υπάρχουν δεδομένα ακόμη', 'profile.site.stats.loading': 'Φόρτωση στατιστικών...', 'profile.site.stats.no_slug': 'Ορίστε τη διεύθυνση του site για να δείτε στατιστικά', 'profile.site.edit_bio_hint': 'Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα «Βασικά».', 'status.can_help_now_hint': 'Η κάρτα σου εμφανίζεται ψηλότερα', 'status.need_help_hint': 'Οι ειδικοί μπορούν να σε βοηθήσουν', 'profile.referral.title': 'Πρόγραμμα παραπομπών', 'profile.referral.desc': 'Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.', 'profile.referral.link_label': 'Ο σύνδεσμος παραπομπής σου', 'profile.referral.copy': 'Αντιγραφή', 'profile.referral.copied': 'Αντιγράφηκε!', 'profile.referral.invited_count': 'επιτυχείς παραπομπές', 'profile.referral.no_code': 'Ο κωδικός παραπομπής δεν είναι διαθέσιμος.', 'notifications.title': 'Ρυθμίσεις ειδοποιήσεων', 'notifications.email.new_tasks': 'Email για νέες εργασίες', 'notifications.email.new_tasks.desc': 'Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου', 'notifications.messages.desc': 'Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα', 'notifications.saved': 'Ρυθμίσεις αποθηκεύτηκαν', 'notifications.plan_required': 'Συνδρομή απαιτείται για αυτή τη λειτουργία', 'profile.tab.info': 'Βασικά στοιχεία', 'profile.tab.finance': 'Οικονομικά', 'profile.tab.skills': 'Δεξιότητες', 'profile.tab.categories': 'Κατηγορίες', 'profile.tab.geography': 'Γεωγραφία', 'profile.specialist.categories': 'Κατηγορίες εργασιών', 'profile.specialist.categories.desc': 'Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι', 'profile.specialist.geography': 'Περιοχές κάλυψης', 'profile.specialist.geography.desc': 'Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι', 'profile.saving': 'Αποθήκευση...', 'profile.upload.error': 'Σφάλμα κατά την αναφόρτωση', 'profile.saved': 'Αποθηκεύτηκε', 'profile.tab.cards': 'Χαρτοφυλάκιο', 'profile.cards.count': 'Χαρτοφυλάκια', 'profile.cards.add': 'Νέο χαρτοφυλάκιο', 'profile.cards.new_title': 'Τίτλος νέου χαρτοφυλακίου', 'profile.cards.placeholder': 'π.χ. Υδραυλικά', 'profile.cards.create': 'Δημιουργία', 'profile.cards.cancel': 'Ακύρωση', 'profile.cards.empty': 'Δεν έχετε χαρτοφυλάκιο', 'profile.cards.create_first': 'Δημιουργήστε το πρώτο σας χαρτοφυλάκιο', 'profile.cards.delete_confirm': 'Διαγραφή χαρτοφυλακίου;', 'profile.card.tab.main': 'Γενικά', 'profile.card.tab.skills': 'Δεξιότητες', 'profile.card.tab.categories': 'Κατηγορίες', 'profile.card.tab.geography': 'Γεωγραφία', 'profile.card.tab.portfolio': 'Γκαλερί', 'profile.card.active': 'Ενεργή', 'profile.card.save': 'Αποθήκευση', 'profile.card.saved': 'Αποθηκεύτηκε', 'profile.card.delete': 'Διαγραφή', 'profile.card.skill.add': 'Προσθήκη δεξιότητας', 'profile.card.photo.add': 'Προσθήκη φωτογραφίας', 'profile.card.photo.uploading': 'Μεταφόρτωση...', 'profile.card.photo.empty': 'Δεν υπάρχουν φωτογραφίες', 'profile.card.item.title': 'Τίτλος', 'profile.card.item.desc': 'Περιγραφή', 'profile.card.item.save': 'Αποθήκευση', 'profile.card.item.cancel': 'Ακύρωση', 'profile.card.item.edit': 'Επεξεργασία', 'profile.upgrade.cards_limit': 'Όριο χαρτοφυλακίων εξαντλήθηκε', 'profile.upgrade.plan': 'Τρέχον πλάνο:', 'profile.upgrade.contact': 'Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου', 'profile.upgrade.ok': 'Εντάξει', 'profile.plan.title': 'Πλάνο συνδρομής', 'profile.balance': 'Υπόλοιπο', 'profile.balance.topup': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.amount': 'Ποσό (σε EUR)', 'profile.balance.topup.hint': 'Επιλέξτε ποσό ή εισαγάγετε μανούαλα', 'profile.balance.topup.submit': 'Πληρωμή', 'profile.balance.topup.loading': 'Ρεδιρεκτάρισμα...', 'profile.balance.topup.error': 'Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.', 'payment.success.title': 'Πληρωμή επιτυχής!', 'payment.success.desc': 'Το υπόλοιπό σας ενημερώθηκε.', 'payment.cancelled.title': 'Ακύρωση πληρωμής', 'payment.cancelled.desc': 'Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.', 'payment.pending.title': 'Σε εξέλιξη...', 'payment.pending.desc': 'Επεξεργαζόμαστε την πληρωμή σας.', 'payment.back_to_profile': 'Επιστροφή στο προφίλ', 'profile.plan.basic': 'Βασικό (δωρεάν)', 'profile.plan.contact_upgrade': 'Επικοινωνήστε με τον διαχειριστή για αναβάθμιση', 'profile.plan.cards_up_to': 'Χαρτοφυλάκια: έως', 'profile.plan.cards_unlimited': 'Χαρτοφυλάκια: απεριόριστα', 'profile.plan.tasks_up_to': 'Εργασίες: έως', 'profile.plan.offers_up_to': 'Προσφορές: έως', 'profile.plan.valid_until': 'Ισχύει έως', 'profile.plan.no_expiry': 'Δεν λήγει', // Create task 'create.error': 'Σφάλμα κατά τη δημοσίευση', // Tasks list extras 'tasks.category.general': 'Γενικά', 'tasks.budget.range': 'Εύρος:', 'tasks.budget.from': 'από', 'tasks.budget.to': 'έως', 'tasks.filter.reset': 'Εκκαθάριση φίλτρων', 'tasks.load_more': 'Φόρτωση ακόμα', 'tasks.showing': 'Αποτελέσματα:', 'tasks.field.budget': 'Προϋπολογισμός, €', // Admin 'admin.title': 'Πίνακας Διαχείρισης', 'admin.tab.stats': 'Στατιστικά', 'admin.tab.users': 'Χρήστες', 'admin.tab.tasks': 'Εργασίες', 'admin.tab.reports': 'Αναφορές', 'admin.stats.users': 'Χρήστες', 'admin.stats.tasks': 'Εργασίες', 'admin.stats.offers': 'Προσφορές', 'admin.stats.reviews': 'Αξιολογήσεις', 'admin.tasks.by_status': 'Εργασίες ανά κατάσταση', 'admin.col.user': 'Χρήστης', 'admin.col.email': 'Email', 'admin.col.role': 'Ρόλος', 'admin.col.registered': 'Εγγραφή', 'admin.col.status': 'Κατάσταση', 'admin.col.title': 'Τίτλος', 'admin.col.budget': 'Προϋπολογισμός', 'admin.col.created': 'Δημιουργία', 'admin.users.active': 'Ενεργός', 'admin.users.inactive': 'Ανενεργός', 'admin.users.deactivate': 'Απενεργοποίηση', 'admin.users.activate': 'Ενεργοποίηση', 'admin.tasks.cancel': 'Ακύρωση', 'admin.reports.none': 'Δεν υπάρχουν αναφορές', 'admin.reports.reviewed': 'Αναθεωρήθηκε', 'admin.reports.dismiss': 'Απόρριψη', 'admin.pagination.total': 'Σύνολο', 'admin.users.role.change': 'Αλλαγή ρόλου', 'admin.users.search.placeholder': 'Αναζήτηση ονόματος ή email...', 'admin.tasks.delete': 'Διαγραφή', 'admin.tasks.delete.confirm': 'Διαγραφή αυτής της εργασίας μόνιμα;', 'admin.tasks.search.placeholder': 'Αναζήτηση τίτλου...', 'admin.col.customer': 'Πελάτης', 'admin.col.reporter': 'Καταγγέλλων', 'admin.col.target': 'Στόχος', 'admin.filter.all_roles': 'Όλοι οι ρόλοι', 'admin.filter.all_statuses': 'Όλες οι καταστάσεις', 'admin.reports.target.task': 'Εργασία', 'admin.reports.target.user': 'Χρήστης', 'admin.tab.categories': 'Κατηγορίες', 'admin.tab.locations': 'Πόλεις & Περιοχές', 'admin.tab.logs': 'Αρχεία', 'admin.tab.plans': 'Πακέτα', 'admin.tab.settings': 'Ρυθμίσεις', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Δραστηριότητα', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Ειδοποιήσεις', 'admin.notif_logs.type': 'Τύπος', 'admin.notif_logs.title': 'Τίτλος', 'admin.notif_logs.read': 'Διαβασμένο', 'admin.notif_logs.empty': 'Δεν υπάρχουν αρχεία ειδοποιήσεων', 'admin.stats.notif_chart_title': 'Ειδοποιήσεις ανά ημέρα', 'admin.stats.notif_label': 'Ειδοποιήσεις', 'admin.stats.mail_chart_title': 'Emails ανά ημέρα', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Όλα', 'admin.stats.specialists': 'Ειδικοί', 'admin.col.plan': 'Πακέτο', 'admin.back_home': 'Αρχική', 'admin.plans.title': 'Πακέτα συνδρομής', 'admin.plans.add': '+ Νέο πακέτο', 'admin.plans.empty': 'Δεν υπάρχουν πακέτα', 'admin.plans.form.new': 'Νέο πακέτο', 'admin.plans.form.edit': 'Επεξεργασία πακέτου', 'admin.plans.form.name': 'Όνομα', 'admin.plans.form.price': 'Τιμή (EUR)', 'admin.plans.form.old_price': 'Παλιά τιμή (EUR, προαιρετικό)', 'admin.plans.form.max_offers': 'Μέγ. προσφορές (κενό = χωρίς όριο)', 'admin.plans.form.max_cards': 'Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)', 'admin.plans.form.duration_days': 'Διάρκεια (ημέρες, κενό = χωρίς λήξη)', 'admin.plans.form.description': 'Περιγραφή', 'admin.plans.form.features': 'Δυνατότητες (μία ανά γραμμή)', 'admin.plans.form.notify': 'Ειδοποιήσεις νέων εργασιών', 'admin.plans.form.default': 'Προεπιλογή', 'admin.plans.form.active': 'Ενεργό', 'admin.plans.form.order': 'Σειρά', 'admin.plans.form.role': 'Ρόλος', 'admin.plans.form.tier': 'Επίπεδο', 'admin.plans.form.role.customer': 'Πελάτης', 'admin.plans.form.role.specialist': 'Ειδικός', 'admin.plans.form.tier.free': 'Δωρεάν', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Όρια (κενό = χωρίς όριο)', 'admin.plans.form.max_messages_day': 'Μέγ. μηνύματα/ημέρα', 'admin.plans.form.max_orders_day': 'Μέγ. παραγγελίες/ημέρα', 'admin.plans.form.max_skills': 'Μέγ. δεξιότητες', 'admin.plans.form.max_profiles': 'Μέγ. προφίλ', 'admin.plans.form.max_portfolio': 'Μέγ. στοιχεία χαρτοφυλακίου', 'admin.plans.form.section.boost': 'Πολλαπλασιαστές & Ενίσχυση', 'admin.plans.form.search_boost': 'Ενίσχυση αναζήτησης', 'admin.plans.form.offers_multiplier': 'Πολλαπλασιαστής προσφορών', 'admin.plans.form.section.contact': 'Δικαιώματα επικοινωνίας', 'admin.plans.form.can_contact_free': 'Επικοινωνία με δωρεάν χρήστες', 'admin.plans.form.can_contact_pro': 'Επικοινωνία με Pro χρήστες', 'admin.plans.form.can_contact_all': 'Επικοινωνία με όλους', 'admin.plans.form.can_show_contact': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.plans.form.can_view_phone': 'Προβολή τηλεφώνου', 'admin.plans.form.section.features': 'Λειτουργίες', 'admin.plans.form.upload_video': 'Μεταφόρτωση βίντεο', 'admin.plans.form.favorites': 'Αγαπημένα', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Σήμα επαλήθευσης', 'admin.plans.form.highlighted_reviews': 'Προβεβλημένες κριτικές', 'admin.plans.form.personal_site': 'Προσωπική σελίδα', 'admin.plans.form.can_help_now': 'Κατάσταση «Μπορώ να βοηθήσω»', 'admin.plans.form.need_help': 'Κατάσταση «Χρειάζομαι βοήθεια»', 'admin.plans.form.auto_response': 'Αυτόματη απάντηση', 'admin.plans.form.auto_match': 'Αυτόματη αντιστοίχιση', 'admin.plans.form.instant_dispatch_free': 'Άμεση αποστολή (δωρεάν)', 'admin.plans.form.instant_dispatch_pro': 'Άμεση αποστολή (Pro)', 'admin.plans.badge.default': 'Προεπιλογή', 'admin.plans.badge.inactive': 'Ανενεργό', 'admin.plans.make_default': 'Ορισμός ως προεπιλογή', 'admin.plans.tasks': 'Εργασίες', 'admin.plans.offers': 'Προσφορές', 'admin.plans.cards': 'Χαρτοφυλάκιο', 'admin.plans.notify_tasks': 'Ειδοποιήσεις εργασιών', 'admin.plans.delete.confirm': 'Διαγραφή πακέτου', 'admin.activity.title': 'Αρχείο δραστηριότητας', 'admin.activity.event': 'Γεγονός', 'admin.activity.all_events': 'Όλα τα γεγονότα', 'admin.activity.from': 'Από', 'admin.activity.to': 'Έως', 'admin.activity.reset': 'Επαναφορά', 'admin.activity.total': 'Σύνολο', 'admin.activity.empty': 'Δεν υπάρχουν εγγραφές', 'admin.mail.event': 'Συμβάν email', 'admin.mail.all_events': 'Όλα τα email συμβάντα', 'admin.mail.from': 'Από', 'admin.mail.to': 'Έως', 'admin.mail.reset': 'Επαναφορά', 'admin.mail.total': 'Σύνολο', 'admin.mail.empty': 'Δεν υπάρχουν email logs', 'admin.mail.recipient': 'Παραλήπτης', 'admin.mail.provider': 'Πάροχος', 'admin.mail.details': 'Λεπτομέρειες', 'admin.mail.status': 'Κατάσταση', 'admin.mail.success': 'Επιτυχία', 'admin.mail.failed': 'Σφάλμα', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'Δεν υπάρχουν εγγραφές', 'admin.logs.date': 'Ημερομηνία', 'admin.logs.provider': 'Πάροχος', 'admin.logs.model': 'Μοντέλο', 'admin.logs.action': 'Ενέργεια', 'admin.logs.langs': 'Γλώσσες', 'admin.logs.in': 'Είσοδος', 'admin.logs.out': 'Έξοδος', 'admin.logs.total': 'Σύνολο', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Κατάσταση', 'admin.stats.activity_30d': 'Δραστηριότητα 30 ημερών', 'admin.stats.tasks_label': 'Εργασίες', 'admin.stats.users_label': 'Χρήστες', 'admin.stats.specialists_label': 'Ειδικοί', 'admin.stats.tokens_title': 'Χρήση tokens (ανά μήνα)', 'admin.stats.tokens_out': 'Εξερχόμενα', 'admin.stats.tokens_in': 'Εισερχόμενα', 'admin.stats.tokens_out_label': 'Εξερχόμενα tokens', 'admin.stats.tokens_in_label': 'Εισερχόμενα tokens', 'admin.stats.cost_label': 'Κόστος (USD)', 'admin.stats.tasks_by_status': 'Εργασίες ανά κατάσταση', 'admin.task_status.open': 'Ανοιχτές', 'admin.task_status.in_progress': 'Σε εξέλιξη', 'admin.task_status.completed': 'Ολοκληρωμένες', 'admin.task_status.cancelled': 'Ακυρωμένες', 'admin.task_status.draft': 'Προσχέδια', 'admin.settings.tab.general': 'Γενικά', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Ειδοποιήσεις', 'admin.settings.tab.payment': 'Πληρωμή', 'admin.settings.tab.referral': 'Παραπομπές', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Κοινωνικά δίκτυα', 'admin.settings.socials.title': 'Σύνδεσμοι κοινωνικών δικτύων', 'admin.settings.socials.hint': 'Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο', 'admin.settings.seo.maintenance_label': 'Λειτουργία συντήρησης', 'admin.settings.seo.maintenance_hint': 'Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες', 'admin.settings.seo.indexing_label': 'Ευρετηρίαση από μηχανές αναζήτησης', 'admin.settings.seo.indexing_hint': 'Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο', 'admin.settings.seo.head_scripts_label': 'Scripts στο (JS)', 'admin.settings.seo.head_scripts_hint': 'Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)', 'admin.settings.seo.site_title_label': 'Τίτλος ιστότοπου', 'admin.settings.seo.site_description_label': 'Περιγραφή ιστότοπου (meta description)', 'admin.settings.referral.title': 'Πρόγραμμα παραπομπών', 'admin.settings.referral.hint': 'Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.', 'admin.settings.referral.enabled_label': 'Ενεργό', 'admin.settings.referral.enabled_hint': 'Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών', 'admin.settings.referral.customer_section': 'Για πελάτες', 'admin.settings.referral.specialist_section': 'Για ειδικούς', 'admin.settings.referral.plan_label': 'Πλάνο ανταμοιβής', 'admin.settings.referral.no_plan': '— χωρίς πλάνο —', 'admin.settings.referral.plan_hint': 'Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.', 'admin.settings.referral.days_label': 'Ημέρες ανταμοιβής', 'admin.settings.referral.days_hint': 'Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.', 'admin.settings.general.title': 'Γενικές ρυθμίσεις', 'admin.settings.general.site_name': 'Όνομα ιστότοπου', 'admin.settings.general.site_url': 'URL ιστότοπου', 'admin.settings.general.contact_email': 'Email επικοινωνίας', 'admin.settings.general.support_phone': 'Τηλέφωνο υποστήριξης', 'admin.settings.smtp.title': 'Ρυθμίσεις SMTP', 'admin.settings.smtp.hint': 'Χρησιμοποιείται για αποστολή ειδοποιήσεων email.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Θύρα', 'admin.settings.smtp.encryption': 'Κρυπτογράφηση', 'admin.settings.smtp.enc.none': 'Χωρίς', 'admin.settings.smtp.enc.tls': 'STARTTLS (θύρα 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (θύρα 465)', 'admin.settings.smtp.username': 'Όνομα χρήστη', 'admin.settings.smtp.password': 'Κωδικός / App Password', 'admin.settings.smtp.from_name': 'Όνομα αποστολέα', 'admin.settings.smtp.from_email': 'Email αποστολέα', 'admin.settings.smtp.test': 'Αποστολή δοκιμαστικού email', 'admin.settings.smtp.sending': 'Αποστολή...', 'admin.settings.payment.hint': 'Τα στοιχεία για ePay Piraeus Bank.', 'admin.settings.env.test': 'Δοκιμαστικό (sandbox)', 'admin.settings.env.prod': 'Παραγωγή', 'admin.settings.env.label': 'Περιβάλλον', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Ενεργό', 'admin.settings.saving': 'Αποθήκευση...', 'admin.settings.saved': '✓ Αποθηκεύτηκε', 'admin.notif.vars_hint': 'Διαθέσιμες μεταβλητές στα πρότυπα', 'admin.notif.tmpl.not_set': 'Πρότυπο δεν έχει οριστεί', 'admin.notif.tmpl.subject_label': 'Θέμα email', 'admin.notif.tmpl.body_label': 'Κείμενο email (HTML)', 'admin.notif.tmpl.save': 'Αποθήκευση', 'admin.notif.tmpl.close': 'Κλείσιμο', 'admin.notif.tmpl.translate': 'Αυτόματη μετάφραση', 'admin.notif.tmpl.translating': 'Μετάφραση...', 'admin.notif.tmpl.saving': 'Αποθήκευση...', 'admin.notif.email_verification': 'Επαλήθευση email', 'admin.notif.registration_success': 'Επιτυχής εγγραφή', 'admin.notif.password_reset': 'Επαναφορά κωδικού', 'admin.notif.new_offer': 'Νέα προσφορά', 'admin.notif.new_task': 'Νέα εργασία', 'admin.notif.offer_accepted': 'Προσφορά αποδεκτή', 'admin.notif.new_message': 'Νέο μήνυμα', 'admin.notif.offer_declined': 'Απόρριψη προσφοράς', 'admin.notif.offer_other_accepted': 'Επιλέχθηκε άλλος ειδικός', 'admin.notif.task_updated': 'Ενημέρωση εργασίας', 'admin.notif.deadline_reminder': 'Υπενθύμιση προθεσμίας', 'admin.notif.task_archived': 'Αυτόματη απόσυρση εργασίας', 'admin.notif.referral_reward': 'Ανταμοιβή παραπομπής', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Τιμολόγιο — ενεργοποίηση πλάνου', 'admin.email_template.plan_upgraded': 'Τιμολόγιο — αναβάθμιση πλάνου', 'admin.email_template.plan_downgrade_scheduled': 'Τιμολόγιο — προγραμματισμένη υποβάθμιση', 'admin.email_template.plan_downgrade_applied': 'Τιμολόγιο — εφαρμογή υποβάθμισης', 'admin.email_template.plan_renewal_reminder': 'Τιμολόγιο — υπενθύμιση ανανέωσης', 'admin.email_template.plan_insufficient_funds': 'Τιμολόγιο — ανεπαρκές υπόλοιπο', // Pricing confirm modal 'pricing.confirm.title': 'Επιβεβαίωση επιλογής πλάνου', 'pricing.confirm.plan': 'Πλάνο', 'pricing.confirm.prorated': 'Αναλογική έκπτωση', 'pricing.confirm.effective_price': 'Προς πληρωμή', 'pricing.confirm.your_balance': 'Το υπόλοιπό σας', 'pricing.confirm.downgrade_info': 'Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.', 'pricing.confirm.insufficient': 'Ανεπαρκές υπόλοιπο.', 'pricing.confirm.top_up': 'Ανανέωση', 'pricing.confirm.schedule_downgrade': 'Προγραμματισμός μετάβασης', 'pricing.confirm.pay': 'Πληρωμή', 'admin.user_edit.title': 'Επεξεργασία χρήστη', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Διευθυνση email επαληθεύτηκε', 'admin.user_edit.email_not_verified': 'Email δεν έχει επαληθευτεί', 'admin.user_edit.verify_email_btn': 'Χειροκίνητη επαλήθευση', 'admin.user_edit.verify_email_done': 'Email επαληθεύτηκε!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Εγγραφή', 'admin.user_edit.last_seen': 'Τελευταία σύνδεση', 'admin.user_edit.lang': 'Γλώσσα', 'admin.user_edit.first_name': 'Όνομα', 'admin.user_edit.last_name': 'Επώνυμο', 'admin.user_edit.phone': 'Τηλέφωνο', 'admin.user_edit.bio': 'Βιογραφικό', 'admin.user_edit.role': 'Ρόλος', 'admin.user_edit.plan': 'Πακέτο', 'admin.user_edit.no_plan': '— Χωρίς πακέτο —', 'admin.user_edit.active': 'Ενεργός λογαριασμός', 'admin.user_edit.balance': 'Υπόλοιπο (EUR)', 'admin.user_edit.skills': 'Δεξιότητες', 'admin.user_edit.tab.profile': 'Προφίλ', 'admin.user_edit.tab.account': 'Λογαριασμός', 'admin.user_edit.tab.balance': 'Υπόλοιπο', 'admin.user_edit.tab.settings': 'Ρυθμίσεις', 'admin.user_edit.tab.specialist': 'Χαρτοφυλάκιο', 'admin.user_edit.tab.site': 'Ιστοσελίδα', 'admin.user_edit.plan_expires': 'Λήξη πλάνου', 'admin.user_edit.interface_lang': 'Γλώσσα διεπαφής', 'admin.user_edit.comm_languages': 'Γλώσσες επικοινωνίας', 'admin.user_edit.personal_site_slug': 'Προσωπική σελίδα', 'admin.user_edit.show_contact_info': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.user_edit.show_contact_info.hint': 'Ορατό στους πελάτες', 'admin.user_edit.notify_new_tasks': 'Ειδοποίηση για νέες εργασίες', 'admin.user_edit.notify_new_tasks.hint': 'Push και email ειδοποιήσεις', 'admin.user_edit.notif_messages': 'Ειδοποιήσεις μηνυμάτων', 'admin.user_edit.notif_messages.hint': 'Νέα μηνύματα στη συνομιλία', 'admin.user_edit.site_settings': 'Ρυθμίσεις προσωπικής σελίδας', 'admin.user_edit.categories': 'Κατηγορίες υπηρεσιών', 'admin.user_edit.locations': 'Περιοχές εξυπηρέτησης', 'admin.user_edit.skill_placeholder': 'Νέα δεξιότητα...', 'admin.user_edit.add_category': '— Επιλέξτε κατηγορία —', 'admin.user_edit.add_location': '— Επιλέξτε περιοχή —', 'admin.user_edit.specialist_cards': 'Χαρτοφυλάκιο ειδικού', 'admin.user_edit.no_cards': 'Δεν βρέθηκαν στοιχεία χαρτοφυλακίου', 'admin.user_edit.card_title': 'Τίτλος χαρτοφυλακίου', 'admin.user_edit.card_description': 'Περιγραφή', 'admin.balance.topup.btn': 'Αναπλήρωση', 'admin.balance.withdraw.btn': 'Αφαίρεση', 'admin.balance.modal_hint': 'Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό', 'admin.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'admin.balance.topup.amount': 'Ποσό', 'admin.balance.topup.description': 'Σχόλιο', 'admin.balance.topup.description.placeholder': 'Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση', 'admin.balance.topup.submit': 'Αναπλήρωση υπολοίπου', 'admin.balance.withdraw.title': 'Αφαίρεση υπολοίπου', 'admin.balance.withdraw.amount': 'Ποσό', 'admin.balance.withdraw.description': 'Σχόλιο', 'admin.balance.withdraw.description.placeholder': 'Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση', 'admin.balance.withdraw.submit': 'Αφαίρεση από το υπόλοιπο', 'admin.user_edit.role.customer': 'Πελάτης', 'admin.user_edit.role.specialist': 'Ειδικός', 'admin.user_edit.role.admin': 'Διαχειριστής', 'common.refresh': 'Ανανέωση', 'common.back_home': 'Αρχική', 'admin.loc.hint': 'Διαχείριση πόλεων και συνοικιών', 'admin.loc.add_city': 'Νέα πόλη', 'admin.loc.add_district': 'Προσθήκη συνοικίας', 'admin.loc.new': 'Νέα τοποθεσία', 'admin.loc.edit': 'Επεξεργασία τοποθεσίας', 'admin.loc.district': 'συνοικία', 'admin.loc.empty': 'Δεν υπάρχουν τοποθεσίες', 'admin.loc.delete.confirm': 'Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.', 'admin.cat.add_root': 'Νέα κατηγορία', 'admin.cat.add_sub': 'Υποκατηγορία', 'admin.cat.edit': 'Επεξεργασία', 'admin.cat.delete': 'Διαγραφή', 'admin.cat.delete.confirm': 'Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Εικονίδιο', 'admin.cat.name_el': 'Ελληνικά', 'admin.cat.name_en': 'Αγγλικά', 'admin.cat.name_ru': 'Ρωσικά', 'admin.cat.order': 'Σειρά', 'admin.cat.active': 'Ενεργή', 'admin.cat.parent': 'Γονική κατηγορία', 'admin.cat.no_parent': 'Κορυφαίο επίπεδο', 'admin.cat.save': 'Αποθήκευση', 'admin.cat.cancel': 'Ακύρωση', 'admin.cat.empty': 'Δεν υπάρχουν κατηγορίες', 'admin.cat.hint': 'Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία', 'admin.cat.new': 'Νέα κατηγορία', 'admin.cat.subcategory': 'υποκατηγορία', 'admin.cat.add_child': 'Προσθήκη υποκατηγορίας', 'admin.cat.inactive': 'Ανενεργή', 'admin.event.user_login': 'Σύνδεση', 'admin.event.user_register': 'Εγγραφή', 'admin.event.admin_user_deactivate': 'Αποκλεισμός χρήστη', 'admin.event.admin_user_activate': 'Ενεργοποίηση χρήστη', 'admin.event.admin_user_role_changed': 'Αλλαγή ρόλου', 'admin.event.admin_task_cancelled': 'Ακύρωση εργασίας', 'admin.event.admin_task_deleted': 'Διαγραφή εργασίας', 'admin.event.admin_report_reviewed': 'Αναφορά εξετάστηκε', 'admin.event.admin_report_dismissed': 'Αναφορά απορρίφθηκε', 'admin.event.task_created': 'Δημιουργία εργασίας', 'user.online': 'Σε σύνδεση', 'user.seen_minutes': 'ήταν εδώ πριν {n} λεπτά', 'user.seen_hours': 'ήταν εδώ πριν {n} ώρες', 'user.seen_yesterday': 'ήταν εδώ χθες', 'user.seen_days': 'ήταν εδώ πριν {n} μέρες', // Specialists 'specialists.title': 'Ειδικοί', 'specialists.search': 'Αναζήτηση ειδικού...', 'specialists.search.btn': 'Αναζήτηση', 'specialists.empty': 'Δεν βρέθηκαν ειδικοί', 'specialists.no_bio': 'Χωρίς περιγραφή', 'specialists.view': 'Προβολή προφίλ', 'specialists.reviews': 'αξιολογήσεις', 'specialist.favorite': 'Προσθήκη στα αγαπημένα', 'specialist.unfavorite': 'Αφαίρεση από αγαπημένα', 'specialist.site_link': 'Προσωπικό site', 'favorites.specialists.title': 'Αγαπημένοι ειδικοί', 'favorites.specialists.empty': 'Δεν έχετε αγαπημένους ειδικούς', 'nav.favorites': 'Αγαπημένα', 'nav.schedule': 'Πρόγραμμα', 'nav.find_tasks': 'Αναζήτηση εργασιών', 'schedule.title': 'Το πρόγραμμά μου', 'schedule.subtitle': 'Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας', 'schedule.available': 'Ελεύθερος', 'schedule.busy': 'Απασχολημένος', 'schedule.unset': 'Μη ορισμένο', 'schedule.click_hint': '← κλικ για εναλλαγή κατάστασης', 'schedule.range_mode': 'Επιλογή εύρους', 'schedule.range_from': 'Από {date} — επιλέξτε τελική ημερομηνία', 'schedule.click_to_set': 'Κλικ για ορισμό', 'schedule.free': 'ελεύθερα', 'schedule.busy_count': 'απασχολημένα', 'schedule.free_days': 'ελεύθερες ημέρες', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Σύνδεση με Google Calendar', 'schedule.disconnectGoogle': 'Αποσύνδεση', 'schedule.connectedAs': 'Συνδεδεμένο ως', 'schedule.importFromGoogle': 'Συγχρονισμός από Google', 'schedule.gcalConnected': '✓ Google Calendar συνδέθηκε', 'schedule.gcalError': 'Σφάλμα σύνδεσης Google Calendar', 'schedule.gcalImportDone': 'Εισήχθησαν {n} ημερ. από Google Calendar', 'schedule.gcalAutoSyncNote': 'Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar', 'schedule.gcalConnectDesc': 'Συνδέστε το Google Calendar για αυτόματο συγχρονισμό', 'schedule.gcalDisconnectConfirm': 'Αποσύνδεση Google Calendar;', 'find_tasks.title': 'Αναζήτηση εργασιών', 'find_tasks.for_me': 'Για μένα', 'find_tasks.all': 'Όλες οι εργασίες', 'find_tasks.by_category': 'Ανά κατηγορία', 'find_tasks.list': 'Λίστα', 'find_tasks.already_offered': 'Προσφορά υποβλήθηκε', 'find_tasks.offer_now': 'Υποβολή προσφοράς', 'find_tasks.empty_for_me': 'Δεν βρέθηκαν εργασίες στις κατηγορίες σας', 'find_tasks.banner_hint': 'Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας', 'find_tasks.no_cards': 'Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς', 'find_tasks.add_card': 'Δημιουργία χαρτοφυλακίου', 'find_tasks.search': 'Αναζήτηση εργασιών...', 'find_tasks.tasks_count': 'εργασίες', // Footer 'footer.tagline': 'Η πλατφόρμα εργασιών για την Ελλάδα', 'footer.rights': 'Όλα τα δικαιώματα διατηρούνται.', // App download section 'app.download_title': 'Κατεβάστε την εφαρμογή CanHelp', 'app.download_desc': 'Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.', // Nav 'nav.pricing': 'Τιμές', // Pricing page 'pricing.title': 'Τιμολόγηση', 'pricing.subtitle': 'Επιλέξτε το κατάλληλο πρόγραμμα', 'pricing.role.customer': 'Πελάτης', 'pricing.role.specialist': 'Ειδικός', 'pricing.free': 'Δωρεάν', 'pricing.per_month': 'μήνα', 'pricing.duration': 'Διάρκεια', 'pricing.days': 'ημ.', 'pricing.current_plan': 'Το πρόγραμμά σας', 'pricing.popular': 'Δημοφιλές', 'pricing.choose': 'Επιλογή', 'pricing.your_plan': 'Ενεργό πρόγραμμα', 'pricing.free_default': 'Προεπιλογή', 'pricing.compare': 'Σύγκριση λειτουργιών', 'pricing.feature': 'Λειτουργία', 'pricing.faq_note': 'Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.', 'pricing.feat.messages': 'Μηνύματα / ημέρα', 'pricing.feat.orders': 'Παραγγελίες / ημέρα', 'pricing.feat.contact_all': 'Επικοινωνία με όλους', 'pricing.feat.view_phone': 'Εμφάνιση τηλεφώνου', 'pricing.feat.show_contact': 'Εμφάνιση στοιχείων επαφής', 'pricing.feat.favorites': 'Αγαπημένα', 'pricing.feat.verified_badge': 'Επαληθευμένο badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Προσωπικό site', 'pricing.feat.auto_response': 'Αυτόματη απάντηση', 'pricing.feat.auto_match': 'Αυτόματη αντιστοίχιση', 'pricing.feat.highlighted_reviews': 'Επισημασμένες αξιολογήσεις', 'pricing.feat.portfolio': 'Στοιχεία χαρτοφυλακίου', 'pricing.feat.cards': 'Κάρτες ειδικού', 'pricing.feat.notify_tasks': 'Ειδοποιήσεις νέων εργασιών', 'pricing.feat.video': 'Βίντεο στο χαρτοφυλάκιο', // Upgrade prompt 'upgrade.available_in': 'Διαθέσιμο στο', 'upgrade.cta': 'Αναβάθμιση', // Dashboard plan block 'dashboard.plan.title': 'Το πρόγραμμά μου', 'dashboard.plan.expires': 'Λήγει σε {n} ημέρες', 'dashboard.plan.upgrade': 'Αναβάθμιση προγράμματος', 'dashboard.plan.no_plan': 'Δωρεάν πρόγραμμα', 'dashboard.plan.messages': 'Μηνύματα σήμερα', 'dashboard.plan.orders': 'Παραγγελίες σήμερα', 'dashboard.plan.limits': 'Ημερήσια όρια', 'dashboard.plan.features': 'Λειτουργίες', 'dashboard.plan.stats': 'Στατιστικά', 'dashboard.stats.cards': 'Χαρτοφυλάκια', 'dashboard.stats.maxCards': 'Μέγ. χαρτοφυλάκια', 'dashboard.stats.portfolioItems': 'Στοιχεία portfolio', 'dashboard.stats.maxPortfolioItems': 'Μέγ. στοιχεία', 'dashboard.stats.activeOffers': 'Ενεργές προσφορές', 'dashboard.stats.reviewsReceived': 'Αξιολογήσεις', 'dashboard.stats.activeTasks': 'Ενεργές εργασίες', 'dashboard.stats.completedTasks': 'Ολοκληρωμένες', 'status.can_help_now': 'Είμαι διαθέσιμος τώρα', 'status.need_help': 'Χρειάζομαι βοήθεια', 'status.active': 'Ενεργό', 'status.toggle_on': 'Ενεργοποίηση', 'status.toggle_off': 'Απενεργοποίηση', // FOMO 'fomo.missed_orders': 'Χάσατε {n} παραγγελίες', 'fomo.missed_value': 'Αξία €{v}', 'fomo.upgrade_hint': 'Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες', 'fomo.conversion': 'Μετατροπές εργασιών', 'fomo.active': 'Ενεργές', 'fomo.with_offers': 'Με προσφορές', 'fomo.completed': 'Ολοκληρωμένες', 'fomo.already_offered': '{n} ειδικοί έχουν ήδη απαντήσει', 'fomo.specialist_missed': 'Χάσατε {n} παραγγελίες', 'fomo.top_categories': 'Κατηγορίες', 'fomo.offers_received': 'προσφορές ελήφθησαν', 'fomo.avg_offers': 'Μέσο {n}/εργασία', 'fomo.completion_rate': 'ολοκληρωμένες', // Task auto-match 'task.auto_match': 'Αυτόματη αντιστοίχιση', 'task.auto_match_results': 'Κορυφαίοι ειδικοί', 'task.no_offer_yet': 'Δεν έχετε στείλει προσφορά ακόμα', 'task.make_offer': 'Αποστολή προσφοράς', 'auto_response.title': 'Αυτόματη Απάντηση', 'auto_response.enabled': 'Ενεργοποίηση αυτόματης απάντησης', 'auto_response.min_budget': 'Ελάχ. προϋπολογισμός', 'auto_response.max_budget': 'Μέγ. προϋπολογισμός', 'auto_response.default_price': 'Προεπιλεγμένη τιμή', 'auto_response.default_message': 'Προεπιλεγμένο μήνυμα', 'auto_response.max_per_day': 'Μέγ. αυτόματες προσφορές/ημέρα', 'auto_response.save': 'Αποθήκευση', 'auto_response.saved': 'Αποθηκεύτηκε', 'auto_response.categories': 'Κατηγορίες', 'auto_response.locations': 'Τοποθεσίες', // Personal site 'profile.personal_site': 'Προσωπικό Site', 'profile.site_slug': 'Slug URL', 'profile.site_slug_hint': 'Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _', 'profile.site_open': 'Άνοιγμα site', 'profile.site_preview': 'Το site σας', 'profile.show_contact': 'Εμφάνιση στοιχείων επαφής', 'profile.show_contact_hint': 'Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας', // Google Calendar plan gate 'gcal.upgrade_required': 'Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα', // Chat limits 'chat.limit_warning': 'Απομένουν {n} μηνύματα σήμερα', 'chat.limit_reached': 'Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας', 'chat.upgrade': 'Αναβάθμιση', // Site page 'site.member_since': 'Μαζί μας από', 'site.rating': 'Βαθμολογία', 'site.completed_tasks': 'Ολοκληρώθηκαν', 'site.languages': 'Γλώσσες', 'site.photos': 'φωτ.', 'site.contact_form': 'Επικοινωνία', 'site.contact_sent': 'Το μήνυμα στάλθηκε!', 'site.contact_sent_desc': 'Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα', 'site.contact_name': 'Όνομα', 'site.contact_name_ph': 'Το όνομά σας', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Μήνυμα', 'site.contact_message_ph': 'Περιγράψτε την εργασία σας...', 'site.contact_send': 'Αποστολή', 'site.share': 'Κοινοποίηση', 'site.speaks_languages': 'Μιλάει', 'site.message_sent': 'Το μήνυμα εστάλη!', 'site.message_sent_desc': 'Ο ειδικός θα το λάβει στη συνομιλία', 'site.message_placeholder': 'Γράψτε το μήνυμά σας...', 'site.write_to_chat': 'Γράψτε στο chat', 'site.auth_required_title': 'Απαιτείται σύνδεση', 'site.auth_required_desc': 'Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.', 'site.auth_login_btn': 'Σύνδεση', 'site.auth_contact_form_btn': 'Επικοινωνία μέσω φόρμας', 'specialist.services': 'Υπηρεσίες', 'portfolio.title': 'Χαρτοφυλάκιο', 'common.not_found': 'Η σελίδα δεν βρέθηκε', 'common.anonymous': 'Ανώνυμα', 'specialist_setup.page_title': 'Ρύθμιση προφίλ ειδικού', 'specialist_setup.step_of': 'Βήμα {current} από {total}', 'specialist_setup.next': 'Επόμενο', 'specialist_setup.back': 'Πίσω', 'specialist_setup.skip': 'Παράλειψη', 'specialist_setup.finish': 'Ολοκλήρωση', 'specialist_setup.go_to_profile': 'Μεταβείτε στο προφίλ', 'specialist_setup.browse_tasks': 'Εξερεύνηση εργασιών', 'specialist_setup.step1.title': 'Καλωσήλθατε!', 'specialist_setup.step1.subtitle': 'Ας ρυθμίσουμε το προφίλ σας', 'specialist_setup.step1.desc': 'Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.', 'specialist_setup.step1.what_next': 'Τι θα κάνουμε:', 'specialist_setup.step1.item1': 'Συμπλήρωση βασικών πληροφοριών', 'specialist_setup.step1.item2': 'Δημιουργία κάρτας υπηρεσίας', 'specialist_setup.step1.item3': 'Προσθήκη δεξιοτήτων και κατηγοριών', 'specialist_setup.step1.item4': 'Επιλογή γεωγραφικής περιοχής', 'specialist_setup.step1.item5': 'Μεταφόρτωση φωτογραφιών χαρτοφυλακίου', 'specialist_setup.step2.title': 'Βασικό προφίλ', 'specialist_setup.step2.subtitle': 'Πείτε μας για σας', 'specialist_setup.step2.bio_label': 'Σχετικά με εμένα', 'specialist_setup.step2.bio_placeholder': 'Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...', 'specialist_setup.step2.phone_label': 'Τηλέφωνο', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Φωτογραφία προφίλ', 'specialist_setup.step2.photo_btn': 'Μεταφόρτωση φωτογραφίας', 'specialist_setup.step2.photo_uploading': 'Μεταφόρτωση...', 'specialist_setup.step2.photo_hint': 'Εμφανίζεται στο προφίλ σας', 'specialist_setup.step3.title': 'Κάρτα υπηρεσίας', 'specialist_setup.step3.subtitle': 'Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας', 'specialist_setup.step3.title_label': 'Τίτλος κάρτας', 'specialist_setup.step3.title_placeholder': 'Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...', 'specialist_setup.step3.desc_label': 'Περιγραφή', 'specialist_setup.step3.desc_placeholder': 'Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...', 'specialist_setup.step3.title_required': 'Απαιτείται τίτλος', 'specialist_setup.step4.title': 'Δεξιότητες & Κατηγορίες', 'specialist_setup.step4.subtitle': 'Προσθέστε δεξιότητες και επιλέξτε κατηγορίες', 'specialist_setup.step4.skills_label': 'Δεξιότητες', 'specialist_setup.step4.skills_placeholder': 'Π.χ. Εγκατάσταση σωληνώσεων...', 'specialist_setup.step4.skills_add': 'Προσθήκη', 'specialist_setup.step4.categories_label': 'Κατηγορίες', 'specialist_setup.step5.title': 'Γεωγραφική περιοχή', 'specialist_setup.step5.subtitle': 'Πού παρέχετε υπηρεσίες;', 'specialist_setup.step5.hint': 'Επιλέξτε πόλεις ή συγκεκριμένες περιοχές', 'specialist_setup.done.title': 'Το προφίλ σας είναι έτοιμο!', 'specialist_setup.done.subtitle': 'Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί', 'specialist_setup.done.desc': 'Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας.' }, en: { 'footer.slogan': 'Your task — our care! We solve any issue quickly and easily.', 'footer.links': 'Links', 'footer.socials': 'Socials', 'nav.home': 'Home', 'nav.tasks': 'Tasks', 'nav.post': '+ Post task', 'nav.dashboard': 'Dashboard', 'nav.chat': 'Messages', 'nav.notifications': 'Notifications', 'nav.profile': 'Profile', 'nav.admin': 'Admin Panel', 'nav.specialists': 'Specialists', 'nav.new_task': 'New task', 'nav.login': 'Login', 'nav.register': 'Register', 'nav.logout': 'Logout', 'hero.title': 'Find a specialist for any job', 'hero.subtitle': 'Post a task, receive offers and choose the best professional', 'hero.cta.post': 'Post a task', 'hero.cta.browse': 'Become a specialist', 'hero.search.placeholder': 'What do you need? e.g. electrician, cleaning...', 'stats.specialists': 'specialists', 'stats.tasks': 'tasks', 'stats.categories': 'categories', 'stats.free': 'free sign-up', 'section.categories': 'Create a task in any category', 'section.how': 'How it works', 'section.recent': 'Recent tasks', 'section.all': 'See all →', 'section.more': 'more', 'section.cities': 'Cities & Districts', 'section.community': 'A community project for everyone', 'community.subtitle': 'CanHelp is not just a marketplace — it\'s a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.', 'community.point1.title': 'Are you good at something?', 'community.point1.desc': 'Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.', 'community.point2.title': 'Need help with something?', 'community.point2.desc': 'Post a task in under a minute and receive offers from verified specialists in your city.', 'community.point3.title': 'Help the project grow', 'community.point3.desc': 'CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.', 'community.share': 'Share with friends', 'community.share.copied': 'Link copied!', // Referral section on home page 'section.referral': 'Referral Program', 'referral.home.subtitle': 'Share your link — every new user who signs up through it earns you a reward.', 'referral.home.step1.title': 'Sign up and get your link', 'referral.home.step1.desc': 'Create an account and find your unique referral link in your profile.', 'referral.home.step2.title': 'Share with friends', 'referral.home.step2.desc': 'Send the link to friends, acquaintances, or post it on social media.', 'referral.home.step3.title': 'Earn rewards', 'referral.home.step3.desc': 'Once your friend verifies their email, you automatically receive your reward.', 'referral.home.cta': 'Get your link', 'referral.home.badge': 'Referral Program', // FAQ section 'section.faq': 'Frequently Asked Questions', 'faq.q1': 'How does CanHelp work?', 'faq.a1': 'Post a task, receive offers from specialists, choose the best one and start working together. It\'s fast, simple and free for customers.', 'faq.q2': 'How much does it cost to use the platform?', 'faq.a2': 'Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.', 'faq.q3': 'How can I become a specialist?', 'faq.a3': 'Register, go to «Become a Specialist», fill in your profile with skills and categories, and start receiving tasks.', 'faq.q4': 'How do I choose the right specialist?', 'faq.a4': 'Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.', 'faq.q5': 'What if I am not satisfied?', 'faq.a5': 'You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.', 'faq.q6': 'Can I contact a specialist before accepting their offer?', 'faq.a6': 'Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.', 'faq.q7': 'How long does it take to receive offers?', 'faq.a7': 'Usually within a few hours. Specialists get notified about new tasks and can respond quickly.', 'faq.q8': 'Can I post a task in any city in Greece?', 'faq.a8': 'Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.', 'faq.q9': 'What types of tasks can I find on CanHelp?', 'faq.a9': 'Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.', 'faq.q10': 'Is there a mobile app?', 'faq.a10': 'Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.', 'how.step1.title': 'Post a task', 'how.step1.desc': 'Describe what you need and set your budget', 'how.step2.title': 'Receive offers', 'how.step2.desc': 'Specialists will send you offers with price and timeline', 'how.step3.title': 'Choose & start', 'how.step3.desc': 'Pick the best professional and start the collaboration', 'tasks.title': 'tasks', 'tasks.filters': 'Filters', 'tasks.search': 'Search', 'tasks.search.placeholder': 'Title or keyword...', 'tasks.search.btn': 'Search', 'tasks.publish': 'Post', 'tasks.category.all': 'All', 'tasks.category.all_in': 'All in', 'tasks.category.label': 'Category', 'tasks.location.label': 'City', 'tasks.location.placeholder': 'e.g. Athens', 'tasks.empty': 'No tasks found', 'tasks.empty.cta': 'Post the first one', 'task.status.open': 'Open', 'task.status.in_progress': 'In progress', 'task.status.completed': 'Completed', 'task.status.cancelled': 'Cancelled', 'task.status.draft': 'Draft', 'task.budget': 'Budget', 'task.location': 'Location', 'task.deadline': 'Start date', 'task.created_at': 'Created', 'task.customer': 'Customer', 'task.offer.btn': 'Submit offer', 'task.invite.banner_title': "You've been invited to this task", 'task.invite.banner_hint': 'The customer personally invited you', 'task.invite.accept': 'Send offer', 'task.invite.decline': 'Decline', 'offer.accept': 'Accept', 'offer.decline': 'Decline', 'task.complete': 'Complete task', 'task.complete.confirm': 'Mark this task as complete?', 'task.edit': 'Edit', 'task.status_label': 'Status', 'task.yours': 'Your task', 'task.offer.yours': 'Your offer', 'review.leave': 'Leave a review', 'review.rating': 'Rating', 'review.comment': 'Comment', 'review.comment.placeholder': 'Tell us about your experience...', 'review.submit': 'Submit review', 'review.submitting': 'Submitting...', 'review.done': 'Review submitted!', 'profile.reviews': 'Reviews', 'profile.no_reviews': 'No reviews yet', 'profile.rating': 'Rating', 'profile.skills.label': 'Skills', 'profile.member_since': 'Member since', 'task.offers': 'Offers', 'task.offers.none': 'No offers yet', 'create.title': 'Post a task', 'create.field.title': 'Title', 'create.field.description': 'Description', 'create.field.category': 'Category', 'create.field.category.select': 'Select...', 'create.field.location': 'Location', 'create.field.location.any': 'Anywhere', 'create.field.location.all': 'Entire city', 'create.field.budget': 'Budget (€)', 'create.field.deadline': 'Start date', 'create.field.budget_negotiable': 'Price is negotiable', 'create.field.time_slot': 'Time slot', 'create.field.time_slot.any': 'Anytime', 'create.field.time_slot.morning': 'Morning (08:00–13:00)', 'create.field.time_slot.afternoon': 'Afternoon (13:00–18:00)', 'create.field.time_slot.evening': 'Evening (18:00–22:00)', 'create.field.time_slot.weekend': 'Weekend', 'create.field.address': 'Address (optional)', 'create.field.address.district': 'District', 'create.field.address.street': 'Street', 'create.field.address.house': 'Number', 'create.field.confidential': 'Confidential note', 'create.field.confidential.placeholder': 'Details visible only to the assigned specialist...', 'create.field.confidential.hint': 'Not shown publicly', 'create.field.photos': 'Photos', 'create.field.photos.add': 'Add photo', 'create.field.photos.uploading': 'Uploading...', 'task.budget_negotiable': 'Price negotiable', 'task.time_slot': 'Time slot', 'task.confidential': 'Confidential note', 'create.field.title.placeholder': 'e.g. Clean 80sqm apartment', 'create.field.description.placeholder': 'Describe in detail what you need...', 'create.field.location.placeholder': 'e.g. Athens, Kolonaki', 'create.field.budget.placeholder': 'e.g. 100', 'create.submit': 'Post task', 'create.submitting': 'Posting...', 'login.title': 'Welcome back', 'login.subtitle': 'Sign in to CanHelp', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.submitting': 'Signing in...', 'login.error': 'Invalid email or password', 'login.unverified.title': 'Verify your email address', 'login.unverified.desc': 'We sent a verification link to your email. Check your inbox (or spam) and click the link.', 'login.unverified.resend': 'Resend verification email', 'login.unverified.sending': 'Sending...', 'login.unverified.sent': '✓ Sent — check your inbox', 'profile.email.verified': 'Email verified', 'profile.email.not_verified': 'Email not verified', 'login.no_account': "Don't have an account?", 'login.register_link': 'Register', 'login.forgot_password': 'Forgot password?', 'login.or_continue_with': 'or continue with', 'login.continue_google': 'Continue with Google', 'forgot.title': 'Forgot password', 'forgot.subtitle': 'Enter your email to receive a reset link', 'forgot.email': 'Email', 'forgot.submit': 'Send reset link', 'forgot.submitting': 'Sending...', 'forgot.sent.title': 'Check your inbox', 'forgot.sent.desc': 'If an account exists with that email, we\'ll send you a password reset link.', 'forgot.back_to_login': 'Back to sign in', 'forgot.error': 'Could not send reset link. Check the email address and try again.', 'forgot.error.not_found': 'No account found with this email address.', 'forgot.error.send_failed': 'Failed to send email. Please try again later.', 'reset.title': 'New password', 'reset.subtitle': 'Enter your new password', 'reset.password': 'New password', 'reset.confirm': 'Confirm password', 'reset.submit': 'Change password', 'reset.submitting': 'Saving...', 'reset.success': 'Password changed successfully. Redirecting to sign in...', 'reset.back_to_login': 'Back to sign in', 'reset.error.mismatch': 'Passwords do not match', 'reset.error.invalid': 'Invalid or expired link. Please request a new one.', 'register.title': 'Register', 'register.subtitle': 'Create a CanHelp account', 'register.first_name': 'First name', 'register.last_name': 'Last name', 'register.email': 'Email', 'register.password': 'Password (min 8 characters)', 'register.role': 'Role', 'register.role.customer': 'User', 'register.role.customer.desc': 'I post tasks', 'register.role.specialist': 'Specialist', 'register.role.specialist.desc': 'I take on tasks', 'register.submit': 'Create account', 'register.submitting': 'Registering...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Sign in', 'register.continue_google': 'Continue with Google', 'register.check_email.title': 'Check your email', 'register.check_email.desc': 'We sent a verification link to your email address. Check your inbox (or spam) and click the link.', 'register.check_email.login': 'Back to sign in', 'dashboard.title': 'Dashboard', 'dashboard.new_task': '+ New task', 'dashboard.my_tasks': 'My tasks', 'dashboard.my_offers': 'My offers', 'dashboard.invitations': 'Job invitations', 'dashboard.offers_count': 'offers', 'dashboard.declined_count': 'declined', 'dashboard.completed_tasks': 'Completed tasks', 'dashboard.completed_offers': 'Completed offers', 'dashboard.review_pending': 'Review not yet submitted', 'tasks.new.top_specialists': 'Top specialists', 'tasks.new.select_category': 'Select a category to see matching specialists', 'tasks.new.invite': 'Offer work', 'tasks.new.invited': 'Selected ✓', 'reviews.count': 'reviews', 'filter.location': 'Location', 'filter.language': 'Languages', 'filter.language.any': 'Any language', 'filter.category.all': 'All categories', 'user.categories': 'Categories', 'user.work_area': 'Work area', 'dashboard.tasks.empty': "You haven't posted any tasks", 'dashboard.tasks.empty.cta': 'Post your first one', 'dashboard.tasks.add_new': 'Add a new task', 'dashboard.offers.empty': "You haven't submitted any offers", 'dashboard.offers.empty.cta': 'Find tasks', 'dashboard.customer.specialists_title': 'Looking for a specialist?', 'dashboard.customer.specialists_hint': 'Browse specialist profiles, read reviews and invite them to your tasks', 'dashboard.customer.specialists_cta': 'Find a specialist', 'dashboard.customer.how_title': 'How it works', 'dashboard.customer.step1': 'Create a task with a description and budget', 'dashboard.customer.step2': 'Specialists will send offers with price and timeline', 'dashboard.customer.step3': 'Choose the right one and start working', 'notif.title': 'Notifications', 'notif.mark_all': 'Mark all as read', 'notif.empty': 'No notifications', 'notif.type.new_offer': 'New offer', 'notif.type.offer_accepted': 'Your offer was accepted', 'notif.type.offer_declined': 'Your offer was declined', 'notif.type.task_completed': 'Task completed', 'notif.type.task_cancelled': 'Task cancelled', 'notif.type.new_message': 'New message', 'notif.type.new_review': 'New review', 'notif.type.task_invite': 'Job invitation', 'notif.body.new_offer': 'New offer for «{title}»', 'notif.body.offer_accepted': 'Your offer for «{title}» was accepted', 'notif.body.offer_declined': 'Your offer for «{title}» was declined', 'notif.body.task_invite': 'You\'ve been invited for «{title}»', 'notif.body.new_review': 'You received a {rating}★ review', 'offer.status.pending': 'Pending', 'offer.status.accepted': 'Accepted', 'offer.status.declined': 'Declined', 'offer.status.withdrawn': 'Withdrawn', 'offer.status.other_accepted': 'Another specialist was chosen', 'common.loading': 'Loading...', 'common.error': 'Error', 'common.save': 'Save', 'common.saving': 'Saving...', 'common.cancel': 'Cancel', 'common.add': 'Add', 'common.close': 'Close', 'common.edit': 'Edit', 'common.delete': 'Delete', 'common.from': 'by', 'common.currency': '€', 'common.greece': 'Greece', // Chat 'chat.connected': 'Connected', 'chat.disconnected': 'Disconnected', 'chat.no_rooms': 'No conversations yet', 'chat.task_fallback': 'Task', 'chat.select': 'Select a conversation', 'chat.no_messages': 'No messages yet', 'chat.placeholder': 'Write a message... (Enter to send)', 'chat.conversation_fallback': 'Conversation', 'chat.direct_chat': 'Direct chat', 'chat.linked_task': 'Linked task', 'chat.write_btn': 'Message', 'chat.just_now': 'just now', 'chat.min_ago': 'm', 'chat.write_specialist': 'Write to specialist', 'chat.write_customer': 'Write to customer', 'chat.notif_settings': 'Notification settings', 'chat.notif_messages': 'Notifications for new messages', 'chat.toast_title': 'New message', 'chat.toast_open': 'Open chat', // Offer form 'offer.price': 'Price', 'offer.price.placeholder': 'e.g. 80', 'offer.customer_budget': 'Client budget', 'offer.message': 'Message', 'offer.optional': 'optional', 'offer.message.placeholder': 'Introduce yourself, your experience and why you are the best choice...', 'offer.submitting': 'Sending...', // Profile 'profile.photo': 'Profile photo', 'profile.photo.change': 'Change photo', 'profile.photo.hint': 'JPEG, PNG, WebP · up to 5MB', 'profile.basic_info': 'Basic info', 'profile.phone': 'Phone', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Short bio', 'profile.bio.placeholder': 'Tell us a bit about yourself...', 'profile.language': 'Language', 'profile.language.hint': 'App interface and email notification language', 'profile.languages': 'Languages spoken', 'profile.languages.hint': 'Select all languages you speak', 'profile.skills': 'Skills', 'profile.skills.subtitle': 'Add the services you offer', 'profile.skills.placeholder': 'e.g. Cleaning, IT, Tutoring...', 'profile.role': 'Account role', 'profile.role.specialist': '🔧 Specialist', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 User', 'profile.role.change': 'To change your role please contact support.', 'profile.become_specialist': 'Become a Specialist', 'profile.become_specialist.desc': 'Upgrade to Specialist to take on tasks and build your profile.', 'become_specialist.hero.title': 'Earn money doing what you do best', 'become_specialist.hero.subtitle': 'Create a specialist profile and receive orders from clients across Greece', 'become_specialist.how.title': 'How it works', 'become_specialist.step1.title': 'Create a specialist portfolio', 'become_specialist.step1.desc': 'Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks', 'become_specialist.step2.title': 'Find tasks', 'become_specialist.step2.desc': 'Discover tasks in your categories in the "Find Orders" section', 'become_specialist.step3.title': 'Send an offer & earn', 'become_specialist.step3.desc': 'Submit offers with price and timeline, chat with clients and complete tasks', 'become_specialist.benefits.title': 'Specialist profile advantages', 'become_specialist.benefit1': 'Task search filtered by your categories and location', 'become_specialist.benefit2': 'Public profile with client reviews', 'become_specialist.benefit3': 'Availability schedule visible to clients', 'become_specialist.benefit4': 'Saved to favourites by clients', 'become_specialist.cta': 'Learn more', 'become_specialist.free_badge': 'Free registration', 'profile.tab.notifications': 'Notifications', 'profile.tab.reviews': 'Reviews', 'profile.tab.referral': 'Referrals', 'profile.tab.auto_response': 'Auto-response', 'profile.tab.site': 'Site', 'profile.site.title': 'Personal page', 'profile.site.url_label': 'Personal site', 'profile.site.copy': 'Copy', 'profile.site.copied': 'Copied', 'profile.site.visible_title': "What's on your page", 'profile.site.visible.name': 'Name and photo', 'profile.site.visible.bio': 'Bio', 'profile.site.visible.rating': 'Rating and reviews', 'profile.site.visible.portfolio': 'Portfolio / Cards', 'profile.site.visible.contacts': 'Contact info', 'profile.site.visible.full_last_name': 'Full last name', 'profile.site.visible.services': 'Service cards', 'profile.site.visible.reviews': 'Reviews section', 'profile.site.visible.status': '"Ready to help" status', 'profile.site.theme': 'Appearance theme', 'profile.site.theme.dark': 'Dark', 'profile.site.theme.light': 'Light', 'profile.site.slug_taken': 'This address is already taken', 'profile.site.stats.title': 'Site analytics', 'profile.site.stats.days': 'last 30 days', 'profile.site.stats.views': 'Views', 'profile.site.stats.unique': 'Unique visitors', 'profile.site.stats.messages': 'Messages', 'profile.site.stats.total_views': 'Total views', 'profile.site.stats.total_unique': 'Unique visitors', 'profile.site.stats.total_messages': 'Messages', 'profile.site.stats.empty': 'No data yet', 'profile.site.stats.loading': 'Loading analytics...', 'profile.site.stats.no_slug': 'Set your site URL to see analytics', 'profile.site.edit_bio_hint': 'Bio and photo are edited in the "Basic info" tab.', 'status.title': 'Status', 'status.can_help_now_hint': 'Your card is shown higher in search', 'status.need_help_hint': 'Specialists can offer you help', 'profile.referral.title': 'Referral program', 'profile.referral.desc': 'Share your link and earn rewards for every new user you invite.', 'profile.referral.link_label': 'Your referral link', 'profile.referral.copy': 'Copy', 'profile.referral.copied': 'Copied!', 'profile.referral.invited_count': 'successful referrals', 'profile.referral.no_code': 'Referral code is not available.', 'notifications.title': 'Notification settings', 'notifications.email.new_tasks': 'Email for new tasks', 'notifications.email.new_tasks.desc': 'Receive an email when a new task is posted in your categories', 'notifications.messages.desc': 'Receive a notification when a new message arrives', 'notifications.saved': 'Settings saved', 'notifications.plan_required': 'Not available in your plan', 'profile.tab.info': 'Basic info', 'profile.tab.finance': 'Finance', 'profile.tab.skills': 'Skills', 'profile.tab.categories': 'Categories', 'profile.tab.geography': 'Geography', 'profile.specialist.categories': 'Work categories', 'profile.specialist.categories.desc': 'Select the categories you work in', 'profile.specialist.geography': 'Coverage areas', 'profile.specialist.geography.desc': 'Select the cities / districts where you are active', 'profile.saving': 'Saving...', 'profile.upload.error': 'Error uploading photo', 'profile.saved': 'Saved', 'profile.tab.cards': 'Portfolio', 'profile.cards.count': 'Portfolio', 'profile.cards.add': 'Add portfolio', 'profile.cards.new_title': 'New portfolio title', 'profile.cards.placeholder': 'e.g. Plumbing', 'profile.cards.create': 'Create', 'profile.cards.cancel': 'Cancel', 'profile.cards.empty': 'No portfolio yet', 'profile.cards.create_first': 'Create your first portfolio', 'profile.cards.delete_confirm': 'Delete portfolio?', 'profile.card.tab.main': 'General', 'profile.card.tab.skills': 'Skills', 'profile.card.tab.categories': 'Categories', 'profile.card.tab.geography': 'Geography', 'profile.card.tab.portfolio': 'Portfolio', 'profile.card.active': 'Active', 'profile.card.save': 'Save', 'profile.card.saved': 'Saved', 'profile.card.delete': 'Delete', 'profile.card.skill.add': 'Add skill', 'profile.card.photo.add': 'Add photo', 'profile.card.photo.uploading': 'Uploading...', 'profile.card.photo.empty': 'No photos yet', 'profile.card.item.title': 'Title', 'profile.card.item.desc': 'Description', 'profile.card.item.save': 'Save', 'profile.card.item.cancel': 'Cancel', 'profile.card.item.edit': 'Edit', 'profile.upgrade.cards_limit': 'Portfolio limit reached', 'profile.upgrade.plan': 'Current plan:', 'profile.upgrade.contact': 'Contact the administrator to change your plan', 'profile.upgrade.ok': 'Got it', 'profile.plan.title': 'Subscription plan', 'profile.balance': 'Balance', 'profile.balance.topup': 'Top Up Balance', 'profile.balance.topup.title': 'Top Up Balance', 'profile.balance.topup.amount': 'Amount (EUR)', 'profile.balance.topup.hint': 'Choose a preset or enter a custom amount', 'profile.balance.topup.submit': 'Proceed to Payment', 'profile.balance.topup.loading': 'Redirecting...', 'profile.balance.topup.error': 'Payment initiation failed. Please try again.', 'payment.success.title': 'Payment Successful!', 'payment.success.desc': 'Your balance has been updated.', 'payment.cancelled.title': 'Payment Cancelled', 'payment.cancelled.desc': 'Payment was cancelled. No charges were made.', 'payment.pending.title': 'Processing...', 'payment.pending.desc': 'Your payment is being processed.', 'payment.back_to_profile': 'Back to Profile', 'profile.plan.basic': 'Basic (free)', 'profile.plan.contact_upgrade': 'Contact admin to upgrade your plan', 'profile.plan.cards_up_to': 'Portfolio: up to', 'profile.plan.cards_unlimited': 'Portfolio: unlimited', 'profile.plan.tasks_up_to': 'Tasks: up to', 'profile.plan.offers_up_to': 'Offers: up to', 'profile.plan.valid_until': 'Valid until', 'profile.plan.no_expiry': 'No expiry', // Create task 'create.error': 'Error posting task', // Tasks list extras 'tasks.category.general': 'General', 'tasks.budget.range': 'Range:', 'tasks.budget.from': 'from', 'tasks.budget.to': 'to', 'tasks.filter.reset': 'Reset filters', 'tasks.load_more': 'Load more', 'tasks.showing': 'Results:', 'tasks.field.budget': 'Budget, €', // Admin 'admin.title': 'Admin Panel', 'admin.tab.stats': 'Statistics', 'admin.tab.users': 'Users', 'admin.tab.tasks': 'Tasks', 'admin.tab.reports': 'Reports', 'admin.stats.users': 'Users', 'admin.stats.tasks': 'Tasks', 'admin.stats.offers': 'Offers', 'admin.stats.reviews': 'Reviews', 'admin.tasks.by_status': 'Tasks by status', 'admin.col.user': 'User', 'admin.col.email': 'Email', 'admin.col.role': 'Role', 'admin.col.registered': 'Registered', 'admin.col.status': 'Status', 'admin.col.title': 'Title', 'admin.col.budget': 'Budget', 'admin.col.created': 'Created', 'admin.users.active': 'Active', 'admin.users.inactive': 'Inactive', 'admin.users.deactivate': 'Deactivate', 'admin.users.activate': 'Activate', 'admin.tasks.cancel': 'Cancel', 'admin.reports.none': 'No reports', 'admin.reports.reviewed': 'Reviewed', 'admin.reports.dismiss': 'Dismiss', 'admin.pagination.total': 'Total', 'admin.users.role.change': 'Change role', 'admin.users.search.placeholder': 'Search name or email...', 'admin.tasks.delete': 'Delete', 'admin.tasks.delete.confirm': 'Permanently delete this task?', 'admin.tasks.search.placeholder': 'Search title...', 'admin.col.customer': 'Customer', 'admin.col.reporter': 'Reporter', 'admin.col.target': 'Target', 'admin.filter.all_roles': 'All roles', 'admin.filter.all_statuses': 'All statuses', 'admin.reports.target.task': 'Task', 'admin.reports.target.user': 'User', 'admin.tab.categories': 'Categories', 'admin.tab.locations': 'Cities & Districts', 'admin.tab.logs': 'Logs', 'admin.tab.plans': 'Plans', 'admin.tab.settings': 'Settings', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Activity', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Notifications', 'admin.notif_logs.type': 'Type', 'admin.notif_logs.title': 'Title', 'admin.notif_logs.read': 'Read', 'admin.notif_logs.empty': 'No notification logs', 'admin.stats.notif_chart_title': 'Notifications per day', 'admin.stats.notif_label': 'Notifications', 'admin.stats.mail_chart_title': 'Emails per day', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'All', 'admin.stats.specialists': 'Specialists', 'admin.col.plan': 'Plan', 'admin.back_home': 'Home', 'admin.plans.title': 'Subscription plans', 'admin.plans.add': '+ New plan', 'admin.plans.empty': 'No plans created', 'admin.plans.form.new': 'New plan', 'admin.plans.form.edit': 'Edit plan', 'admin.plans.form.name': 'Name', 'admin.plans.form.price': 'Price (EUR)', 'admin.plans.form.old_price': 'Old price (EUR, optional)', 'admin.plans.form.max_offers': 'Max offers (empty = no limit)', 'admin.plans.form.max_cards': 'Max portfolio (empty = no limit)', 'admin.plans.form.duration_days': 'Duration (days, empty = no expiry)', 'admin.plans.form.description': 'Description', 'admin.plans.form.features': 'Features (one per line)', 'admin.plans.form.notify': 'Notify about new tasks', 'admin.plans.form.default': 'Default', 'admin.plans.form.active': 'Active', 'admin.plans.form.order': 'Order', 'admin.plans.form.role': 'Role', 'admin.plans.form.tier': 'Tier', 'admin.plans.form.role.customer': 'Customer', 'admin.plans.form.role.specialist': 'Specialist', 'admin.plans.form.tier.free': 'Free', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Limits (empty = unlimited)', 'admin.plans.form.max_messages_day': 'Max Messages/Day', 'admin.plans.form.max_orders_day': 'Max Orders/Day', 'admin.plans.form.max_skills': 'Max Skills', 'admin.plans.form.max_profiles': 'Max Profiles', 'admin.plans.form.max_portfolio': 'Max Portfolio Items', 'admin.plans.form.section.boost': 'Multipliers & Boost', 'admin.plans.form.search_boost': 'Search Boost', 'admin.plans.form.offers_multiplier': 'Offers Multiplier', 'admin.plans.form.section.contact': 'Contact Permissions', 'admin.plans.form.can_contact_free': 'Contact Free Plan users', 'admin.plans.form.can_contact_pro': 'Contact Pro Plan users', 'admin.plans.form.can_contact_all': 'Contact All users', 'admin.plans.form.can_show_contact': 'Show Contact Info', 'admin.plans.form.can_view_phone': 'View Phone', 'admin.plans.form.section.features': 'Feature Flags', 'admin.plans.form.upload_video': 'Upload Video', 'admin.plans.form.favorites': 'Favorites', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Verified Badge', 'admin.plans.form.highlighted_reviews': 'Highlighted Reviews', 'admin.plans.form.personal_site': 'Personal Site', 'admin.plans.form.can_help_now': 'Can Help Now Status', 'admin.plans.form.need_help': 'Need Help Status', 'admin.plans.form.auto_response': 'Auto Response', 'admin.plans.form.auto_match': 'Auto Match', 'admin.plans.form.instant_dispatch_free': 'Instant Dispatch (Free)', 'admin.plans.form.instant_dispatch_pro': 'Instant Dispatch (Pro)', 'admin.plans.badge.default': 'Default', 'admin.plans.badge.inactive': 'Inactive', 'admin.plans.make_default': 'Set as default', 'admin.plans.tasks': 'Tasks', 'admin.plans.offers': 'Offers', 'admin.plans.cards': 'Portfolio', 'admin.plans.notify_tasks': 'Task notifications', 'admin.plans.delete.confirm': 'Delete plan', 'admin.activity.title': 'Activity log', 'admin.activity.event': 'Event', 'admin.activity.all_events': 'All events', 'admin.activity.from': 'From', 'admin.activity.to': 'To', 'admin.activity.reset': 'Reset', 'admin.activity.total': 'Total', 'admin.activity.empty': 'No records', 'admin.mail.event': 'Email event', 'admin.mail.all_events': 'All email events', 'admin.mail.from': 'From', 'admin.mail.to': 'To', 'admin.mail.reset': 'Reset', 'admin.mail.total': 'Total', 'admin.mail.empty': 'No email logs', 'admin.mail.recipient': 'Recipient', 'admin.mail.provider': 'Provider', 'admin.mail.details': 'Details', 'admin.mail.status': 'Status', 'admin.mail.success': 'Success', 'admin.mail.failed': 'Failed', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'No records', 'admin.logs.date': 'Date', 'admin.logs.provider': 'Provider', 'admin.logs.model': 'Model', 'admin.logs.action': 'Action', 'admin.logs.langs': 'Languages', 'admin.logs.in': 'In', 'admin.logs.out': 'Out', 'admin.logs.total': 'Total', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Status', 'admin.stats.activity_30d': 'Activity over 30 days', 'admin.stats.tasks_label': 'Tasks', 'admin.stats.users_label': 'Users', 'admin.stats.specialists_label': 'Specialists', 'admin.stats.tokens_title': 'Token usage (by month)', 'admin.stats.tokens_out': 'Output', 'admin.stats.tokens_in': 'Input', 'admin.stats.tokens_out_label': 'Output tokens', 'admin.stats.tokens_in_label': 'Input tokens', 'admin.stats.cost_label': 'Cost (USD)', 'admin.stats.tasks_by_status': 'Tasks by status', 'admin.task_status.open': 'Open', 'admin.task_status.in_progress': 'In progress', 'admin.task_status.completed': 'Completed', 'admin.task_status.cancelled': 'Cancelled', 'admin.task_status.draft': 'Drafts', 'admin.settings.tab.general': 'General', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Notifications', 'admin.settings.tab.payment': 'Payment', 'admin.settings.tab.referral': 'Referrals', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Socials', 'admin.settings.socials.title': 'Social Network Links', 'admin.settings.socials.hint': 'Filled links are displayed in the site footer', 'admin.settings.seo.maintenance_label': 'Maintenance Mode', 'admin.settings.seo.maintenance_hint': 'Show a maintenance page to all visitors', 'admin.settings.seo.indexing_label': 'Search Engine Indexing', 'admin.settings.seo.indexing_hint': 'Allow search engines to index the site', 'admin.settings.seo.head_scripts_label': ' Scripts (JS)', 'admin.settings.seo.head_scripts_hint': 'Runs on every page (Google Tag Manager, analytics, etc.)', 'admin.settings.seo.site_title_label': 'Site Title', 'admin.settings.seo.site_description_label': 'Site Description (meta description)', 'admin.settings.referral.title': 'Referral program', 'admin.settings.referral.hint': 'Reward users who bring new registrations.', 'admin.settings.referral.enabled_label': 'Enabled', 'admin.settings.referral.enabled_hint': 'Enable / disable reward application', 'admin.settings.referral.customer_section': 'For customers', 'admin.settings.referral.specialist_section': 'For specialists', 'admin.settings.referral.plan_label': 'Reward plan', 'admin.settings.referral.no_plan': '— no plan —', 'admin.settings.referral.plan_hint': 'This plan will be assigned to the referrer. If their current plan is higher, only days will be added.', 'admin.settings.referral.days_label': 'Reward days', 'admin.settings.referral.days_hint': 'Number of days added to the plan expiry.', 'admin.settings.general.title': 'General settings', 'admin.settings.general.site_name': 'Site name', 'admin.settings.general.site_url': 'Site URL', 'admin.settings.general.contact_email': 'Contact email', 'admin.settings.general.support_phone': 'Support phone', 'admin.settings.smtp.title': 'SMTP settings', 'admin.settings.smtp.hint': 'Used to send email notifications.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Port', 'admin.settings.smtp.encryption': 'Encryption', 'admin.settings.smtp.enc.none': 'None', 'admin.settings.smtp.enc.tls': 'STARTTLS (port 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (port 465)', 'admin.settings.smtp.username': 'Username', 'admin.settings.smtp.password': 'Password / App Password', 'admin.settings.smtp.from_name': 'Sender name', 'admin.settings.smtp.from_email': 'Sender email', 'admin.settings.smtp.test': 'Send test email', 'admin.settings.smtp.sending': 'Sending...', 'admin.settings.payment.hint': 'ePay Piraeus Bank credentials.', 'admin.settings.env.test': 'Test (sandbox)', 'admin.settings.env.prod': 'Production', 'admin.settings.env.label': 'Environment', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Active', 'admin.settings.saving': 'Saving...', 'admin.settings.saved': 'Saved', 'admin.notif.vars_hint': 'Available variables in templates', 'admin.notif.tmpl.not_set': 'Template not configured', 'admin.notif.tmpl.subject_label': 'Email subject', 'admin.notif.tmpl.body_label': 'Email body (HTML)', 'admin.notif.tmpl.save': 'Save', 'admin.notif.tmpl.close': 'Close', 'admin.notif.tmpl.translate': 'Auto-translate to other languages', 'admin.notif.tmpl.translating': 'Translating...', 'admin.notif.tmpl.saving': 'Saving...', 'admin.notif.email_verification': 'Email verification', 'admin.notif.registration_success': 'Successful registration', 'admin.notif.password_reset': 'Password reset', 'admin.notif.new_offer': 'New offer', 'admin.notif.new_task': 'New task', 'admin.notif.offer_accepted': 'Offer accepted', 'admin.notif.new_message': 'New message', 'admin.notif.offer_declined': 'Offer declined', 'admin.notif.offer_other_accepted': 'Another specialist chosen', 'admin.notif.task_updated': 'Task updated', 'admin.notif.deadline_reminder': 'Deadline reminder', 'admin.notif.task_archived': 'Task unpublished automatically', 'admin.notif.referral_reward': 'Referral reward', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Plan activated', 'admin.email_template.plan_upgraded': 'Plan upgraded', 'admin.email_template.plan_downgrade_scheduled': 'Downgrade scheduled', 'admin.email_template.plan_downgrade_applied': 'Downgrade applied', 'admin.email_template.plan_renewal_reminder': 'Renewal reminder', 'admin.email_template.plan_insufficient_funds': 'Insufficient funds warning', // Pricing confirm modal 'pricing.confirm.title': 'Confirm plan selection', 'pricing.confirm.plan': 'Plan', 'pricing.confirm.prorated': 'Prorated credit', 'pricing.confirm.effective_price': 'Amount due', 'pricing.confirm.your_balance': 'Your balance', 'pricing.confirm.downgrade_info': 'The switch to the new plan will happen automatically after the current period ends.', 'pricing.confirm.insufficient': 'Insufficient balance.', 'pricing.confirm.top_up': 'Top up', 'pricing.confirm.schedule_downgrade': 'Schedule downgrade', 'pricing.confirm.pay': 'Pay', 'admin.user_edit.title': 'Edit user', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email verified', 'admin.user_edit.email_not_verified': 'Email not verified', 'admin.user_edit.verify_email_btn': 'Verify manually', 'admin.user_edit.verify_email_done': 'Email verified!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Registered', 'admin.user_edit.last_seen': 'Last seen', 'admin.user_edit.lang': 'Language', 'admin.user_edit.first_name': 'First name', 'admin.user_edit.last_name': 'Last name', 'admin.user_edit.phone': 'Phone', 'admin.user_edit.bio': 'Bio', 'admin.user_edit.role': 'Role', 'admin.user_edit.plan': 'Plan', 'admin.user_edit.no_plan': '— No plan —', 'admin.user_edit.active': 'Active account', 'admin.user_edit.balance': 'Balance (EUR)', 'admin.user_edit.skills': 'Skills', 'admin.user_edit.tab.profile': 'Profile', 'admin.user_edit.tab.account': 'Account', 'admin.user_edit.tab.balance': 'Balance', 'admin.user_edit.tab.settings': 'Settings', 'admin.user_edit.tab.specialist': 'Portfolio', 'admin.user_edit.tab.site': 'Website', 'admin.user_edit.plan_expires': 'Plan expires', 'admin.user_edit.interface_lang': 'Interface language', 'admin.user_edit.comm_languages': 'Communication languages', 'admin.user_edit.personal_site_slug': 'Personal page', 'admin.user_edit.show_contact_info': 'Show contact info', 'admin.user_edit.show_contact_info.hint': 'Visible to customers', 'admin.user_edit.notify_new_tasks': 'Notify about new tasks', 'admin.user_edit.notify_new_tasks.hint': 'Push and email notifications', 'admin.user_edit.notif_messages': 'Message notifications', 'admin.user_edit.notif_messages.hint': 'New messages in chat', 'admin.user_edit.site_settings': 'Personal page settings', 'admin.user_edit.categories': 'Service categories', 'admin.user_edit.locations': 'Service areas', 'admin.user_edit.skill_placeholder': 'New skill...', 'admin.user_edit.add_category': '— Select category —', 'admin.user_edit.add_location': '— Select location —', 'admin.user_edit.specialist_cards': 'Portfolio', 'admin.user_edit.no_cards': 'No portfolio found', 'admin.user_edit.card_title': 'Portfolio title', 'admin.user_edit.card_description': 'Description', 'admin.balance.topup.btn': 'Top up', 'admin.balance.withdraw.btn': 'Withdraw', 'admin.balance.modal_hint': 'Changes take effect immediately and are recorded in history', 'admin.balance.topup.title': 'Top up balance', 'admin.balance.topup.amount': 'Amount', 'admin.balance.topup.description': 'Comment', 'admin.balance.topup.description.placeholder': 'For example: bonus or manual top-up', 'admin.balance.topup.submit': 'Top up balance', 'admin.balance.withdraw.title': 'Withdraw balance', 'admin.balance.withdraw.amount': 'Amount', 'admin.balance.withdraw.description': 'Comment', 'admin.balance.withdraw.description.placeholder': 'For example: refund or manual debit', 'admin.balance.withdraw.submit': 'Withdraw from balance', 'admin.user_edit.role.customer': 'Customer', 'admin.user_edit.role.specialist': 'Specialist', 'admin.user_edit.role.admin': 'Administrator', 'common.refresh': 'Refresh', 'common.back_home': 'Home', 'admin.loc.hint': 'Manage cities and districts', 'admin.loc.add_city': 'New city', 'admin.loc.add_district': 'Add district', 'admin.loc.new': 'New location', 'admin.loc.edit': 'Edit location', 'admin.loc.district': 'district', 'admin.loc.empty': 'No locations', 'admin.loc.delete.confirm': 'Delete location? All districts will also be deleted.', 'admin.cat.add_root': 'New category', 'admin.cat.add_sub': 'Subcategory', 'admin.cat.edit': 'Edit', 'admin.cat.delete': 'Delete', 'admin.cat.delete.confirm': 'Delete category? All subcategories will also be deleted.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Icon', 'admin.cat.name_el': 'Greek', 'admin.cat.name_en': 'English', 'admin.cat.name_ru': 'Russian', 'admin.cat.order': 'Order', 'admin.cat.active': 'Active', 'admin.cat.parent': 'Parent category', 'admin.cat.no_parent': 'Top level', 'admin.cat.save': 'Save', 'admin.cat.cancel': 'Cancel', 'admin.cat.empty': 'No categories', 'admin.cat.hint': 'Manage categories with multi-level hierarchy', 'admin.cat.new': 'New category', 'admin.cat.subcategory': 'subcategory', 'admin.cat.add_child': 'Add subcategory', 'admin.cat.inactive': 'Inactive', 'admin.event.user_login': 'Login', 'admin.event.user_register': 'Registration', 'admin.event.admin_user_deactivate': 'User blocked', 'admin.event.admin_user_activate': 'User activated', 'admin.event.admin_user_role_changed': 'Role changed', 'admin.event.admin_task_cancelled': 'Task cancelled', 'admin.event.admin_task_deleted': 'Task deleted', 'admin.event.admin_report_reviewed': 'Report reviewed', 'admin.event.admin_report_dismissed': 'Report dismissed', 'admin.event.task_created': 'Task created', // User status 'user.online': 'Online', 'user.seen_minutes': 'was here {n} min ago', 'user.seen_hours': 'was here {n} hr ago', 'user.seen_yesterday': 'was here yesterday', 'user.seen_days': 'was here {n} days ago', // Specialists 'specialists.title': 'Specialists', 'specialists.search': 'Search specialist...', 'specialists.search.btn': 'Search', 'specialists.empty': 'No specialists found', 'specialists.no_bio': 'No description', 'specialists.view': 'View profile', 'specialists.reviews': 'reviews', 'specialist.favorite': 'Add to favorites', 'specialist.unfavorite': 'Remove from favorites', 'specialist.site_link': 'Personal site', 'favorites.specialists.title': 'Favourite specialists', 'favorites.specialists.empty': 'No favourite specialists yet', 'nav.favorites': 'Favourites', 'nav.schedule': 'Schedule', 'nav.find_tasks': 'Find Orders', 'schedule.title': 'My Schedule', 'schedule.subtitle': 'Mark the days when you are free or busy — clients will see your availability', 'schedule.available': 'Available', 'schedule.busy': 'Busy', 'schedule.unset': 'Not set', 'schedule.click_hint': '← click to cycle status', 'schedule.range_mode': 'Select range', 'schedule.range_from': 'From {date} — select end date', 'schedule.click_to_set': 'Click to set', 'schedule.free': 'free', 'schedule.busy_count': 'busy', 'schedule.free_days': 'free days', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Connect Google Calendar', 'schedule.disconnectGoogle': 'Disconnect', 'schedule.connectedAs': 'Connected as', 'schedule.importFromGoogle': 'Sync from Google', 'schedule.gcalConnected': '\u2713 Google Calendar connected', 'schedule.gcalError': 'Google Calendar connection error', 'schedule.gcalImportDone': 'Imported {n} days from Google Calendar', 'schedule.gcalAutoSyncNote': 'Availability changes are automatically synced to Google Calendar', 'schedule.gcalConnectDesc': 'Connect Google Calendar to automatically sync your availability', 'schedule.gcalDisconnectConfirm': 'Disconnect Google Calendar?', 'find_tasks.title': 'Find Orders', 'find_tasks.for_me': 'For me', 'find_tasks.all': 'All orders', 'find_tasks.by_category': 'By category', 'find_tasks.list': 'List', 'find_tasks.already_offered': 'Offer sent', 'find_tasks.offer_now': 'Make an offer', 'find_tasks.empty_for_me': 'No tasks found in your categories', 'find_tasks.banner_hint': 'Find tasks matching your portfolio categories', 'find_tasks.no_cards': 'Create a specialist portfolio to see tasks matched to you', 'find_tasks.add_card': 'Create portfolio', 'find_tasks.search': 'Search tasks...', 'find_tasks.tasks_count': 'tasks', 'footer.tagline': 'The task platform for Greece', 'footer.rights': 'All rights reserved.', // App download section 'app.download_title': 'Download the CanHelp mobile app', 'app.download_desc': 'All of CanHelp — always at your fingertips. Available for Android and iOS.', // Nav 'nav.pricing': 'Pricing', // Pricing page 'pricing.title': 'Pricing', 'pricing.subtitle': 'Choose the right plan for you', 'pricing.role.customer': 'Customer', 'pricing.role.specialist': 'Specialist', 'pricing.free': 'Free', 'pricing.per_month': 'mo', 'pricing.duration': 'Duration', 'pricing.days': 'days', 'pricing.current_plan': 'Your plan', 'pricing.popular': 'Popular', 'pricing.choose': 'Choose', 'pricing.your_plan': 'Active plan', 'pricing.free_default': 'Default', 'pricing.compare': 'Compare features', 'pricing.feature': 'Feature', 'pricing.faq_note': 'Payment is deducted from your CanHelp balance. Top up available in Payments.', 'pricing.feat.messages': 'Messages / day', 'pricing.feat.orders': 'Orders / day', 'pricing.feat.contact_all': 'Contact everyone', 'pricing.feat.view_phone': 'View phone number', 'pricing.feat.show_contact': 'Show contact info', 'pricing.feat.favorites': 'Favorites', 'pricing.feat.verified_badge': 'Verified badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Personal site', 'pricing.feat.auto_response': 'Auto-response', 'pricing.feat.auto_match': 'Auto-match', 'pricing.feat.highlighted_reviews': 'Highlighted reviews', 'pricing.feat.portfolio': 'Portfolio items', 'pricing.feat.cards': 'Specialist cards', 'pricing.feat.notify_tasks': 'New task notifications', 'pricing.feat.video': 'Video in portfolio', // Upgrade prompt 'upgrade.available_in': 'Available in', 'upgrade.cta': 'Upgrade', // Dashboard plan block 'dashboard.plan.title': 'My Plan', 'dashboard.plan.expires': 'Expires in {n} days', 'dashboard.plan.upgrade': 'Upgrade plan', 'dashboard.plan.no_plan': 'Free plan', 'dashboard.plan.messages': 'Messages today', 'dashboard.plan.orders': 'Orders today', 'dashboard.plan.limits': 'Daily limits', 'dashboard.plan.features': 'Features', 'dashboard.plan.stats': 'Stats', 'dashboard.stats.cards': 'Portfolios', 'dashboard.stats.maxCards': 'Max portfolios', 'dashboard.stats.portfolioItems': 'Portfolio items', 'dashboard.stats.maxPortfolioItems': 'Max items', 'dashboard.stats.activeOffers': 'Active offers', 'dashboard.stats.reviewsReceived': 'Reviews', 'dashboard.stats.activeTasks': 'Active tasks', 'dashboard.stats.completedTasks': 'Completed', 'status.need_help': 'I need help', 'status.active': 'Active', 'status.toggle_on': 'Enable', 'status.toggle_off': 'Disable', // FOMO 'fomo.missed_orders': 'Missed {n} orders', 'fomo.missed_value': 'Worth €{v}', 'fomo.upgrade_hint': 'Upgrade to receive more orders', 'fomo.conversion': 'Task conversion', 'fomo.active': 'Active', 'fomo.with_offers': 'With offers', 'fomo.completed': 'Completed', 'fomo.already_offered': '{n} specialists have already responded', 'fomo.specialist_missed': 'You missed {n} orders', 'fomo.top_categories': 'Categories', 'fomo.offers_received': 'offers received', 'fomo.avg_offers': 'Avg {n}/task', 'fomo.completion_rate': 'completed', // Task auto-match 'task.auto_match': 'Auto-match', 'task.auto_match_results': 'Top specialists', 'task.no_offer_yet': 'You haven\'t sent an offer yet', 'task.make_offer': 'Send offer', 'auto_response.title': 'Auto-Response', 'auto_response.enabled': 'Enable auto-response', 'auto_response.min_budget': 'Min budget', 'auto_response.max_budget': 'Max budget', 'auto_response.default_price': 'Default price', 'auto_response.default_message': 'Default message', 'auto_response.max_per_day': 'Max auto-offers per day', 'auto_response.save': 'Save', 'auto_response.saved': 'Saved', 'auto_response.categories': 'Categories', 'auto_response.locations': 'Locations', // Personal site 'profile.personal_site': 'Personal Site', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Only latin letters, numbers, - and _', 'profile.site_open': 'Open site', 'profile.site_preview': 'Your site', 'profile.show_contact': 'Show contact info', 'profile.show_contact_hint': 'Customers with Pro/Ultimate plans will see your phone number', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Calendar requires a Pro or Ultimate plan', // Chat limits 'chat.limit_warning': '{n} messages left today', 'chat.limit_reached': 'Message limit reached. Upgrade your plan', 'chat.upgrade': 'Upgrade', // Site page 'site.member_since': 'Member since', 'site.rating': 'Rating', 'site.completed_tasks': 'Completed', 'site.languages': 'Languages', 'site.photos': 'photos', 'site.contact_form': 'Get in touch', 'site.contact_sent': 'Message sent!', 'site.contact_sent_desc': 'The specialist will contact you soon', 'site.contact_name': 'Name', 'site.contact_name_ph': 'Your name', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Message', 'site.contact_message_ph': 'Describe your task...', 'site.contact_send': 'Send', 'site.share': 'Share', 'site.speaks_languages': 'Speaks', 'site.message_sent': 'Message sent!', 'site.message_sent_desc': 'The specialist will receive it in the chat', 'site.message_placeholder': 'Write your message...', 'site.write_to_chat': 'Write to chat', 'site.auth_required_title': 'Sign in required', 'site.auth_required_desc': 'To write in the chat, you need to sign in to your CanHelp account.', 'site.auth_login_btn': 'Sign in', 'site.auth_contact_form_btn': 'Contact via feedback form', 'specialist.services': 'Services', 'portfolio.title': 'Portfolio', 'status.can_help_now': 'Available now', 'common.not_found': 'Page not found', 'common.anonymous': 'Anonymous', 'specialist_setup.page_title': 'Specialist profile setup', 'specialist_setup.step_of': 'Step {current} of {total}', 'specialist_setup.next': 'Next', 'specialist_setup.back': 'Back', 'specialist_setup.skip': 'Skip', 'specialist_setup.finish': 'Finish', 'specialist_setup.go_to_profile': 'Go to profile', 'specialist_setup.browse_tasks': 'Browse tasks', 'specialist_setup.step1.title': 'Welcome!', 'specialist_setup.step1.subtitle': "Let's set up your profile", 'specialist_setup.step1.desc': 'A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.', 'specialist_setup.step1.what_next': 'What we will do:', 'specialist_setup.step1.item1': 'Fill in basic information', 'specialist_setup.step1.item2': 'Create a service card', 'specialist_setup.step1.item3': 'Add skills and categories', 'specialist_setup.step1.item4': 'Select service area', 'specialist_setup.step1.item5': 'Upload portfolio photos', 'specialist_setup.step2.title': 'Basic profile', 'specialist_setup.step2.subtitle': 'Tell us about yourself', 'specialist_setup.step2.bio_label': 'About me', 'specialist_setup.step2.bio_placeholder': 'Describe your experience, services you offer...', 'specialist_setup.step2.phone_label': 'Phone', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Profile photo', 'specialist_setup.step2.photo_btn': 'Upload photo', 'specialist_setup.step2.photo_uploading': 'Uploading...', 'specialist_setup.step2.photo_hint': 'Shown on your profile', 'specialist_setup.step3.title': 'Service card', 'specialist_setup.step3.subtitle': 'Create your first service card', 'specialist_setup.step3.title_label': 'Card title', 'specialist_setup.step3.title_placeholder': 'E.g. Plumber, Electrician, Cleaning...', 'specialist_setup.step3.desc_label': 'Description', 'specialist_setup.step3.desc_placeholder': 'Describe in detail what you offer, your experience, advantages...', 'specialist_setup.step3.title_required': 'Title is required', 'specialist_setup.step4.title': 'Skills & Categories', 'specialist_setup.step4.subtitle': 'Add skills and select categories', 'specialist_setup.step4.skills_label': 'Skills', 'specialist_setup.step4.skills_placeholder': 'E.g. Pipe installation...', 'specialist_setup.step4.skills_add': 'Add', 'specialist_setup.step4.categories_label': 'Categories', 'specialist_setup.step5.title': 'Service area', 'specialist_setup.step5.subtitle': 'Where do you provide services?', 'specialist_setup.step5.hint': 'Select cities or specific areas', 'specialist_setup.done.title': 'Your profile is ready!', 'specialist_setup.done.subtitle': 'Congratulations! Your profile has been set up', 'specialist_setup.done.desc': 'You can now receive orders from clients. Browse tasks that match your skills.' }, ru: { 'footer.slogan': 'Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.', 'footer.links': 'Ссылки', 'footer.socials': 'Мы в соцсетях', 'nav.home': 'Главная', 'nav.tasks': 'Задачи', 'nav.post': '+ Опубликовать', 'nav.dashboard': 'Панель управления', 'nav.chat': 'Сообщения', 'nav.notifications': 'Уведомления', 'nav.profile': 'Профиль', 'nav.admin': 'Админка', 'nav.specialists': 'Специалисты', 'nav.new_task': 'Новая задача', 'nav.login': 'Войти', 'nav.register': 'Регистрация', 'nav.logout': 'Выйти', 'hero.title': 'Найди специалиста для любой работы', 'hero.subtitle': 'Опубликуй задачу, получи предложения и выбери лучшего профессионала', 'hero.cta.post': 'Опубликовать задачу', 'hero.cta.browse': 'Стать специалистом', 'hero.search.placeholder': 'Что нужно? напр. электрик, уборка...', 'stats.specialists': 'специалистов', 'stats.tasks': 'задач', 'stats.categories': 'категорий', 'stats.free': 'бесплатная регистрация', 'section.categories': 'Создай задачу в любой категории', 'section.how': 'Как это работает', 'section.recent': 'Последние задачи', 'section.all': 'Смотреть все →', 'section.more': 'ещё', 'section.cities': 'Города и районы', 'section.community': 'Общественный проект для всех', 'community.subtitle': 'CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.', 'community.point1.title': 'Умеете что-то делать?', 'community.point1.desc': 'Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.', 'community.point2.title': 'Нужна помощь?', 'community.point2.desc': 'Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.', 'community.point3.title': 'Помогите проекту расти', 'community.point3.desc': 'CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.', 'community.share': 'Поделиться с друзьями', 'community.share.copied': 'Ссылка скопирована!', // Referral section on home page 'section.referral': 'Реферальная программа', 'referral.home.subtitle': 'Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.', 'referral.home.step1.title': 'Зарегистрируйтесь и получите ссылку', 'referral.home.step1.desc': 'Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.', 'referral.home.step2.title': 'Поделитесь с друзьями', 'referral.home.step2.desc': 'Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.', 'referral.home.step3.title': 'Получайте награды', 'referral.home.step3.desc': 'Как только друг подтвердит email, вы автоматически получите свою награду.', 'referral.home.cta': 'Получить ссылку', 'referral.home.badge': 'Реферальная программа', // FAQ section 'section.faq': 'Частые вопросы', 'faq.q1': 'Как работает CanHelp?', 'faq.a1': 'Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.', 'faq.q2': 'Сколько стоит использование платформы?', 'faq.a2': 'Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.', 'faq.q3': 'Как стать специалистом?', 'faq.a3': 'Зарегистрируйтесь, перейдите в «Стать специалистом», заполните профиль навыками и категориями и начните получать задачи.', 'faq.q4': 'Как выбрать подходящего специалиста?', 'faq.a4': 'Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.', 'faq.q5': 'Что если я не доволен результатом?', 'faq.a5': 'Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.', 'faq.q6': 'Можно ли связаться со специалистом до принятия предложения?', 'faq.a6': 'Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.', 'faq.q7': 'Сколько времени ждать предложений?', 'faq.a7': 'Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.', 'faq.q8': 'Можно ли разместить задачу в любом городе Греции?', 'faq.a8': 'Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.', 'faq.q9': 'Какие виды задач есть на CanHelp?', 'faq.a9': 'Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.', 'faq.q10': 'Есть ли мобильное приложение?', 'faq.a10': 'Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.', 'how.step1.title': 'Опубликуй задачу', 'how.step1.desc': 'Опиши что нужно и установи бюджет', 'how.step2.title': 'Получи предложения', 'how.step2.desc': 'Специалисты пришлют предложения с ценой и сроками', 'how.step3.title': 'Выбери и начни', 'how.step3.desc': 'Выбери лучшего профессионала и начни сотрудничество', 'tasks.title': 'задач', 'tasks.filters': 'Фильтры', 'tasks.search': 'Поиск', 'tasks.search.placeholder': 'Название или ключевое слово...', 'tasks.search.btn': 'Поиск', 'tasks.publish': 'Опубликовать', 'tasks.category.all': 'Все', 'tasks.category.all_in': 'Все в', 'tasks.category.label': 'Категория', 'tasks.location.label': 'Город', 'tasks.location.placeholder': 'напр. Афины', 'tasks.empty': 'Задачи не найдены', 'tasks.empty.cta': 'Опубликуй первую', 'task.status.open': 'Открыта', 'task.status.in_progress': 'В работе', 'task.status.completed': 'Завершена', 'task.status.cancelled': 'Отменена', 'task.status.draft': 'Черновик', 'task.budget': 'Бюджет', 'task.location': 'Местоположение', 'task.deadline': 'Дата начала', 'task.created_at': 'Создано', 'task.customer': 'Заказчик', 'task.offer.btn': 'Отправить предложение', 'task.invite.banner_title': 'Вас пригласили на это задание', 'task.invite.banner_hint': 'Заказчик лично пригласил вас', 'task.invite.accept': 'Отправить предложение', 'task.invite.decline': 'Отказаться', 'offer.accept': 'Принять', 'offer.decline': 'Отклонить', 'task.complete': 'Завершить задачу', 'task.complete.confirm': 'Отметить задачу как выполненную?', 'task.edit': 'Редактировать', 'task.status_label': 'Статус', 'task.yours': 'Ваша задача', 'task.offer.yours': 'Ваше предложение', 'review.leave': 'Оставить отзыв', 'review.rating': 'Оценка', 'review.comment': 'Комментарий', 'review.comment.placeholder': 'Расскажите о своём опыте...', 'review.submit': 'Отправить отзыв', 'review.submitting': 'Отправка...', 'review.done': 'Отзыв отправлен!', 'profile.reviews': 'Отзывы', 'profile.no_reviews': 'Отзывов пока нет', 'profile.rating': 'Рейтинг', 'profile.skills.label': 'Навыки', 'profile.member_since': 'Участник с', 'task.offers': 'Предложения', 'task.offers.none': 'Предложений пока нет', 'create.title': 'Опубликовать задачу', 'create.field.title': 'Название', 'create.field.description': 'Описание', 'create.field.category': 'Категория', 'create.field.category.select': 'Выберите...', 'create.field.location': 'Местоположение', 'create.field.location.any': 'Где угодно', 'create.field.location.all': 'Весь город', 'create.field.budget': 'Бюджет (€)', 'create.field.deadline': 'Дата начала', 'create.field.budget_negotiable': 'Цена обсуждается', 'create.field.time_slot': 'Время выполнения', 'create.field.time_slot.any': 'В любое время', 'create.field.time_slot.morning': 'Утром (08:00–13:00)', 'create.field.time_slot.afternoon': 'Днём (13:00–18:00)', 'create.field.time_slot.evening': 'Вечером (18:00–22:00)', 'create.field.time_slot.weekend': 'Выходной', 'create.field.address': 'Адрес (необязательно)', 'create.field.address.district': 'Квартал', 'create.field.address.street': 'Улица', 'create.field.address.house': 'Дом', 'create.field.confidential': 'Конфиденциальная заметка', 'create.field.confidential.placeholder': 'Детали, видные только назначенному специалисту...', 'create.field.confidential.hint': 'Не отображается публично', 'create.field.photos': 'Фотографии', 'create.field.photos.add': 'Добавить фото', 'create.field.photos.uploading': 'Загрузка...', 'task.budget_negotiable': 'Цена обсуждается', 'task.time_slot': 'Время', 'task.confidential': 'Конфид. заметка', 'create.field.title.placeholder': 'напр. Уборка квартиры 80кв', 'create.field.description.placeholder': 'Подробно опишите что нужно...', 'create.field.location.placeholder': 'напр. Афины, Колонаки', 'create.field.budget.placeholder': 'напр. 100', 'create.submit': 'Опубликовать задачу', 'create.submitting': 'Публикация...', 'login.title': 'Добро пожаловать', 'login.subtitle': 'Вход в CanHelp', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.submitting': 'Вход...', 'login.error': 'Неверный email или пароль', 'login.unverified.title': 'Подтвердите ваш email', 'login.unverified.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'login.unverified.resend': 'Отправить письмо повторно', 'login.unverified.sending': 'Отправка...', 'login.unverified.sent': '✓ Отправлено — проверьте входящие', 'profile.email.verified': 'Email подтверждён', 'profile.email.not_verified': 'Email не подтверждён', 'login.no_account': 'Нет аккаунта?', 'login.register_link': 'Зарегистрироваться', 'login.forgot_password': 'Забыл пароль?', 'login.or_continue_with': 'или продолжите через', 'login.continue_google': 'Войти через Google', 'forgot.title': 'Забыл пароль', 'forgot.subtitle': 'Введите email для получения ссылки восстановления', 'forgot.email': 'Email', 'forgot.submit': 'Отправить ссылку', 'forgot.submitting': 'Отправка...', 'forgot.sent.title': 'Проверьте входящие', 'forgot.sent.desc': 'Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.', 'forgot.back_to_login': 'Вернуться ко входу', 'forgot.error': 'Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.', 'forgot.error.not_found': 'Аккаунт с таким email не найден.', 'forgot.error.send_failed': 'Ошибка отправки письма. Попробуйте позже.', 'reset.title': 'Новый пароль', 'reset.subtitle': 'Введите новый пароль', 'reset.password': 'Новый пароль', 'reset.confirm': 'Подтвердите пароль', 'reset.submit': 'Изменить пароль', 'reset.submitting': 'Сохранение...', 'reset.success': 'Пароль успешно изменён. Перенаправление ко входу...', 'reset.back_to_login': 'Вернуться ко входу', 'reset.error.mismatch': 'Пароли не совпадают', 'reset.error.invalid': 'Недействительная или устаревшая ссылка. Запросите новую.', 'register.title': 'Регистрация', 'register.subtitle': 'Создать аккаунт в CanHelp', 'register.first_name': 'Имя', 'register.last_name': 'Фамилия', 'register.email': 'Email', 'register.password': 'Пароль (мин. 8 символов)', 'register.role': 'Роль', 'register.role.customer': 'Пользователь', 'register.role.customer.desc': 'Публикую задачи', 'register.role.specialist': 'Специалист', 'register.role.specialist.desc': 'Беру задачи', 'register.submit': 'Создать аккаунт', 'register.submitting': 'Регистрация...', 'register.has_account': 'Уже есть аккаунт?', 'register.login_link': 'Войти', 'register.continue_google': 'Зарегистрироваться через Google', 'register.check_email.title': 'Проверьте почту', 'register.check_email.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'register.check_email.login': 'Вернуться к входу', 'dashboard.title': 'Панель управления', 'dashboard.new_task': '+ Новая задача', 'dashboard.my_tasks': 'Мои задачи', 'dashboard.my_offers': 'Мои предложения', 'dashboard.invitations': 'Приглашения на задания', 'dashboard.offers_count': 'предл.', 'dashboard.declined_count': 'откл.', 'dashboard.completed_tasks': 'Завершённые задачи', 'dashboard.completed_offers': 'Завершённые предложения', 'dashboard.review_pending': 'Оценка ещё не оставлена', 'tasks.new.top_specialists': 'Топ специалисты', 'tasks.new.select_category': 'Выберите категорию, чтобы увидеть специалистов', 'tasks.new.invite': 'Предложить работу', 'tasks.new.invited': 'Выбран ✓', 'reviews.count': 'отзывов', 'filter.location': 'Локация', 'filter.language': 'Языки', 'filter.language.any': 'Любой язык', 'filter.category.all': 'Все категории', 'user.categories': 'Категории', 'user.work_area': 'Район работы', 'dashboard.tasks.empty': 'Вы не публиковали задачи', 'dashboard.tasks.empty.cta': 'Опубликуйте первую', 'dashboard.tasks.add_new': 'Добавить новую задачу', 'dashboard.offers.empty': 'Вы не отправляли предложений', 'dashboard.offers.empty.cta': 'Найти задачи', 'dashboard.customer.specialists_title': 'Ищете исполнителя?', 'dashboard.customer.specialists_hint': 'Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи', 'dashboard.customer.specialists_cta': 'Найти исполнителя', 'dashboard.customer.how_title': 'Как это работает', 'dashboard.customer.step1': 'Создайте задачу с описанием и бюджетом', 'dashboard.customer.step2': 'Специалисты пришлют предложения с ценой и сроками', 'dashboard.customer.step3': 'Выберите подходящего и начните работу', 'notif.title': 'Уведомления', 'notif.mark_all': 'Отметить все как прочитанные', 'notif.empty': 'Нет уведомлений', 'notif.type.new_offer': 'Новое предложение', 'notif.type.offer_accepted': 'Ваше предложение принято', 'notif.type.offer_declined': 'Ваше предложение отклонено', 'notif.type.task_completed': 'Задание выполнено', 'notif.type.task_cancelled': 'Задание отменено', 'notif.type.new_message': 'Новое сообщение', 'notif.type.new_review': 'Новый отзыв', 'notif.type.task_invite': 'Приглашение на задание', 'notif.body.new_offer': 'Новое предложение на «{title}»', 'notif.body.offer_accepted': 'Ваше предложение на «{title}» принято', 'notif.body.offer_declined': 'Ваше предложение на «{title}» отклонено', 'notif.body.task_invite': 'Вас приглашают на «{title}»', 'notif.body.new_review': 'Вы получили оценку {rating}★', 'offer.status.pending': 'Ожидает', 'offer.status.accepted': 'Принято', 'offer.status.declined': 'Отклонено', 'offer.status.withdrawn': 'Отозвано', 'offer.status.other_accepted': 'Выбран другой исполнитель', 'common.loading': 'Загрузка...', 'common.error': 'Ошибка', 'common.save': 'Сохранить', 'common.saving': 'Сохранение...', 'common.cancel': 'Отмена', 'common.add': 'Добавить', 'common.close': 'Закрыть', 'common.edit': 'Редактировать', 'common.delete': 'Удалить', 'common.from': 'от', 'common.currency': '€', 'common.greece': 'Греция', // Chat 'chat.connected': 'Подключено', 'chat.disconnected': 'Отключено', 'chat.no_rooms': 'Переписок пока нет', 'chat.task_fallback': 'Задача', 'chat.select': 'Выберите переписку', 'chat.no_messages': 'Сообщений пока нет', 'chat.placeholder': 'Напишите сообщение... (Enter для отправки)', 'chat.conversation_fallback': 'Переписка', 'chat.direct_chat': 'Личный чат', 'chat.linked_task': 'Прикреплённый заказ', 'chat.write_btn': 'Написать', 'chat.just_now': 'только что', 'chat.min_ago': 'м', 'chat.write_specialist': 'Написать специалисту', 'chat.write_customer': 'Написать заказчику', 'chat.notif_settings': 'Настройки уведомлений', 'chat.notif_messages': 'Уведомления о новых сообщениях', 'chat.toast_title': 'Новое сообщение', 'chat.toast_open': 'Открыть чат', // Offer form 'offer.price': 'Цена', 'offer.price.placeholder': 'напр. 80', 'offer.customer_budget': 'Бюджет заказчика', 'offer.message': 'Сообщение', 'offer.optional': 'необязательно', 'offer.message.placeholder': 'Представьтесь, расскажите об опыте и почему вы лучший выбор...', 'offer.submitting': 'Отправка...', // Profile 'profile.photo': 'Фото профиля', 'profile.photo.change': 'Изменить фото', 'profile.photo.hint': 'JPEG, PNG, WebP · до 5MB', 'profile.basic_info': 'Основная информация', 'profile.phone': 'Телефон', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Краткое описание', 'profile.bio.placeholder': 'Расскажите немного о себе...', 'profile.language': 'Язык', 'profile.language.hint': 'Язык интерфейса и email-уведомлений', 'profile.languages': 'Языки общения', 'profile.languages.hint': 'Выберите все языки, на которых вы общаетесь', 'profile.skills': 'Навыки', 'profile.skills.subtitle': 'Добавьте услуги, которые вы предлагаете', 'profile.skills.placeholder': 'напр. Уборка, IT, Репетиторство...', 'profile.role': 'Роль аккаунта', 'profile.role.specialist': '🔧 Специалист', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Пользователь', 'profile.role.change': 'Для смены роли обратитесь в службу поддержки.', 'profile.become_specialist': 'Стать специалистом', 'profile.become_specialist.desc': 'Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.', 'become_specialist.hero.title': 'Зарабатывай, делая то, что умеешь', 'become_specialist.hero.subtitle': 'Создай профиль специалиста и получай заказы от клиентов по всей Греции', 'become_specialist.how.title': 'Как это работает', 'become_specialist.step1.title': 'Создай портфолио специалиста', 'become_specialist.step1.desc': 'Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы', 'become_specialist.step2.title': 'Ищи заказы', 'become_specialist.step2.desc': 'Просматривай задачи по своим категориям в разделе «Поиск заказов»', 'become_specialist.step3.title': 'Откликайся и зарабатывай', 'become_specialist.step3.desc': 'Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы', 'become_specialist.benefits.title': 'Преимущества профиля специалиста', 'become_specialist.benefit1': 'Поиск заказов по вашим категориям и локации', 'become_specialist.benefit2': 'Публичный профиль с отзывами клиентов', 'become_specialist.benefit3': 'Расписание доступности, видимое клиентам', 'become_specialist.benefit4': 'Добавление в избранное клиентами', 'become_specialist.cta': 'Подробнее', 'become_specialist.free_badge': 'Бесплатная регистрация', 'profile.tab.notifications': 'Уведомления', 'profile.tab.reviews': 'Отзывы', 'profile.tab.referral': 'Рефералы', 'profile.tab.auto_response': 'Авто-ответ', 'profile.tab.site': 'Сайт', 'profile.site.title': 'Персональная страница', 'profile.site.url_label': 'Личный сайт', 'profile.site.copy': 'Копировать', 'profile.site.copied': 'Скопировано', 'profile.site.visible_title': 'Что отображается на вашей странице', 'profile.site.visible.name': 'Имя и фото', 'profile.site.visible.bio': 'Биография', 'profile.site.visible.rating': 'Рейтинг и отзывы', 'profile.site.visible.portfolio': 'Портфолио / Карточки', 'profile.site.visible.contacts': 'Контактные данные', 'profile.site.visible.full_last_name': 'Фамилия полностью', 'profile.site.visible.services': 'Карточки услуг', 'profile.site.visible.reviews': 'Раздел с отзывами', 'profile.site.visible.status': 'Статус «Готов помочь»', 'profile.site.theme': 'Тема оформления', 'profile.site.theme.dark': 'Тёмная', 'profile.site.theme.light': 'Светлая', 'profile.site.slug_taken': 'Этот адрес уже занят', 'profile.site.stats.title': 'Аналитика сайта', 'profile.site.stats.days': 'последние 30 дней', 'profile.site.stats.views': 'Просмотры', 'profile.site.stats.unique': 'Уникальные посетители', 'profile.site.stats.messages': 'Сообщения', 'profile.site.stats.total_views': 'Просмотры', 'profile.site.stats.total_unique': 'Уник. посетители', 'profile.site.stats.total_messages': 'Сообщения', 'profile.site.stats.empty': 'Данных пока нет', 'profile.site.stats.loading': 'Загрузка аналитики...', 'profile.site.stats.no_slug': 'Укажите адрес сайта, чтобы видеть статистику', 'profile.site.edit_bio_hint': 'Биография и фото настраиваются во вкладке «Основное».', 'status.title': 'Статус', 'status.can_help_now_hint': 'Ваша карточка показывается выше в поиске', 'status.need_help_hint': 'Специалисты могут предложить вам помощь', 'profile.referral.title': 'Партнёрская программа', 'profile.referral.desc': 'Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.', 'profile.referral.link_label': 'Ваша реферальная ссылка', 'profile.referral.copy': 'Копировать', 'profile.referral.copied': 'Скопировано!', 'profile.referral.invited_count': 'успешных приглашений', 'profile.referral.no_code': 'Реферальный код недоступен.', 'notifications.title': 'Настройки уведомлений', 'notifications.email.new_tasks': 'Email о новых заказах', 'notifications.email.new_tasks.desc': 'Получать email, когда в ваших категориях публикуется новый заказ', 'notifications.messages.desc': 'Получать уведомление при новом входящем сообщении', 'notifications.saved': 'Настройки сохранены', 'notifications.plan_required': 'Недоступно в вашем тарифе', 'profile.tab.info': 'Основное', 'profile.tab.finance': 'Финансы', 'profile.tab.skills': 'Навыки', 'profile.tab.categories': 'Категории', 'profile.tab.geography': 'География', 'profile.specialist.categories': 'Категории работ', 'profile.specialist.categories.desc': 'Выберите категории, в которых вы работаете', 'profile.specialist.geography': 'Города покрытия', 'profile.specialist.geography.desc': 'Выберите города / районы, где вы работаете', 'profile.saving': 'Сохранение...', 'profile.upload.error': 'Ошибка загрузки фото', 'profile.saved': 'Сохранено', 'profile.tab.cards': 'Портфолио', 'profile.cards.count': 'Портфолио', 'profile.cards.add': 'Добавить портфолио', 'profile.cards.new_title': 'Название нового портфолио', 'profile.cards.placeholder': 'Например: Сантехника', 'profile.cards.create': 'Создать', 'profile.cards.cancel': 'Отмена', 'profile.cards.empty': 'У вас нет портфолио', 'profile.cards.create_first': 'Создать первое портфолио', 'profile.cards.delete_confirm': 'Удалить портфолио?', 'profile.card.tab.main': 'Основное', 'profile.card.tab.skills': 'Навыки', 'profile.card.tab.categories': 'Категории', 'profile.card.tab.geography': 'География', 'profile.card.tab.portfolio': 'Галерея', 'profile.card.active': 'Активна', 'profile.card.save': 'Сохранить', 'profile.card.saved': 'Сохранено', 'profile.card.delete': 'Удалить', 'profile.card.skill.add': 'Добавить навык', 'profile.card.photo.add': 'Добавить фото', 'profile.card.photo.uploading': 'Загрузка...', 'profile.card.photo.empty': 'Нет фотографий', 'profile.card.item.title': 'Заголовок', 'profile.card.item.desc': 'Описание', 'profile.card.item.save': 'Сохранить', 'profile.card.item.cancel': 'Отмена', 'profile.card.item.edit': 'Описание работы', 'profile.upgrade.cards_limit': 'Лимит портфолио исчерпан', 'profile.upgrade.plan': 'Текущий тариф:', 'profile.upgrade.contact': 'Обратитесь к администратору для смены тарифа', 'profile.upgrade.ok': 'Понятно', 'profile.plan.title': 'Тарифный план', 'profile.balance': 'Баланс', 'profile.balance.topup': 'Пополнить баланс', 'profile.balance.topup.title': 'Пополнить баланс', 'profile.balance.topup.amount': 'Сумма (в EUR)', 'profile.balance.topup.hint': 'Выберите сумму или введите вручную', 'profile.balance.topup.submit': 'Перейти к оплате', 'profile.balance.topup.loading': 'Перенаправление...', 'profile.balance.topup.error': 'Ошибка инициализации платежа. Попробуйте снова.', 'payment.success.title': 'Оплата прошла успешно!', 'payment.success.desc': 'Ваш баланс обновлён.', 'payment.cancelled.title': 'Оплата отменена', 'payment.cancelled.desc': 'Оплата была отменена. Средства не списаны.', 'payment.pending.title': 'Обрабатывается...', 'payment.pending.desc': 'Ваш платёж в обработке.', 'payment.back_to_profile': 'Вернуться в профиль', 'profile.plan.basic': 'Базовый (бесплатный)', 'profile.plan.contact_upgrade': 'Обратитесь к администратору для подключения тарифа', 'profile.plan.cards_up_to': 'Портфолио: до', 'profile.plan.cards_unlimited': 'Портфолио: безлимитно', 'profile.plan.tasks_up_to': 'Задач: до', 'profile.plan.offers_up_to': 'Откликов: до', 'profile.plan.valid_until': 'Действителен до', 'profile.plan.no_expiry': 'Бессрочно', // Create task 'create.error': 'Ошибка при публикации', // Tasks list extras 'tasks.category.general': 'Общее', 'tasks.budget.range': 'Диапазон:', 'tasks.budget.from': 'от', 'tasks.budget.to': 'до', 'tasks.filter.reset': 'Сбросить фильтры', 'tasks.load_more': 'Загрузить ещё', 'tasks.showing': 'Результатов:', 'tasks.field.budget': 'Бюджет, €', // Admin 'admin.title': 'Панель администратора', 'admin.tab.stats': 'Статистика', 'admin.tab.users': 'Пользователи', 'admin.tab.tasks': 'Задачи', 'admin.tab.reports': 'Жалобы', 'admin.stats.users': 'Пользователи', 'admin.stats.tasks': 'Задачи', 'admin.stats.offers': 'Предложения', 'admin.stats.reviews': 'Отзывы', 'admin.tasks.by_status': 'Задачи по статусу', 'admin.col.user': 'Пользователь', 'admin.col.email': 'Email', 'admin.col.role': 'Роль', 'admin.col.registered': 'Регистрация', 'admin.col.status': 'Статус', 'admin.col.title': 'Название', 'admin.col.budget': 'Бюджет', 'admin.col.created': 'Создано', 'admin.users.active': 'Активен', 'admin.users.inactive': 'Неактивен', 'admin.users.deactivate': 'Деактивировать', 'admin.users.activate': 'Активировать', 'admin.tasks.cancel': 'Отменить', 'admin.reports.none': 'Жалоб нет', 'admin.reports.reviewed': 'Рассмотрено', 'admin.reports.dismiss': 'Отклонить', 'admin.pagination.total': 'Всего', 'admin.users.role.change': 'Изменить роль', 'admin.users.search.placeholder': 'Поиск по имени или email...', 'admin.tasks.delete': 'Удалить', 'admin.tasks.delete.confirm': 'Удалить эту задачу навсегда?', 'admin.tasks.search.placeholder': 'Поиск по названию...', 'admin.col.customer': 'Заказчик', 'admin.col.reporter': 'Жалобщик', 'admin.col.target': 'Цель', 'admin.filter.all_roles': 'Все роли', 'admin.filter.all_statuses': 'Все статусы', 'admin.reports.target.task': 'Задача', 'admin.reports.target.user': 'Пользователь', 'admin.tab.categories': 'Категории', 'admin.tab.locations': 'Города и районы', 'admin.tab.logs': 'Логи', 'admin.tab.plans': 'Тарифы', 'admin.tab.settings': 'Настройки', 'admin.logs.subtab.ai': 'AI логи', 'admin.logs.subtab.activity': 'Активность', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Уведомления', 'admin.notif_logs.type': 'Тип', 'admin.notif_logs.title': 'Заголовок', 'admin.notif_logs.read': 'Прочитано', 'admin.notif_logs.empty': 'Логи уведомлений пусты', 'admin.stats.notif_chart_title': 'Уведомления по дням', 'admin.stats.notif_label': 'Уведомления', 'admin.stats.mail_chart_title': 'Email по дням', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Все', 'admin.stats.specialists': 'Исполнители', 'admin.col.plan': 'Тариф', 'admin.back_home': 'На главную', 'admin.plans.title': 'Тарифные пакеты', 'admin.plans.add': '+ Добавить тариф', 'admin.plans.empty': 'Тарифы не созданы', 'admin.plans.form.new': 'Новый тариф', 'admin.plans.form.edit': 'Редактировать тариф', 'admin.plans.form.name': 'Название', 'admin.plans.form.price': 'Цена (EUR)', 'admin.plans.form.old_price': 'Старая цена (EUR, необязательно)', 'admin.plans.form.max_offers': 'Макс. откликов (пусто = без лимита)', 'admin.plans.form.max_cards': 'Макс. портфолио (пусто = без лимита)', 'admin.plans.form.duration_days': 'Срок (дней, пусто = без истечения)', 'admin.plans.form.description': 'Описание', 'admin.plans.form.features': 'Возможности (по одной на строку)', 'admin.plans.form.notify': 'Уведомления о новых заказах', 'admin.plans.form.default': 'По умолчанию', 'admin.plans.form.active': 'Активен', 'admin.plans.form.order': 'Порядок', 'admin.plans.form.role': 'Роль', 'admin.plans.form.tier': 'Уровень', 'admin.plans.form.role.customer': 'Заказчик', 'admin.plans.form.role.specialist': 'Специалист', 'admin.plans.form.tier.free': 'Бесплатный', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Лимиты (пусто = без ограничений)', 'admin.plans.form.max_messages_day': 'Макс. сообщений/день', 'admin.plans.form.max_orders_day': 'Макс. заказов/день', 'admin.plans.form.max_skills': 'Макс. навыков', 'admin.plans.form.max_profiles': 'Макс. профилей', 'admin.plans.form.max_portfolio': 'Макс. элементов портфолио', 'admin.plans.form.section.boost': 'Множители & Буст', 'admin.plans.form.search_boost': 'Буст в поиске', 'admin.plans.form.offers_multiplier': 'Множитель откликов', 'admin.plans.form.section.contact': 'Права контактов', 'admin.plans.form.can_contact_free': 'Контакт с бесплатными пользователями', 'admin.plans.form.can_contact_pro': 'Контакт с Pro пользователями', 'admin.plans.form.can_contact_all': 'Контакт со всеми', 'admin.plans.form.can_show_contact': 'Показывать контакты', 'admin.plans.form.can_view_phone': 'Просмотр телефона', 'admin.plans.form.section.features': 'Возможности', 'admin.plans.form.upload_video': 'Загрузка видео', 'admin.plans.form.favorites': 'Избранное', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Знак верификации', 'admin.plans.form.highlighted_reviews': 'Выделенные отзывы', 'admin.plans.form.personal_site': 'Личный сайт', 'admin.plans.form.can_help_now': 'Статус «Могу помочь»', 'admin.plans.form.need_help': 'Статус «Нужна помощь»', 'admin.plans.form.auto_response': 'Автоответ', 'admin.plans.form.auto_match': 'Автоподбор', 'admin.plans.form.instant_dispatch_free': 'Мгновенная рассылка (бесплатно)', 'admin.plans.form.instant_dispatch_pro': 'Мгновенная рассылка (Pro)', 'admin.plans.badge.default': 'По умолчанию', 'admin.plans.badge.inactive': 'Неактивен', 'admin.plans.make_default': 'Сделать по умолчанию', 'admin.plans.tasks': 'Задач', 'admin.plans.offers': 'Откликов', 'admin.plans.cards': 'Портфолио', 'admin.plans.notify_tasks': 'Уведомления о заказах', 'admin.plans.delete.confirm': 'Удалить тариф', 'admin.activity.title': 'Журнал активности', 'admin.activity.event': 'Событие', 'admin.activity.all_events': 'Все события', 'admin.activity.from': 'От', 'admin.activity.to': 'До', 'admin.activity.reset': 'Сбросить', 'admin.activity.total': 'Всего', 'admin.activity.empty': 'Нет записей', 'admin.mail.event': 'Email событие', 'admin.mail.all_events': 'Все email события', 'admin.mail.from': 'От', 'admin.mail.to': 'До', 'admin.mail.reset': 'Сбросить', 'admin.mail.total': 'Всего', 'admin.mail.empty': 'Нет email логов', 'admin.mail.recipient': 'Получатель', 'admin.mail.provider': 'Провайдер', 'admin.mail.details': 'Детали', 'admin.mail.status': 'Статус', 'admin.mail.success': 'Успешно', 'admin.mail.failed': 'Ошибка', 'admin.event.email_sent': 'Email отправлен', 'admin.event.email_failed': 'Email не отправлен', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Тестовый email отправлен', 'admin.event.admin_email_test_failed': 'Тестовый email не отправлен', 'admin.logs.empty': 'Нет записей', 'admin.logs.date': 'Дата', 'admin.logs.provider': 'Провайдер', 'admin.logs.model': 'Модель', 'admin.logs.action': 'Действие', 'admin.logs.langs': 'Языки', 'admin.logs.in': 'Вход', 'admin.logs.out': 'Выход', 'admin.logs.total': 'Итого', 'admin.logs.ms': 'мс', 'admin.logs.status': 'Статус', 'admin.stats.activity_30d': 'Активность за 30 дней', 'admin.stats.tasks_label': 'Заявки', 'admin.stats.users_label': 'Пользователи', 'admin.stats.specialists_label': 'Исполнители', 'admin.stats.tokens_title': 'Расход токенов (по месяцам)', 'admin.stats.tokens_out': 'Исходящие', 'admin.stats.tokens_in': 'Входящие', 'admin.stats.tokens_out_label': 'Исходящие токены', 'admin.stats.tokens_in_label': 'Входящие токены', 'admin.stats.cost_label': 'Стоимость (USD)', 'admin.stats.tasks_by_status': 'Заявки по статусам', 'admin.task_status.open': 'Открытые', 'admin.task_status.in_progress': 'В работе', 'admin.task_status.completed': 'Завершённые', 'admin.task_status.cancelled': 'Отменённые', 'admin.task_status.draft': 'Черновики', 'admin.settings.tab.general': 'Общие', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Уведомления', 'admin.settings.tab.payment': 'Оплата', 'admin.settings.tab.referral': 'Реферальная', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Соцсети', 'admin.settings.socials.title': 'Ссылки на социальные сети', 'admin.settings.socials.hint': 'Заполненные ссылки отображаются в подвале сайта', 'admin.settings.seo.maintenance_label': 'Режим обслуживания', 'admin.settings.seo.maintenance_hint': 'Показывать страницу обслуживания всем посетителям', 'admin.settings.seo.indexing_label': 'Индексация поисковыми системами', 'admin.settings.seo.indexing_hint': 'Разрешить поисковым системам индексировать сайт', 'admin.settings.seo.head_scripts_label': 'Скрипты в (JS)', 'admin.settings.seo.head_scripts_hint': 'Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)', 'admin.settings.seo.site_title_label': 'Заголовок сайта', 'admin.settings.seo.site_description_label': 'Описание сайта (meta description)', 'admin.settings.referral.title': 'Партнёрская программа', 'admin.settings.referral.hint': 'Награждайте пользователей, приводящих новых участников.', 'admin.settings.referral.enabled_label': 'Включено', 'admin.settings.referral.enabled_hint': 'Включить / отключить выдачу наград', 'admin.settings.referral.customer_section': 'Для клиентов', 'admin.settings.referral.specialist_section': 'Для специалистов', 'admin.settings.referral.plan_label': 'Тарифный план за реферала', 'admin.settings.referral.no_plan': '— без плана —', 'admin.settings.referral.plan_hint': 'Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.', 'admin.settings.referral.days_label': 'Дней награды', 'admin.settings.referral.days_hint': 'Количество дней, добавляемых к сроку действия плана.', 'admin.settings.general.title': 'Общие настройки', 'admin.settings.general.site_name': 'Название сайта', 'admin.settings.general.site_url': 'URL сайта', 'admin.settings.general.contact_email': 'Email для связи', 'admin.settings.general.support_phone': 'Телефон поддержки', 'admin.settings.smtp.title': 'Настройки SMTP сервера', 'admin.settings.smtp.hint': 'Используется для отправки email-уведомлений.', 'admin.settings.smtp.host': 'SMTP Хост', 'admin.settings.smtp.port': 'Порт', 'admin.settings.smtp.encryption': 'Шифрование', 'admin.settings.smtp.enc.none': 'Нет', 'admin.settings.smtp.enc.tls': 'STARTTLS (порт 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (порт 465)', 'admin.settings.smtp.username': 'Имя пользователя', 'admin.settings.smtp.password': 'Пароль / App Password', 'admin.settings.smtp.from_name': 'Имя отправителя', 'admin.settings.smtp.from_email': 'Email отправителя', 'admin.settings.smtp.test': 'Отправить тестовый email', 'admin.settings.smtp.sending': 'Отправка...', 'admin.settings.payment.hint': 'Данные для подключения к ePay Piraeus Bank.', 'admin.settings.env.test': 'Тест (sandbox)', 'admin.settings.env.prod': 'Боевой режим', 'admin.settings.env.label': 'Среда', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Активен', 'admin.settings.saving': 'Сохранение...', 'admin.settings.saved': 'Сохранено', 'admin.notif.vars_hint': 'Доступные переменные в шаблонах', 'admin.notif.tmpl.not_set': 'Шаблон не настроен', 'admin.notif.tmpl.subject_label': 'Тема письма', 'admin.notif.tmpl.body_label': 'Текст письма (HTML)', 'admin.notif.tmpl.save': 'Сохранить', 'admin.notif.tmpl.close': 'Закрыть', 'admin.notif.tmpl.translate': 'Авто-перевод на другие языки', 'admin.notif.tmpl.translating': 'Перевод...', 'admin.notif.tmpl.saving': 'Сохранение...', 'admin.notif.email_verification': 'Подтверждение email адреса', 'admin.notif.registration_success': 'Успешная регистрация', 'admin.notif.password_reset': 'Восстановление пароля', 'admin.notif.new_offer': 'Новое предложение', 'admin.notif.new_task': 'Новая задача', 'admin.notif.offer_accepted': 'Предложение принято', 'admin.notif.new_message': 'Новое сообщение', 'admin.notif.offer_declined': 'Отклонение предложения', 'admin.notif.offer_other_accepted': 'Выбран другой исполнитель', 'admin.notif.task_updated': 'Изменение задания', 'admin.notif.deadline_reminder': 'Напоминание о дедлайне', 'admin.notif.task_archived': 'Автоснятие задания', 'admin.notif.referral_reward': 'Реферальная награда', // Шаблоны email для тарифов 'admin.email_template.plan_activated': 'Тарифы — активация тарифа', 'admin.email_template.plan_upgraded': 'Тарифы — повышение тарифа', 'admin.email_template.plan_downgrade_scheduled': 'Тарифы — запланированное понижение', 'admin.email_template.plan_downgrade_applied': 'Тарифы — применение понижения', 'admin.email_template.plan_renewal_reminder': 'Тарифы — напоминание о продлении', 'admin.email_template.plan_insufficient_funds': 'Тарифы — нехватка средств', // Модальное окно подтверждения тарифа 'pricing.confirm.title': 'Подтвердите выбор тарифа', 'pricing.confirm.plan': 'Тариф', 'pricing.confirm.prorated': 'Зачёт остатка', 'pricing.confirm.effective_price': 'К оплате', 'pricing.confirm.your_balance': 'Ваш баланс', 'pricing.confirm.downgrade_info': 'Переход на новый тариф произойдёт автоматически после окончания текущего периода.', 'pricing.confirm.insufficient': 'Недостаточно средств на балансе.', 'pricing.confirm.top_up': 'Пополнить', 'pricing.confirm.schedule_downgrade': 'Запланировать переход', 'pricing.confirm.pay': 'Оплатить', 'admin.user_edit.title': 'Редактирование пользователя', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email подтверждён', 'admin.user_edit.email_not_verified': 'Email не подтверждён', 'admin.user_edit.verify_email_btn': 'Подтвердить вручную', 'admin.user_edit.verify_email_done': 'Email подтверждён!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Регистрация', 'admin.user_edit.last_seen': 'Последний визит', 'admin.user_edit.lang': 'Язык', 'admin.user_edit.first_name': 'Имя', 'admin.user_edit.last_name': 'Фамилия', 'admin.user_edit.phone': 'Телефон', 'admin.user_edit.bio': 'О себе', 'admin.user_edit.role': 'Роль', 'admin.user_edit.plan': 'Тариф', 'admin.user_edit.no_plan': '— Без тарифа —', 'admin.user_edit.active': 'Активный аккаунт', 'admin.user_edit.balance': 'Баланс (EUR)', 'admin.user_edit.skills': 'Навыки', 'admin.user_edit.tab.profile': 'Профиль', 'admin.user_edit.tab.account': 'Аккаунт', 'admin.user_edit.tab.balance': 'Баланс', 'admin.user_edit.tab.settings': 'Настройки', 'admin.user_edit.tab.specialist': 'Портфолио', 'admin.user_edit.tab.site': 'Сайт', 'admin.user_edit.plan_expires': 'Тариф истекает', 'admin.user_edit.interface_lang': 'Язык интерфейса', 'admin.user_edit.comm_languages': 'Языки общения', 'admin.user_edit.personal_site_slug': 'Персональная страница', 'admin.user_edit.show_contact_info': 'Показывать контакты', 'admin.user_edit.show_contact_info.hint': 'Видно заказчикам', 'admin.user_edit.notify_new_tasks': 'Уведомлять о новых задачах', 'admin.user_edit.notify_new_tasks.hint': 'Push и email уведомления', 'admin.user_edit.notif_messages': 'Уведомления о сообщениях', 'admin.user_edit.notif_messages.hint': 'Новые сообщения в чате', 'admin.user_edit.site_settings': 'Настройки персональной страницы', 'admin.user_edit.categories': 'Категории услуг', 'admin.user_edit.locations': 'Районы обслуживания', 'admin.user_edit.skill_placeholder': 'Новый навык...', 'admin.user_edit.add_category': '— Выберите категорию —', 'admin.user_edit.add_location': '— Выберите район —', 'admin.user_edit.specialist_cards': 'Портфолио специалиста', 'admin.user_edit.no_cards': 'Портфолио не найдено', 'admin.user_edit.card_title': 'Заголовок портфолио', 'admin.user_edit.card_description': 'Описание', 'admin.balance.topup.btn': 'Пополнить', 'admin.balance.withdraw.btn': 'Списать', 'admin.balance.modal_hint': 'Изменения применяются сразу и фиксируются в истории', 'admin.balance.topup.title': 'Пополнение баланса', 'admin.balance.topup.amount': 'Сумма', 'admin.balance.topup.description': 'Комментарий', 'admin.balance.topup.description.placeholder': 'Например: бонус или ручное пополнение', 'admin.balance.topup.submit': 'Пополнить баланс', 'admin.balance.withdraw.title': 'Снятие баланса', 'admin.balance.withdraw.amount': 'Сумма', 'admin.balance.withdraw.description': 'Комментарий', 'admin.balance.withdraw.description.placeholder': 'Например: возврат или ручное списание', 'admin.balance.withdraw.submit': 'Списать баланс', 'admin.user_edit.role.customer': 'Заказчик', 'admin.user_edit.role.specialist': 'Исполнитель', 'admin.user_edit.role.admin': 'Администратор', 'common.refresh': 'Обновить', 'common.back_home': 'На главную', 'admin.loc.hint': 'Управление городами и районами', 'admin.loc.add_city': 'Новый город', 'admin.loc.add_district': 'Добавить район', 'admin.loc.new': 'Новая локация', 'admin.loc.edit': 'Редактировать локацию', 'admin.loc.district': 'район', 'admin.loc.empty': 'Нет локаций', 'admin.loc.delete.confirm': 'Удалить локацию? Все районы также будут удалены.', 'admin.cat.add_root': 'Новая категория', 'admin.cat.add_sub': 'Подкатегория', 'admin.cat.edit': 'Редактировать', 'admin.cat.delete': 'Удалить', 'admin.cat.delete.confirm': 'Удалить категорию? Все подкатегории также будут удалены.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Иконка', 'admin.cat.name_el': 'Греческий', 'admin.cat.name_en': 'Английский', 'admin.cat.name_ru': 'Русский', 'admin.cat.order': 'Порядок', 'admin.cat.active': 'Активна', 'admin.cat.parent': 'Родительская категория', 'admin.cat.no_parent': 'Верхний уровень', 'admin.cat.save': 'Сохранить', 'admin.cat.cancel': 'Отмена', 'admin.cat.empty': 'Нет категорий', 'admin.cat.hint': 'Управление категориями с многоуровневой иерархией', 'admin.cat.new': 'Новая категория', 'admin.cat.subcategory': 'подкатегория', 'admin.cat.add_child': 'Добавить подкатегорию', 'admin.cat.inactive': 'Неактивна', 'admin.event.user_login': 'Вход', 'admin.event.user_register': 'Регистрация', 'admin.event.admin_user_deactivate': 'Блокировка юзера', 'admin.event.admin_user_activate': 'Разблокировка юзера', 'admin.event.admin_user_role_changed': 'Смена роли', 'admin.event.admin_task_cancelled': 'Отмена задачи', 'admin.event.admin_task_deleted': 'Удаление задачи', 'admin.event.admin_report_reviewed': 'Жалоба рассмотрена', 'admin.event.admin_report_dismissed': 'Жалоба отклонена', 'admin.event.task_created': 'Создана задача', // User status 'user.online': 'Онлайн', 'user.seen_minutes': 'был здесь {n} мин назад', 'user.seen_hours': 'был здесь {n} ч назад', 'user.seen_yesterday': 'был здесь вчера', 'user.seen_days': 'был здесь {n} дн назад', // Specialists 'specialists.title': 'Специалисты', 'specialists.search': 'Поиск специалиста...', 'specialists.search.btn': 'Поиск', 'specialists.empty': 'Специалисты не найдены', 'specialists.no_bio': 'Без описания', 'specialists.view': 'Смотреть профиль', 'specialists.reviews': 'отзывов', 'specialist.favorite': 'Добавить в избранное', 'specialist.unfavorite': 'Убрать из избранного', 'specialist.site_link': 'Личный сайт', 'favorites.specialists.title': 'Избранные специалисты', 'favorites.specialists.empty': 'Вы ещё не добавили специалистов в избранное', 'nav.favorites': 'Избранное', 'nav.schedule': 'Расписание', 'nav.find_tasks': 'Поиск заказов', 'schedule.title': 'Моё расписание', 'schedule.subtitle': 'Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность', 'schedule.available': 'Свободен', 'schedule.busy': 'Занят', 'schedule.unset': 'Не указано', 'schedule.click_hint': '← клик меняет статус по кругу', 'schedule.range_mode': 'Выделить диапазон', 'schedule.range_from': 'С {date} — выберите конечную дату', 'schedule.click_to_set': 'Нажмите чтобы отметить', 'schedule.free': 'свободно', 'schedule.busy_count': 'занято', 'schedule.free_days': 'свободных дней', 'schedule.googleCalendar': 'Google Календарь', 'schedule.connectGoogle': 'Подключить Google Календарь', 'schedule.disconnectGoogle': 'Отключить', 'schedule.connectedAs': 'Подключено как', 'schedule.importFromGoogle': 'Синхр. из Google', 'schedule.gcalConnected': '\u2713 Google Календарь подключён', 'schedule.gcalError': 'Ошибка подключения Google Календарь', 'schedule.gcalImportDone': 'Импортировано {n} дней из Google Календарь', 'schedule.gcalAutoSyncNote': 'Изменения доступности автоматически отправляются в Google Календарь', 'schedule.gcalConnectDesc': 'Подключите Google Календарь для автоматической синхронизации расписания', 'schedule.gcalDisconnectConfirm': 'Отключить Google Календарь?', 'find_tasks.title': 'Поиск заказов', 'find_tasks.for_me': 'Для меня', 'find_tasks.all': 'Все заказы', 'find_tasks.by_category': 'По категориям', 'find_tasks.list': 'Списком', 'find_tasks.already_offered': 'Предложение отправлено', 'find_tasks.offer_now': 'Откликнуться', 'find_tasks.empty_for_me': 'Нет заказов в ваших категориях', 'find_tasks.banner_hint': 'Найдите заказы по категориям вашего портфолио', 'find_tasks.no_cards': 'Создайте портфолио специалиста, чтобы видеть подходящие заказы', 'find_tasks.add_card': 'Создать портфолио', 'find_tasks.search': 'Поиск заказов...', 'find_tasks.tasks_count': 'заданий', 'footer.tagline': 'Платформа задач для Греции', 'footer.rights': 'Все права защищены.', // App download section 'app.download_title': 'Скачайте мобильное приложение CanHelp', 'app.download_desc': 'Всё CanHelp — всегда под рукой. Доступно для Android и iOS.', // Nav 'nav.pricing': 'Тарифы', // Pricing page 'pricing.title': 'Тарифы', 'pricing.subtitle': 'Выберите подходящий план', 'pricing.role.customer': 'Заказчик', 'pricing.role.specialist': 'Специалист', 'pricing.free': 'Бесплатно', 'pricing.per_month': 'мес', 'pricing.duration': 'Срок', 'pricing.days': 'дн.', 'pricing.current_plan': 'Ваш план', 'pricing.popular': 'Популярный', 'pricing.choose': 'Выбрать', 'pricing.your_plan': 'Активный план', 'pricing.free_default': 'По умолчанию', 'pricing.compare': 'Сравнение функций', 'pricing.feature': 'Функция', 'pricing.faq_note': 'Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.', 'pricing.feat.messages': 'Сообщений / день', 'pricing.feat.orders': 'Заказов / день', 'pricing.feat.contact_all': 'Связь со всеми', 'pricing.feat.view_phone': 'Просмотр телефона', 'pricing.feat.show_contact': 'Показывать контакты', 'pricing.feat.favorites': 'Избранное', 'pricing.feat.verified_badge': 'Верифицированный бейдж', 'pricing.feat.google_calendar': 'Google Календарь', 'pricing.feat.personal_site': 'Персональный сайт', 'pricing.feat.auto_response': 'Авто-ответ', 'pricing.feat.auto_match': 'Авто-подбор', 'pricing.feat.highlighted_reviews': 'Выделенные отзывы', 'pricing.feat.portfolio': 'Элементов портфолио', 'pricing.feat.cards': 'Карточки специалиста', 'pricing.feat.notify_tasks': 'Уведомления о новых задачах', 'pricing.feat.video': 'Видео в портфолио', // Upgrade prompt 'upgrade.available_in': 'Доступно в', 'upgrade.cta': 'Улучшить', // Dashboard plan block 'dashboard.plan.title': 'Мой план', 'dashboard.plan.expires': 'Истекает через {n} дней', 'dashboard.plan.upgrade': 'Улучшить план', 'dashboard.plan.no_plan': 'Бесплатный план', 'dashboard.plan.messages': 'Сообщений сегодня', 'dashboard.plan.orders': 'Заказов сегодня', 'dashboard.plan.limits': 'Дневные лимиты', 'dashboard.plan.features': 'Функции', 'dashboard.plan.stats': 'Статистика', 'dashboard.stats.cards': 'Портфолио', 'dashboard.stats.maxCards': 'Макс. портфолио', 'dashboard.stats.portfolioItems': 'Элементы портфолио', 'dashboard.stats.maxPortfolioItems': 'Макс. элементы', 'dashboard.stats.activeOffers': 'Активные отклики', 'dashboard.stats.reviewsReceived': 'Отзывы', 'dashboard.stats.activeTasks': 'Активные задачи', 'dashboard.stats.completedTasks': 'Завершённые', 'status.need_help': 'Нужна помощь', 'status.active': 'Активен', 'status.toggle_on': 'Включить', 'status.toggle_off': 'Выключить', // FOMO 'fomo.missed_orders': 'Пропущено {n} заказов', 'fomo.missed_value': 'На сумму €{v}', 'fomo.upgrade_hint': 'Улучшите план — получайте больше заказов', 'fomo.conversion': 'Конверсия задач', 'fomo.active': 'Активные', 'fomo.with_offers': 'С офертами', 'fomo.completed': 'Завершённые', 'fomo.already_offered': '{n} специалистов уже откликнулись', 'fomo.specialist_missed': 'Вы пропустили {n} заказов', 'fomo.top_categories': 'Категории', 'fomo.offers_received': 'предложений получено', 'fomo.avg_offers': 'В среднем {n}/задача', 'fomo.completion_rate': 'завершено', // Task auto-match 'task.auto_match': 'Авто-матч', 'task.auto_match_results': 'Топ специалисты', 'task.no_offer_yet': 'Вы ещё не отправили предложение', 'task.make_offer': 'Отправить предложение', 'auto_response.title': 'Авто-ответ', 'auto_response.enabled': 'Включить авто-ответ', 'auto_response.min_budget': 'Мин. бюджет', 'auto_response.max_budget': 'Макс. бюджет', 'auto_response.default_price': 'Цена по умолчанию', 'auto_response.default_message': 'Сообщение по умолчанию', 'auto_response.max_per_day': 'Макс. авто-офертов в день', 'auto_response.save': 'Сохранить', 'auto_response.saved': 'Сохранено', 'auto_response.categories': 'Категории', 'auto_response.locations': 'Локации', // Personal site 'profile.personal_site': 'Персональный сайт', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Только латинские буквы, цифры, - и _', 'profile.site_open': 'Открыть сайт', 'profile.site_preview': 'Ваш сайт', 'profile.show_contact': 'Показывать контакты', 'profile.show_contact_hint': 'Заказчики с Pro/Ultimate-планом увидят ваш телефон', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Календарь требует план Pro или Ultimate', // Chat limits 'chat.limit_warning': 'Осталось {n} сообщений сегодня', 'chat.limit_reached': 'Лимит сообщений исчерпан. Улучшите план', 'chat.upgrade': 'Улучшить', // Site page 'site.member_since': 'С нами с', 'site.rating': 'Рейтинг', 'site.completed_tasks': 'Выполнено', 'site.languages': 'Языков', 'site.photos': 'фото', 'site.contact_form': 'Связаться', 'site.contact_sent': 'Сообщение отправлено!', 'site.contact_sent_desc': 'Специалист свяжется с вами в ближайшее время', 'site.contact_name': 'Имя', 'site.contact_name_ph': 'Ваше имя', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Сообщение', 'site.contact_message_ph': 'Опишите вашу задачу...', 'site.contact_send': 'Отправить', 'site.share': 'Поделиться', 'site.speaks_languages': 'Говорит на языках', 'site.message_sent': 'Сообщение отправлено!', 'site.message_sent_desc': 'Специалист получит его в чате', 'site.message_placeholder': 'Напишите сообщение...', 'site.write_to_chat': 'Написать в чат', 'site.auth_required_title': 'Нужна авторизация', 'site.auth_required_desc': 'Чтобы написать в чат, необходимо войти в аккаунт CanHelp.', 'site.auth_login_btn': 'Войти в аккаунт', 'site.auth_contact_form_btn': 'Написать через форму обратной связи', 'specialist.services': 'Услуги', 'portfolio.title': 'Портфолио', 'status.can_help_now': 'Готов помочь', 'common.not_found': 'Страница не найдена', 'common.anonymous': 'Анонимно', 'specialist_setup.page_title': 'Настройка профиля специалиста', 'specialist_setup.step_of': 'Шаг {current} из {total}', 'specialist_setup.next': 'Далее', 'specialist_setup.back': 'Назад', 'specialist_setup.skip': 'Пропустить', 'specialist_setup.finish': 'Завершить', 'specialist_setup.go_to_profile': 'Перейти в профиль', 'specialist_setup.browse_tasks': 'Найти задачи', 'specialist_setup.step1.title': 'Добро пожаловать!', 'specialist_setup.step1.subtitle': 'Давайте настроим ваш профиль', 'specialist_setup.step1.desc': 'Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.', 'specialist_setup.step1.what_next': 'Что мы сделаем:', 'specialist_setup.step1.item1': 'Заполним основную информацию', 'specialist_setup.step1.item2': 'Создадим карточку услуги', 'specialist_setup.step1.item3': 'Добавим навыки и категории', 'specialist_setup.step1.item4': 'Выберем географию обслуживания', 'specialist_setup.step1.item5': 'Загрузим фото портфолио', 'specialist_setup.step2.title': 'Базовый профиль', 'specialist_setup.step2.subtitle': 'Расскажите о себе', 'specialist_setup.step2.bio_label': 'О себе', 'specialist_setup.step2.bio_placeholder': 'Опишите ваш опыт, услуги которые вы предлагаете...', 'specialist_setup.step2.phone_label': 'Телефон', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Фото профиля', 'specialist_setup.step2.photo_btn': 'Загрузить фото', 'specialist_setup.step2.photo_uploading': 'Загрузка...', 'specialist_setup.step2.photo_hint': 'Отображается в вашем профиле', 'specialist_setup.step3.title': 'Карточка услуги', 'specialist_setup.step3.subtitle': 'Создайте вашу первую карточку услуги', 'specialist_setup.step3.title_label': 'Название карточки', 'specialist_setup.step3.title_placeholder': 'Напр. Сантехник, Электрик, Уборка...', 'specialist_setup.step3.desc_label': 'Описание', 'specialist_setup.step3.desc_placeholder': 'Подробно опишите что вы предлагаете, опыт, преимущества...', 'specialist_setup.step3.title_required': 'Название обязательно', 'specialist_setup.step4.title': 'Навыки и категории', 'specialist_setup.step4.subtitle': 'Добавьте навыки и выберите категории', 'specialist_setup.step4.skills_label': 'Навыки', 'specialist_setup.step4.skills_placeholder': 'Напр. Монтаж труб...', 'specialist_setup.step4.skills_add': 'Добавить', 'specialist_setup.step4.categories_label': 'Категории', 'specialist_setup.step5.title': 'География обслуживания', 'specialist_setup.step5.subtitle': 'Где вы оказываете услуги?', 'specialist_setup.step5.hint': 'Выберите города или конкретные районы', 'specialist_setup.done.title': 'Ваш профиль готов!', 'specialist_setup.done.subtitle': 'Поздравляем! Профиль настроен', 'specialist_setup.done.desc': 'Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам.' } }; function getTranslations(locale) { const t = translations[locale] ?? translations.el; return (key, fallback)=>t[key] ?? translations.el[key] ?? fallback ?? key; } /***/ })   /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ getTranslations), /* harmony export */ YZ: () => (/* binding */ LOCALES) /* harmony export */ }); /* unused harmony export translations */ nexport const LOCALES = [ { code: 'el', label: 'Ελληνικά', flag: '🇬🇷' }, { code: 'en', label: 'English', flag: '🇬🇧' }, { code: 'ru', label: 'Русский', flag: '🇷🇺' } ]; export const translations = { el: { 'footer.slogan': 'Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.', 'footer.links': 'Σύνδεσμοι', 'footer.socials': 'Στα κοινωνικά δίκτυα', // Nav 'nav.home': 'Αρχική', 'nav.tasks': 'Εργασίες', 'nav.post': '+ Δημοσίευση', 'nav.dashboard': 'Πίνακας', 'nav.chat': 'Μηνύματα', 'nav.notifications': 'Ειδοποιήσεις', 'nav.profile': 'Προφίλ', 'nav.admin': 'Διαχείριση', 'nav.specialists': 'Ειδικοί', 'nav.new_task': 'Νέα εργασία', 'nav.login': 'Σύνδεση', 'nav.register': 'Εγγραφή', 'nav.logout': 'Έξοδος', // Hero 'hero.title': 'Βρες ειδικό για κάθε δουλειά', 'hero.subtitle': 'Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία', 'hero.cta.post': 'Δημοσίευσε εργασία', 'hero.cta.browse': 'Γίνε ειδικός', 'hero.search.placeholder': 'Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...', 'stats.specialists': 'ειδικοί', 'stats.tasks': 'εργασίες', 'stats.categories': 'κατηγορίες', 'stats.free': 'δωρεάν εγγραφή', // Sections 'section.categories': 'Δημιούργησε εργασία σε οποιαδήποτε κατηγορία', 'section.how': 'Πώς λειτουργεί', 'section.recent': 'Πρόσφατες εργασίες', 'section.all': 'Δες όλες →', 'section.more': 'ακόμα', 'section.cities': 'Πόλεις & Περιοχές', 'section.community': 'Ένα κοινοτικό έργο για όλους', 'community.subtitle': 'Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.', 'community.point1.title': 'Είσαι ειδικός σε κάτι;', 'community.point1.desc': 'Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.', 'community.point2.title': 'Χρειάζεσαι βοήθεια;', 'community.point2.desc': 'Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.', 'community.point3.title': 'Βοήθησε το έργο να αναπτυχθεί', 'community.point3.desc': 'Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.', 'community.share': 'Μοιράσου με φίλους', 'community.share.copied': 'Σύνδεσμος αντιγράφηκε!', // Referral section on home page 'section.referral': 'Πρόγραμμα παραπομπών', 'referral.home.subtitle': 'Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.', 'referral.home.step1.title': 'Εγγραφείσε και λάβε σύνδεσμο', 'referral.home.step1.desc': 'Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.', 'referral.home.step2.title': 'Μοιράσου με φίλους', 'referral.home.step2.desc': 'Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.', 'referral.home.step3.title': 'Κέρδισε ανταμοιβές', 'referral.home.step3.desc': 'Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.', 'referral.home.cta': 'Πάρε τον σύνδεσμό σου', 'referral.home.badge': 'Πρόγραμμα παραπομπών', // FAQ section 'section.faq': 'Συχνές Ερωτήσεις', 'faq.q1': 'Πώς λειτουργεί το CanHelp;', 'faq.a1': 'Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.', 'faq.q2': 'Πόσο κοστίζει η χρήση της πλατφόρμας;', 'faq.a2': 'Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.', 'faq.q3': 'Πώς μπορώ να γίνω ειδικός;', 'faq.a3': 'Κάνε εγγραφή, πήγαινε στο «Γίνε Ειδικός», συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.', 'faq.q4': 'Πώς επιλέγω τον κατάλληλο ειδικό;', 'faq.a4': 'Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q5': 'Τι γίνεται αν δεν είμαι ικανοποιημένος;', 'faq.a5': 'Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.', 'faq.q6': 'Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;', 'faq.a6': 'Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q7': 'Πόσος χρόνος χρειάζεται για να λάβω προσφορές;', 'faq.a7': 'Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.', 'faq.q8': 'Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;', 'faq.a8': 'Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.', 'faq.q9': 'Τι είδη εργασιών μπορώ να βρω στο CanHelp;', 'faq.a9': 'Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.', 'faq.q10': 'Υπάρχει εφαρμογή για κινητό;', 'faq.a10': 'Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.', // How it works 'how.step1.title': 'Δημοσίευσε εργασία', 'how.step1.desc': 'Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου', 'how.step2.title': 'Λάβε προσφορές', 'how.step2.desc': 'Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο', 'how.step3.title': 'Επίλεξε & ξεκίνα', 'how.step3.desc': 'Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία', // Tasks page 'tasks.title': 'εργασίες', 'tasks.filters': 'Φίλτρα', 'tasks.search': 'Αναζήτηση', 'tasks.search.placeholder': 'Τίτλος ή λέξη κλειδί...', 'tasks.search.btn': 'Αναζήτηση', 'tasks.publish': 'Δημοσίευση', 'tasks.category.all': 'Όλες', 'tasks.category.all_in': 'Όλα στην', 'tasks.category.label': 'Κατηγορία', 'tasks.location.label': 'Πόλη', 'tasks.location.placeholder': 'π.χ. Αθήνα', 'tasks.empty': 'Δεν βρέθηκαν εργασίες', 'tasks.empty.cta': 'Δημοσίευσε την πρώτη', // Task detail 'task.status.open': 'Ανοιχτή', 'task.status.in_progress': 'Σε εξέλιξη', 'task.status.completed': 'Ολοκληρωμένη', 'task.status.cancelled': 'Ακυρωμένη', 'task.status.draft': 'Πρόχειρο', 'task.budget': 'Προϋπολογισμός', 'task.location': 'Τοποθεσία', 'task.deadline': 'Ημερομηνία έναρξης', 'task.created_at': 'Δημιουργήθηκε', 'task.customer': 'Πελάτης', 'task.offer.btn': 'Υποβολή προσφοράς', 'task.invite.banner_title': 'Σας προσκαλούν σε αυτήν την εργασία', 'task.invite.banner_hint': 'Ο πελάτης σας πρόσκαλεσε προσωπικά', 'task.invite.accept': 'Αποστολή προσφοράς', 'task.invite.decline': 'Άρνηση', 'offer.accept': 'Αποδοχή', 'offer.decline': 'Απόρριψη', 'task.complete': 'Ολοκλήρωση εργασίας', 'task.complete.confirm': 'Να ολοκληρωθεί η εργασία;', 'task.edit': 'Επεξεργασία', 'task.status_label': 'Κατάσταση', 'task.yours': 'Η εργασία σου', 'task.offer.yours': 'Η προσφορά σου', 'review.leave': 'Άφησε αξιολόγηση', 'review.rating': 'Βαθμολογία', 'review.comment': 'Σχόλιο', 'review.comment.placeholder': 'Πες μας για την εμπειρία σου...', 'review.submit': 'Υποβολή αξιολόγησης', 'review.submitting': 'Αποστολή...', 'review.done': 'Η αξιολόγηση καταχωρήθηκε!', 'profile.reviews': 'Αξιολογήσεις', 'profile.no_reviews': 'Δεν υπάρχουν αξιολογήσεις ακόμα', 'profile.rating': 'Βαθμολογία', 'profile.skills.label': 'Δεξιότητες', 'profile.member_since': 'Μέλος από', 'task.offers': 'Προσφορές', 'task.offers.none': 'Δεν υπάρχουν ακόμα προσφορές', // Create task 'create.title': 'Δημοσίευση εργασίας', 'create.field.title': 'Τίτλος', 'create.field.description': 'Περιγραφή', 'create.field.category': 'Κατηγορία', 'create.field.category.select': 'Επιλέξτε...', 'create.field.location': 'Τοποθεσία', 'create.field.location.any': 'Οπουδήποτε', 'create.field.location.all': 'Ολόκληρη η πόλη', 'create.field.budget': 'Προϋπολογισμός (€)', 'create.field.deadline': 'Ημερομηνία έναρξης', 'create.field.budget_negotiable': 'Η τιμή είναι διαπραγματεύσιμη', 'create.field.time_slot': 'Χρόνος εκτέλεσης', 'create.field.time_slot.any': 'Οποιαδήποτε', 'create.field.time_slot.morning': 'Πρωινό (08:00–13:00)', 'create.field.time_slot.afternoon': 'Μεσημέρι (13:00–18:00)', 'create.field.time_slot.evening': 'Βράδυ (18:00–22:00)', 'create.field.time_slot.weekend': 'Σαββατοκύριακο', 'create.field.address': 'Διεύθυνση (προαιρετικά)', 'create.field.address.district': 'Συνοικία', 'create.field.address.street': 'Οδός', 'create.field.address.house': 'Αριθμός', 'create.field.confidential': 'Εμπιστευτική σημείωση', 'create.field.confidential.placeholder': 'Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...', 'create.field.confidential.hint': 'Δεν εμφανίζεται δημόσια', 'create.field.photos': 'Φωτογραφίες', 'create.field.photos.add': 'Προσθήκη φωτογραφίας', 'create.field.photos.uploading': 'Ανέβασμα...', 'task.budget_negotiable': 'Τιμή διαπραγματεύσιμη', 'task.time_slot': 'Χρόνος', 'task.confidential': 'Εμπιστευτική σημείωση', 'create.field.title.placeholder': 'π.χ. Καθαρισμός διαμερίσματος 80τμ', 'create.field.description.placeholder': 'Περίγραψε λεπτομερώς τι χρειάζεσαι...', 'create.field.location.placeholder': 'π.χ. Αθήνα, Κολωνάκι', 'create.field.budget.placeholder': 'π.χ. 100', 'create.submit': 'Δημοσίευση εργασίας', 'create.submitting': 'Δημοσίευση...', // Auth 'login.title': 'Καλωσόρισες', 'login.subtitle': 'Σύνδεση στο CanHelp', 'login.email': 'Email', 'login.password': 'Κωδικός', 'login.submit': 'Σύνδεση', 'login.submitting': 'Σύνδεση...', 'login.error': 'Λάθος email ή κωδικός', 'login.unverified.title': 'Επιβεβαιώστε το email σας', 'login.unverified.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.', 'login.unverified.resend': 'Αποστολή νέου email επαλήθευσης', 'login.unverified.sending': 'Αποστολή...', 'login.unverified.sent': '✓ Εστάλη — ελέγξτε τα εισερχόμενα', 'profile.email.verified': 'Email επαληθεύτηκε', 'profile.email.not_verified': 'Email δεν επαληθεύτηκε', 'login.no_account': 'Δεν έχεις λογαριασμό;', 'login.register_link': 'Εγγραφή', 'login.forgot_password': 'Ξέχασα τον κωδικό', 'login.or_continue_with': 'ή συνεχίστε με', 'login.continue_google': 'Σύνδεση με Google', 'forgot.title': 'Ξέχασα τον κωδικό', 'forgot.subtitle': 'Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης', 'forgot.email': 'Email', 'forgot.submit': 'Αποστολή', 'forgot.submitting': 'Αποστολή...', 'forgot.sent.title': 'Ελέγξτε τα εισερχόμενά σας', 'forgot.sent.desc': 'Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.', 'forgot.back_to_login': 'Επιστροφή στη σύνδεση', 'forgot.error': 'Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.', 'forgot.error.not_found': 'Δεν βρέθηκε λογαριασμός με αυτό το email.', 'forgot.error.send_failed': 'Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα', 'reset.title': 'Νέος κωδικός', 'reset.subtitle': 'Εισάγετε τον νέο σας κωδικό', 'reset.password': 'Νέος κωδικός', 'reset.confirm': 'Επιβεβαίωση κωδικού', 'reset.submit': 'Αλλαγή κωδικού', 'reset.submitting': 'Αποθήκευση...', 'reset.success': 'Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...', 'reset.back_to_login': 'Επιστροφή στη σύνδεση', 'reset.error.mismatch': 'Οι κωδικοί δεν ταιριάζουν', 'reset.error.invalid': 'Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.', 'register.title': 'Εγγραφή', 'register.subtitle': 'Δημιουργία λογαριασμού στο CanHelp', 'register.first_name': 'Όνομα', 'register.last_name': 'Επώνυμο', 'register.email': 'Email', 'register.password': 'Κωδικός (min 8 χαρακτήρες)', 'register.role': 'Ρόλος', 'register.role.customer': 'Χρήστης', 'register.role.customer.desc': 'Δημοσιεύω εργασίες', 'register.role.specialist': 'Ειδικός', 'register.role.specialist.desc': 'Αναλαμβάνω εργασίες', 'register.submit': 'Δημιουργία λογαριασμού', 'register.submitting': 'Εγγραφή...', 'register.has_account': 'Έχεις ήδη λογαριασμό;', 'register.login_link': 'Σύνδεση', 'register.continue_google': 'Εγγραφή με Google', 'register.check_email.title': 'Ελέγξτε το email σας', 'register.check_email.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.', 'register.check_email.login': 'Επιστροφή στη σύνδεση', // Dashboard 'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.new_task': '+ Νέα εργασία', 'dashboard.my_tasks': 'Οι εργασίες μου', 'dashboard.my_offers': 'Οι προσφορές μου', 'dashboard.invitations': 'Προσκλήσεις για εργασία', 'dashboard.offers_count': 'προσφορές', 'dashboard.declined_count': 'απορρίφθηκαν', 'dashboard.completed_tasks': 'Ολοκληρωμένες εργασίες', 'dashboard.completed_offers': 'Ολοκληρωμένες προσφορές', 'dashboard.review_pending': 'Η αξιολόγηση δεν έχει υποβληθεί ακόμα', 'tasks.new.top_specialists': 'Κορυφαίοι ειδικοί', 'tasks.new.select_category': 'Επιλέξτε κατηγορία για να δείτε ειδικούς', 'tasks.new.invite': 'Πρόσκληση', 'tasks.new.invited': 'Επιλέχθηκε ✓', 'reviews.count': 'αξιολογήσεις', 'filter.location': 'Τοποθεσία', 'filter.language': 'Γλώσσες', 'filter.language.any': 'Οποιαδήποτε γλώσσα', 'filter.category.all': 'Όλες οι κατηγορίες', 'user.categories': 'Κατηγορίες', 'user.work_area': 'Περιοχή εργασίας', 'dashboard.tasks.empty': 'Δεν έχεις δημοσιεύσει εργασίες', 'dashboard.tasks.empty.cta': 'Δημοσίευσε την πρώτη σου', 'dashboard.tasks.add_new': 'Πρόσθεσε νέα εργασία', 'dashboard.offers.empty': 'Δεν έχεις υποβάλλει προσφορές', 'dashboard.offers.empty.cta': 'Βρες εργασίες', 'dashboard.customer.specialists_title': 'Ψάχνεις εκτελεστή;', 'dashboard.customer.specialists_hint': 'Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου', 'dashboard.customer.specialists_cta': 'Βρες ειδικό', 'dashboard.customer.how_title': 'Πώς λειτουργεί', 'dashboard.customer.step1': 'Δημιούργησε εργασία με περιγραφή και προϋπολογισμό', 'dashboard.customer.step2': 'Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο', 'dashboard.customer.step3': 'Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία', // Notifications 'notif.title': 'Ειδοποιήσεις', 'notif.mark_all': 'Σήμανση όλων ως αναγνωσμένα', 'notif.empty': 'Δεν υπάρχουν ειδοποιήσεις', 'notif.type.new_offer': 'Νέα προσφορά', 'notif.type.offer_accepted': 'Η προσφορά σας έγινε δεκτή', 'notif.type.offer_declined': 'Η προσφορά σας απορρίφθηκε', 'notif.type.task_completed': 'Η εργασία ολοκληρώθηκε', 'notif.type.task_cancelled': 'Η εργασία ακυρώθηκε', 'notif.type.new_message': 'Νέο μήνυμα', 'notif.type.new_review': 'Νέα αξιολόγηση', 'notif.type.task_invite': 'Πρόσκληση σε εργασία', 'notif.body.new_offer': 'Νέα προσφορά για «{title}»', 'notif.body.offer_accepted': 'Η προσφορά σας για «{title}» έγινε δεκτή', 'notif.body.offer_declined': 'Η προσφορά σας για «{title}» απορρίφθηκε', 'notif.body.task_invite': 'Σας προσκαλούν για «{title}»', 'notif.body.new_review': 'Λάβατε αξιολόγηση {rating}★', // Offer status 'offer.status.pending': 'Εκκρεμεί', 'offer.status.accepted': 'Αποδεκτή', 'offer.status.declined': 'Απορρίφθηκε', 'offer.status.withdrawn': 'Αποσύρθηκε', 'offer.status.other_accepted': 'Επιλέχθηκε άλλος ειδικός', // Common 'common.loading': 'Φόρτωση...', 'common.error': 'Σφάλμα', 'common.save': 'Αποθήκευση', 'common.saving': 'Αποθήκευση...', 'common.cancel': 'Ακύρωση', 'common.add': 'Προσθήκη', 'common.close': 'Κλείσιμο', 'common.edit': 'Επεξεργασία', 'common.delete': 'Διαγραφή', 'common.from': 'από', 'common.currency': '€', 'common.greece': 'Ελλάδα', // Chat 'chat.connected': 'Συνδεδεμένος', 'chat.disconnected': 'Αποσυνδεδεμένος', 'chat.no_rooms': 'Δεν υπάρχουν συνομιλίες ακόμα', 'chat.task_fallback': 'Εργασία', 'chat.select': 'Επίλεξε συνομιλία', 'chat.no_messages': 'Δεν υπάρχουν μηνύματα', 'chat.placeholder': 'Γράψε μήνυμα... (Enter για αποστολή)', 'chat.conversation_fallback': 'Συνομιλία', 'chat.direct_chat': 'Απευθείας συνομιλία', 'chat.linked_task': 'Συνδεδεμένη εργασία', 'chat.write_btn': 'Μήνυμα', 'chat.just_now': 'μόλις τώρα', 'chat.min_ago': 'λ', 'chat.write_specialist': 'Γράψε στον ειδικό', 'chat.write_customer': 'Γράψε στον πελάτη', 'chat.notif_settings': 'Ρυθμίσεις ειδοποιήσεων', 'chat.notif_messages': 'Ειδοποιήσεις για νέα μηνύματα', 'chat.toast_title': 'Νέο μήνυμα', 'chat.toast_open': 'Άνοιγμα συνομιλίας', // Offer form 'offer.price': 'Τιμή', 'offer.price.placeholder': 'π.χ. 80', 'offer.customer_budget': 'Προϋπολογισμός πελάτη', 'offer.message': 'Μήνυμα', 'offer.optional': 'προαιρετικό', 'offer.message.placeholder': 'Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...', 'offer.submitting': 'Αποστολή...', // Profile 'profile.photo': 'Φωτογραφία προφίλ', 'profile.photo.change': 'Αλλαγή φωτογραφίας', 'profile.photo.hint': 'JPEG, PNG, WebP · έως 5MB', 'profile.basic_info': 'Βασικά στοιχεία', 'profile.phone': 'Τηλέφωνο', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Σύντομη περιγραφή', 'profile.bio.placeholder': 'Πες μας λίγα λόγια για εσένα...', 'profile.language': 'Γλώσσα', 'profile.language.hint': 'Γλώσσα διεπαφής και email ειδοποιήσεων', 'profile.languages': 'Γλώσσες επικοινωνίας', 'profile.languages.hint': 'Επιλέξτε όλες τις γλώσσες που μιλάτε', 'profile.skills': 'Δεξιότητες', 'profile.skills.subtitle': 'Προσθέσε τις υπηρεσίες που προσφέρεις', 'profile.skills.placeholder': 'π.χ. Καθαρισμός, IT, Μαθήματα...', 'profile.role': 'Ρόλος λογαριασμού', 'profile.role.specialist': '🔧 Ειδικός', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Χρήστης', 'profile.role.change': 'Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.', 'profile.become_specialist': 'Γίνε Ειδικός', 'profile.become_specialist.desc': 'Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.', 'become_specialist.hero.title': 'Κέρδισε χρήματα κάνοντας αυτό που ξέρεις', 'become_specialist.hero.subtitle': 'Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα', 'become_specialist.how.title': 'Πώς λειτουργεί', 'become_specialist.step1.title': 'Δημιούργησε κάρτα ειδικού', 'become_specialist.step1.desc': 'Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα', 'become_specialist.step2.title': 'Βρες εργασίες', 'become_specialist.step2.desc': 'Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα «Αναζήτηση εργασιών»', 'become_specialist.step3.title': 'Στείλε προσφορά & κέρδισε', 'become_specialist.step3.desc': 'Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες', 'become_specialist.benefits.title': 'Πλεονεκτήματα προφίλ ειδικού', 'become_specialist.benefit1': 'Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία', 'become_specialist.benefit2': 'Δημόσιο προφίλ με αξιολογήσεις πελατών', 'become_specialist.benefit3': 'Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες', 'become_specialist.benefit4': 'Προσθήκη σε αγαπημένα από πελάτες', 'become_specialist.cta': 'Περισσότερα', 'become_specialist.free_badge': 'Δωρεάν εγγραφή', 'profile.tab.notifications': 'Ειδοποιήσεις', 'profile.tab.reviews': 'Αξιολογήσεις', 'profile.tab.referral': 'Παραπομπές', 'profile.tab.auto_response': 'Αυτόματη απάντηση', 'profile.tab.site': 'Site', 'profile.site.title': 'Προσωπική σελίδα', 'profile.site.url_label': 'Προσωπικό site', 'profile.site.copy': 'Αντιγραφή', 'profile.site.copied': 'Αντιγράφηκε', 'profile.site.visible_title': 'Τι εμφανίζεται στη σελίδα σας', 'profile.site.visible.name': 'Όνομα και φωτογραφία', 'profile.site.visible.bio': 'Βιογραφικό', 'profile.site.visible.rating': 'Αξιολόγηση και κριτικές', 'profile.site.visible.portfolio': 'Χαρτοφυλάκιο / Κάρτες', 'profile.site.visible.contacts': 'Στοιχεία επικοινωνίας', 'profile.site.visible.full_last_name': 'Πλήρες επώνυμο', 'profile.site.visible.services': 'Κάρτες υπηρεσιών', 'profile.site.visible.reviews': 'Ενότητα κριτικών', 'profile.site.visible.status': 'Κατάσταση «Έτοιμος να βοηθήσω»', 'profile.site.theme': 'Θέμα εμφάνισης', 'profile.site.theme.dark': 'Σκοτεινό', 'profile.site.theme.light': 'Φωτεινό', 'profile.site.slug_taken': 'Αυτή η διεύθυνση είναι ήδη κατειλημμένη', 'profile.site.stats.title': 'Στατιστικά επισκεψιμότητας', 'profile.site.stats.days': 'τελευταίες 30 ημέρες', 'profile.site.stats.views': 'Προβολές', 'profile.site.stats.unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.messages': 'Μηνύματα', 'profile.site.stats.total_views': 'Συνολικές προβολές', 'profile.site.stats.total_unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.total_messages': 'Μηνύματα', 'profile.site.stats.empty': 'Δεν υπάρχουν δεδομένα ακόμη', 'profile.site.stats.loading': 'Φόρτωση στατιστικών...', 'profile.site.stats.no_slug': 'Ορίστε τη διεύθυνση του site για να δείτε στατιστικά', 'profile.site.edit_bio_hint': 'Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα «Βασικά».', 'status.can_help_now_hint': 'Η κάρτα σου εμφανίζεται ψηλότερα', 'status.need_help_hint': 'Οι ειδικοί μπορούν να σε βοηθήσουν', 'profile.referral.title': 'Πρόγραμμα παραπομπών', 'profile.referral.desc': 'Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.', 'profile.referral.link_label': 'Ο σύνδεσμος παραπομπής σου', 'profile.referral.copy': 'Αντιγραφή', 'profile.referral.copied': 'Αντιγράφηκε!', 'profile.referral.invited_count': 'επιτυχείς παραπομπές', 'profile.referral.no_code': 'Ο κωδικός παραπομπής δεν είναι διαθέσιμος.', 'notifications.title': 'Ρυθμίσεις ειδοποιήσεων', 'notifications.email.new_tasks': 'Email για νέες εργασίες', 'notifications.email.new_tasks.desc': 'Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου', 'notifications.messages.desc': 'Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα', 'notifications.saved': 'Ρυθμίσεις αποθηκεύτηκαν', 'notifications.plan_required': 'Συνδρομή απαιτείται για αυτή τη λειτουργία', 'profile.tab.info': 'Βασικά στοιχεία', 'profile.tab.finance': 'Οικονομικά', 'profile.tab.skills': 'Δεξιότητες', 'profile.tab.categories': 'Κατηγορίες', 'profile.tab.geography': 'Γεωγραφία', 'profile.specialist.categories': 'Κατηγορίες εργασιών', 'profile.specialist.categories.desc': 'Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι', 'profile.specialist.geography': 'Περιοχές κάλυψης', 'profile.specialist.geography.desc': 'Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι', 'profile.saving': 'Αποθήκευση...', 'profile.upload.error': 'Σφάλμα κατά την αναφόρτωση', 'profile.saved': 'Αποθηκεύτηκε', 'profile.tab.cards': 'Χαρτοφυλάκιο', 'profile.cards.count': 'Χαρτοφυλάκια', 'profile.cards.add': 'Νέο χαρτοφυλάκιο', 'profile.cards.new_title': 'Τίτλος νέου χαρτοφυλακίου', 'profile.cards.placeholder': 'π.χ. Υδραυλικά', 'profile.cards.create': 'Δημιουργία', 'profile.cards.cancel': 'Ακύρωση', 'profile.cards.empty': 'Δεν έχετε χαρτοφυλάκιο', 'profile.cards.create_first': 'Δημιουργήστε το πρώτο σας χαρτοφυλάκιο', 'profile.cards.delete_confirm': 'Διαγραφή χαρτοφυλακίου;', 'profile.card.tab.main': 'Γενικά', 'profile.card.tab.skills': 'Δεξιότητες', 'profile.card.tab.categories': 'Κατηγορίες', 'profile.card.tab.geography': 'Γεωγραφία', 'profile.card.tab.portfolio': 'Γκαλερί', 'profile.card.active': 'Ενεργή', 'profile.card.save': 'Αποθήκευση', 'profile.card.saved': 'Αποθηκεύτηκε', 'profile.card.delete': 'Διαγραφή', 'profile.card.skill.add': 'Προσθήκη δεξιότητας', 'profile.card.photo.add': 'Προσθήκη φωτογραφίας', 'profile.card.photo.uploading': 'Μεταφόρτωση...', 'profile.card.photo.empty': 'Δεν υπάρχουν φωτογραφίες', 'profile.card.item.title': 'Τίτλος', 'profile.card.item.desc': 'Περιγραφή', 'profile.card.item.save': 'Αποθήκευση', 'profile.card.item.cancel': 'Ακύρωση', 'profile.card.item.edit': 'Επεξεργασία', 'profile.upgrade.cards_limit': 'Όριο χαρτοφυλακίων εξαντλήθηκε', 'profile.upgrade.plan': 'Τρέχον πλάνο:', 'profile.upgrade.contact': 'Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου', 'profile.upgrade.ok': 'Εντάξει', 'profile.plan.title': 'Πλάνο συνδρομής', 'profile.balance': 'Υπόλοιπο', 'profile.balance.topup': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.amount': 'Ποσό (σε EUR)', 'profile.balance.topup.hint': 'Επιλέξτε ποσό ή εισαγάγετε μανούαλα', 'profile.balance.topup.submit': 'Πληρωμή', 'profile.balance.topup.loading': 'Ρεδιρεκτάρισμα...', 'profile.balance.topup.error': 'Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.', 'payment.success.title': 'Πληρωμή επιτυχής!', 'payment.success.desc': 'Το υπόλοιπό σας ενημερώθηκε.', 'payment.cancelled.title': 'Ακύρωση πληρωμής', 'payment.cancelled.desc': 'Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.', 'payment.pending.title': 'Σε εξέλιξη...', 'payment.pending.desc': 'Επεξεργαζόμαστε την πληρωμή σας.', 'payment.back_to_profile': 'Επιστροφή στο προφίλ', 'profile.plan.basic': 'Βασικό (δωρεάν)', 'profile.plan.contact_upgrade': 'Επικοινωνήστε με τον διαχειριστή για αναβάθμιση', 'profile.plan.cards_up_to': 'Χαρτοφυλάκια: έως', 'profile.plan.cards_unlimited': 'Χαρτοφυλάκια: απεριόριστα', 'profile.plan.tasks_up_to': 'Εργασίες: έως', 'profile.plan.offers_up_to': 'Προσφορές: έως', 'profile.plan.valid_until': 'Ισχύει έως', 'profile.plan.no_expiry': 'Δεν λήγει', // Create task 'create.error': 'Σφάλμα κατά τη δημοσίευση', // Tasks list extras 'tasks.category.general': 'Γενικά', 'tasks.budget.range': 'Εύρος:', 'tasks.budget.from': 'από', 'tasks.budget.to': 'έως', 'tasks.filter.reset': 'Εκκαθάριση φίλτρων', 'tasks.load_more': 'Φόρτωση ακόμα', 'tasks.showing': 'Αποτελέσματα:', 'tasks.field.budget': 'Προϋπολογισμός, €', // Admin 'admin.title': 'Πίνακας Διαχείρισης', 'admin.tab.stats': 'Στατιστικά', 'admin.tab.users': 'Χρήστες', 'admin.tab.tasks': 'Εργασίες', 'admin.tab.reports': 'Αναφορές', 'admin.stats.users': 'Χρήστες', 'admin.stats.tasks': 'Εργασίες', 'admin.stats.offers': 'Προσφορές', 'admin.stats.reviews': 'Αξιολογήσεις', 'admin.tasks.by_status': 'Εργασίες ανά κατάσταση', 'admin.col.user': 'Χρήστης', 'admin.col.email': 'Email', 'admin.col.role': 'Ρόλος', 'admin.col.registered': 'Εγγραφή', 'admin.col.status': 'Κατάσταση', 'admin.col.title': 'Τίτλος', 'admin.col.budget': 'Προϋπολογισμός', 'admin.col.created': 'Δημιουργία', 'admin.users.active': 'Ενεργός', 'admin.users.inactive': 'Ανενεργός', 'admin.users.deactivate': 'Απενεργοποίηση', 'admin.users.activate': 'Ενεργοποίηση', 'admin.tasks.cancel': 'Ακύρωση', 'admin.reports.none': 'Δεν υπάρχουν αναφορές', 'admin.reports.reviewed': 'Αναθεωρήθηκε', 'admin.reports.dismiss': 'Απόρριψη', 'admin.pagination.total': 'Σύνολο', 'admin.users.role.change': 'Αλλαγή ρόλου', 'admin.users.search.placeholder': 'Αναζήτηση ονόματος ή email...', 'admin.tasks.delete': 'Διαγραφή', 'admin.tasks.delete.confirm': 'Διαγραφή αυτής της εργασίας μόνιμα;', 'admin.tasks.search.placeholder': 'Αναζήτηση τίτλου...', 'admin.col.customer': 'Πελάτης', 'admin.col.reporter': 'Καταγγέλλων', 'admin.col.target': 'Στόχος', 'admin.filter.all_roles': 'Όλοι οι ρόλοι', 'admin.filter.all_statuses': 'Όλες οι καταστάσεις', 'admin.reports.target.task': 'Εργασία', 'admin.reports.target.user': 'Χρήστης', 'admin.tab.categories': 'Κατηγορίες', 'admin.tab.locations': 'Πόλεις & Περιοχές', 'admin.tab.logs': 'Αρχεία', 'admin.tab.plans': 'Πακέτα', 'admin.tab.settings': 'Ρυθμίσεις', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Δραστηριότητα', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Ειδοποιήσεις', 'admin.notif_logs.type': 'Τύπος', 'admin.notif_logs.title': 'Τίτλος', 'admin.notif_logs.read': 'Διαβασμένο', 'admin.notif_logs.empty': 'Δεν υπάρχουν αρχεία ειδοποιήσεων', 'admin.stats.notif_chart_title': 'Ειδοποιήσεις ανά ημέρα', 'admin.stats.notif_label': 'Ειδοποιήσεις', 'admin.stats.mail_chart_title': 'Emails ανά ημέρα', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Όλα', 'admin.stats.specialists': 'Ειδικοί', 'admin.col.plan': 'Πακέτο', 'admin.back_home': 'Αρχική', 'admin.plans.title': 'Πακέτα συνδρομής', 'admin.plans.add': '+ Νέο πακέτο', 'admin.plans.empty': 'Δεν υπάρχουν πακέτα', 'admin.plans.form.new': 'Νέο πακέτο', 'admin.plans.form.edit': 'Επεξεργασία πακέτου', 'admin.plans.form.name': 'Όνομα', 'admin.plans.form.price': 'Τιμή (EUR)', 'admin.plans.form.old_price': 'Παλιά τιμή (EUR, προαιρετικό)', 'admin.plans.form.max_offers': 'Μέγ. προσφορές (κενό = χωρίς όριο)', 'admin.plans.form.max_cards': 'Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)', 'admin.plans.form.duration_days': 'Διάρκεια (ημέρες, κενό = χωρίς λήξη)', 'admin.plans.form.description': 'Περιγραφή', 'admin.plans.form.features': 'Δυνατότητες (μία ανά γραμμή)', 'admin.plans.form.notify': 'Ειδοποιήσεις νέων εργασιών', 'admin.plans.form.default': 'Προεπιλογή', 'admin.plans.form.active': 'Ενεργό', 'admin.plans.form.order': 'Σειρά', 'admin.plans.form.role': 'Ρόλος', 'admin.plans.form.tier': 'Επίπεδο', 'admin.plans.form.role.customer': 'Πελάτης', 'admin.plans.form.role.specialist': 'Ειδικός', 'admin.plans.form.tier.free': 'Δωρεάν', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Όρια (κενό = χωρίς όριο)', 'admin.plans.form.max_messages_day': 'Μέγ. μηνύματα/ημέρα', 'admin.plans.form.max_orders_day': 'Μέγ. παραγγελίες/ημέρα', 'admin.plans.form.max_skills': 'Μέγ. δεξιότητες', 'admin.plans.form.max_profiles': 'Μέγ. προφίλ', 'admin.plans.form.max_portfolio': 'Μέγ. στοιχεία χαρτοφυλακίου', 'admin.plans.form.section.boost': 'Πολλαπλασιαστές & Ενίσχυση', 'admin.plans.form.search_boost': 'Ενίσχυση αναζήτησης', 'admin.plans.form.offers_multiplier': 'Πολλαπλασιαστής προσφορών', 'admin.plans.form.section.contact': 'Δικαιώματα επικοινωνίας', 'admin.plans.form.can_contact_free': 'Επικοινωνία με δωρεάν χρήστες', 'admin.plans.form.can_contact_pro': 'Επικοινωνία με Pro χρήστες', 'admin.plans.form.can_contact_all': 'Επικοινωνία με όλους', 'admin.plans.form.can_show_contact': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.plans.form.can_view_phone': 'Προβολή τηλεφώνου', 'admin.plans.form.section.features': 'Λειτουργίες', 'admin.plans.form.upload_video': 'Μεταφόρτωση βίντεο', 'admin.plans.form.favorites': 'Αγαπημένα', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Σήμα επαλήθευσης', 'admin.plans.form.highlighted_reviews': 'Προβεβλημένες κριτικές', 'admin.plans.form.personal_site': 'Προσωπική σελίδα', 'admin.plans.form.can_help_now': 'Κατάσταση «Μπορώ να βοηθήσω»', 'admin.plans.form.need_help': 'Κατάσταση «Χρειάζομαι βοήθεια»', 'admin.plans.form.auto_response': 'Αυτόματη απάντηση', 'admin.plans.form.auto_match': 'Αυτόματη αντιστοίχιση', 'admin.plans.form.instant_dispatch_free': 'Άμεση αποστολή (δωρεάν)', 'admin.plans.form.instant_dispatch_pro': 'Άμεση αποστολή (Pro)', 'admin.plans.badge.default': 'Προεπιλογή', 'admin.plans.badge.inactive': 'Ανενεργό', 'admin.plans.make_default': 'Ορισμός ως προεπιλογή', 'admin.plans.tasks': 'Εργασίες', 'admin.plans.offers': 'Προσφορές', 'admin.plans.cards': 'Χαρτοφυλάκιο', 'admin.plans.notify_tasks': 'Ειδοποιήσεις εργασιών', 'admin.plans.delete.confirm': 'Διαγραφή πακέτου', 'admin.activity.title': 'Αρχείο δραστηριότητας', 'admin.activity.event': 'Γεγονός', 'admin.activity.all_events': 'Όλα τα γεγονότα', 'admin.activity.from': 'Από', 'admin.activity.to': 'Έως', 'admin.activity.reset': 'Επαναφορά', 'admin.activity.total': 'Σύνολο', 'admin.activity.empty': 'Δεν υπάρχουν εγγραφές', 'admin.mail.event': 'Συμβάν email', 'admin.mail.all_events': 'Όλα τα email συμβάντα', 'admin.mail.from': 'Από', 'admin.mail.to': 'Έως', 'admin.mail.reset': 'Επαναφορά', 'admin.mail.total': 'Σύνολο', 'admin.mail.empty': 'Δεν υπάρχουν email logs', 'admin.mail.recipient': 'Παραλήπτης', 'admin.mail.provider': 'Πάροχος', 'admin.mail.details': 'Λεπτομέρειες', 'admin.mail.status': 'Κατάσταση', 'admin.mail.success': 'Επιτυχία', 'admin.mail.failed': 'Σφάλμα', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'Δεν υπάρχουν εγγραφές', 'admin.logs.date': 'Ημερομηνία', 'admin.logs.provider': 'Πάροχος', 'admin.logs.model': 'Μοντέλο', 'admin.logs.action': 'Ενέργεια', 'admin.logs.langs': 'Γλώσσες', 'admin.logs.in': 'Είσοδος', 'admin.logs.out': 'Έξοδος', 'admin.logs.total': 'Σύνολο', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Κατάσταση', 'admin.stats.activity_30d': 'Δραστηριότητα 30 ημερών', 'admin.stats.tasks_label': 'Εργασίες', 'admin.stats.users_label': 'Χρήστες', 'admin.stats.specialists_label': 'Ειδικοί', 'admin.stats.tokens_title': 'Χρήση tokens (ανά μήνα)', 'admin.stats.tokens_out': 'Εξερχόμενα', 'admin.stats.tokens_in': 'Εισερχόμενα', 'admin.stats.tokens_out_label': 'Εξερχόμενα tokens', 'admin.stats.tokens_in_label': 'Εισερχόμενα tokens', 'admin.stats.cost_label': 'Κόστος (USD)', 'admin.stats.tasks_by_status': 'Εργασίες ανά κατάσταση', 'admin.task_status.open': 'Ανοιχτές', 'admin.task_status.in_progress': 'Σε εξέλιξη', 'admin.task_status.completed': 'Ολοκληρωμένες', 'admin.task_status.cancelled': 'Ακυρωμένες', 'admin.task_status.draft': 'Προσχέδια', 'admin.settings.tab.general': 'Γενικά', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Ειδοποιήσεις', 'admin.settings.tab.payment': 'Πληρωμή', 'admin.settings.tab.referral': 'Παραπομπές', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Κοινωνικά δίκτυα', 'admin.settings.socials.title': 'Σύνδεσμοι κοινωνικών δικτύων', 'admin.settings.socials.hint': 'Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο', 'admin.settings.seo.maintenance_label': 'Λειτουργία συντήρησης', 'admin.settings.seo.maintenance_hint': 'Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες', 'admin.settings.seo.indexing_label': 'Ευρετηρίαση από μηχανές αναζήτησης', 'admin.settings.seo.indexing_hint': 'Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο', 'admin.settings.seo.head_scripts_label': 'Scripts στο (JS)', 'admin.settings.seo.head_scripts_hint': 'Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)', 'admin.settings.seo.site_title_label': 'Τίτλος ιστότοπου', 'admin.settings.seo.site_description_label': 'Περιγραφή ιστότοπου (meta description)', 'admin.settings.referral.title': 'Πρόγραμμα παραπομπών', 'admin.settings.referral.hint': 'Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.', 'admin.settings.referral.enabled_label': 'Ενεργό', 'admin.settings.referral.enabled_hint': 'Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών', 'admin.settings.referral.customer_section': 'Για πελάτες', 'admin.settings.referral.specialist_section': 'Για ειδικούς', 'admin.settings.referral.plan_label': 'Πλάνο ανταμοιβής', 'admin.settings.referral.no_plan': '— χωρίς πλάνο —', 'admin.settings.referral.plan_hint': 'Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.', 'admin.settings.referral.days_label': 'Ημέρες ανταμοιβής', 'admin.settings.referral.days_hint': 'Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.', 'admin.settings.general.title': 'Γενικές ρυθμίσεις', 'admin.settings.general.site_name': 'Όνομα ιστότοπου', 'admin.settings.general.site_url': 'URL ιστότοπου', 'admin.settings.general.contact_email': 'Email επικοινωνίας', 'admin.settings.general.support_phone': 'Τηλέφωνο υποστήριξης', 'admin.settings.smtp.title': 'Ρυθμίσεις SMTP', 'admin.settings.smtp.hint': 'Χρησιμοποιείται για αποστολή ειδοποιήσεων email.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Θύρα', 'admin.settings.smtp.encryption': 'Κρυπτογράφηση', 'admin.settings.smtp.enc.none': 'Χωρίς', 'admin.settings.smtp.enc.tls': 'STARTTLS (θύρα 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (θύρα 465)', 'admin.settings.smtp.username': 'Όνομα χρήστη', 'admin.settings.smtp.password': 'Κωδικός / App Password', 'admin.settings.smtp.from_name': 'Όνομα αποστολέα', 'admin.settings.smtp.from_email': 'Email αποστολέα', 'admin.settings.smtp.test': 'Αποστολή δοκιμαστικού email', 'admin.settings.smtp.sending': 'Αποστολή...', 'admin.settings.payment.hint': 'Τα στοιχεία για ePay Piraeus Bank.', 'admin.settings.env.test': 'Δοκιμαστικό (sandbox)', 'admin.settings.env.prod': 'Παραγωγή', 'admin.settings.env.label': 'Περιβάλλον', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Ενεργό', 'admin.settings.saving': 'Αποθήκευση...', 'admin.settings.saved': '✓ Αποθηκεύτηκε', 'admin.notif.vars_hint': 'Διαθέσιμες μεταβλητές στα πρότυπα', 'admin.notif.tmpl.not_set': 'Πρότυπο δεν έχει οριστεί', 'admin.notif.tmpl.subject_label': 'Θέμα email', 'admin.notif.tmpl.body_label': 'Κείμενο email (HTML)', 'admin.notif.tmpl.save': 'Αποθήκευση', 'admin.notif.tmpl.close': 'Κλείσιμο', 'admin.notif.tmpl.translate': 'Αυτόματη μετάφραση', 'admin.notif.tmpl.translating': 'Μετάφραση...', 'admin.notif.tmpl.saving': 'Αποθήκευση...', 'admin.notif.email_verification': 'Επαλήθευση email', 'admin.notif.registration_success': 'Επιτυχής εγγραφή', 'admin.notif.password_reset': 'Επαναφορά κωδικού', 'admin.notif.new_offer': 'Νέα προσφορά', 'admin.notif.new_task': 'Νέα εργασία', 'admin.notif.offer_accepted': 'Προσφορά αποδεκτή', 'admin.notif.new_message': 'Νέο μήνυμα', 'admin.notif.offer_declined': 'Απόρριψη προσφοράς', 'admin.notif.offer_other_accepted': 'Επιλέχθηκε άλλος ειδικός', 'admin.notif.task_updated': 'Ενημέρωση εργασίας', 'admin.notif.deadline_reminder': 'Υπενθύμιση προθεσμίας', 'admin.notif.task_archived': 'Αυτόματη απόσυρση εργασίας', 'admin.notif.referral_reward': 'Ανταμοιβή παραπομπής', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Τιμολόγιο — ενεργοποίηση πλάνου', 'admin.email_template.plan_upgraded': 'Τιμολόγιο — αναβάθμιση πλάνου', 'admin.email_template.plan_downgrade_scheduled': 'Τιμολόγιο — προγραμματισμένη υποβάθμιση', 'admin.email_template.plan_downgrade_applied': 'Τιμολόγιο — εφαρμογή υποβάθμισης', 'admin.email_template.plan_renewal_reminder': 'Τιμολόγιο — υπενθύμιση ανανέωσης', 'admin.email_template.plan_insufficient_funds': 'Τιμολόγιο — ανεπαρκές υπόλοιπο', // Pricing confirm modal 'pricing.confirm.title': 'Επιβεβαίωση επιλογής πλάνου', 'pricing.confirm.plan': 'Πλάνο', 'pricing.confirm.prorated': 'Αναλογική έκπτωση', 'pricing.confirm.effective_price': 'Προς πληρωμή', 'pricing.confirm.your_balance': 'Το υπόλοιπό σας', 'pricing.confirm.downgrade_info': 'Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.', 'pricing.confirm.insufficient': 'Ανεπαρκές υπόλοιπο.', 'pricing.confirm.top_up': 'Ανανέωση', 'pricing.confirm.schedule_downgrade': 'Προγραμματισμός μετάβασης', 'pricing.confirm.pay': 'Πληρωμή', 'admin.user_edit.title': 'Επεξεργασία χρήστη', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Διευθυνση email επαληθεύτηκε', 'admin.user_edit.email_not_verified': 'Email δεν έχει επαληθευτεί', 'admin.user_edit.verify_email_btn': 'Χειροκίνητη επαλήθευση', 'admin.user_edit.verify_email_done': 'Email επαληθεύτηκε!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Εγγραφή', 'admin.user_edit.last_seen': 'Τελευταία σύνδεση', 'admin.user_edit.lang': 'Γλώσσα', 'admin.user_edit.first_name': 'Όνομα', 'admin.user_edit.last_name': 'Επώνυμο', 'admin.user_edit.phone': 'Τηλέφωνο', 'admin.user_edit.bio': 'Βιογραφικό', 'admin.user_edit.role': 'Ρόλος', 'admin.user_edit.plan': 'Πακέτο', 'admin.user_edit.no_plan': '— Χωρίς πακέτο —', 'admin.user_edit.active': 'Ενεργός λογαριασμός', 'admin.user_edit.balance': 'Υπόλοιπο (EUR)', 'admin.user_edit.skills': 'Δεξιότητες', 'admin.user_edit.tab.profile': 'Προφίλ', 'admin.user_edit.tab.account': 'Λογαριασμός', 'admin.user_edit.tab.balance': 'Υπόλοιπο', 'admin.user_edit.tab.settings': 'Ρυθμίσεις', 'admin.user_edit.tab.specialist': 'Χαρτοφυλάκιο', 'admin.user_edit.tab.site': 'Ιστοσελίδα', 'admin.user_edit.plan_expires': 'Λήξη πλάνου', 'admin.user_edit.interface_lang': 'Γλώσσα διεπαφής', 'admin.user_edit.comm_languages': 'Γλώσσες επικοινωνίας', 'admin.user_edit.personal_site_slug': 'Προσωπική σελίδα', 'admin.user_edit.show_contact_info': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.user_edit.show_contact_info.hint': 'Ορατό στους πελάτες', 'admin.user_edit.notify_new_tasks': 'Ειδοποίηση για νέες εργασίες', 'admin.user_edit.notify_new_tasks.hint': 'Push και email ειδοποιήσεις', 'admin.user_edit.notif_messages': 'Ειδοποιήσεις μηνυμάτων', 'admin.user_edit.notif_messages.hint': 'Νέα μηνύματα στη συνομιλία', 'admin.user_edit.site_settings': 'Ρυθμίσεις προσωπικής σελίδας', 'admin.user_edit.categories': 'Κατηγορίες υπηρεσιών', 'admin.user_edit.locations': 'Περιοχές εξυπηρέτησης', 'admin.user_edit.skill_placeholder': 'Νέα δεξιότητα...', 'admin.user_edit.add_category': '— Επιλέξτε κατηγορία —', 'admin.user_edit.add_location': '— Επιλέξτε περιοχή —', 'admin.user_edit.specialist_cards': 'Χαρτοφυλάκιο ειδικού', 'admin.user_edit.no_cards': 'Δεν βρέθηκαν στοιχεία χαρτοφυλακίου', 'admin.user_edit.card_title': 'Τίτλος χαρτοφυλακίου', 'admin.user_edit.card_description': 'Περιγραφή', 'admin.balance.topup.btn': 'Αναπλήρωση', 'admin.balance.withdraw.btn': 'Αφαίρεση', 'admin.balance.modal_hint': 'Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό', 'admin.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'admin.balance.topup.amount': 'Ποσό', 'admin.balance.topup.description': 'Σχόλιο', 'admin.balance.topup.description.placeholder': 'Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση', 'admin.balance.topup.submit': 'Αναπλήρωση υπολοίπου', 'admin.balance.withdraw.title': 'Αφαίρεση υπολοίπου', 'admin.balance.withdraw.amount': 'Ποσό', 'admin.balance.withdraw.description': 'Σχόλιο', 'admin.balance.withdraw.description.placeholder': 'Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση', 'admin.balance.withdraw.submit': 'Αφαίρεση από το υπόλοιπο', 'admin.user_edit.role.customer': 'Πελάτης', 'admin.user_edit.role.specialist': 'Ειδικός', 'admin.user_edit.role.admin': 'Διαχειριστής', 'common.refresh': 'Ανανέωση', 'common.back_home': 'Αρχική', 'admin.loc.hint': 'Διαχείριση πόλεων και συνοικιών', 'admin.loc.add_city': 'Νέα πόλη', 'admin.loc.add_district': 'Προσθήκη συνοικίας', 'admin.loc.new': 'Νέα τοποθεσία', 'admin.loc.edit': 'Επεξεργασία τοποθεσίας', 'admin.loc.district': 'συνοικία', 'admin.loc.empty': 'Δεν υπάρχουν τοποθεσίες', 'admin.loc.delete.confirm': 'Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.', 'admin.cat.add_root': 'Νέα κατηγορία', 'admin.cat.add_sub': 'Υποκατηγορία', 'admin.cat.edit': 'Επεξεργασία', 'admin.cat.delete': 'Διαγραφή', 'admin.cat.delete.confirm': 'Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Εικονίδιο', 'admin.cat.name_el': 'Ελληνικά', 'admin.cat.name_en': 'Αγγλικά', 'admin.cat.name_ru': 'Ρωσικά', 'admin.cat.order': 'Σειρά', 'admin.cat.active': 'Ενεργή', 'admin.cat.parent': 'Γονική κατηγορία', 'admin.cat.no_parent': 'Κορυφαίο επίπεδο', 'admin.cat.save': 'Αποθήκευση', 'admin.cat.cancel': 'Ακύρωση', 'admin.cat.empty': 'Δεν υπάρχουν κατηγορίες', 'admin.cat.hint': 'Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία', 'admin.cat.new': 'Νέα κατηγορία', 'admin.cat.subcategory': 'υποκατηγορία', 'admin.cat.add_child': 'Προσθήκη υποκατηγορίας', 'admin.cat.inactive': 'Ανενεργή', 'admin.event.user_login': 'Σύνδεση', 'admin.event.user_register': 'Εγγραφή', 'admin.event.admin_user_deactivate': 'Αποκλεισμός χρήστη', 'admin.event.admin_user_activate': 'Ενεργοποίηση χρήστη', 'admin.event.admin_user_role_changed': 'Αλλαγή ρόλου', 'admin.event.admin_task_cancelled': 'Ακύρωση εργασίας', 'admin.event.admin_task_deleted': 'Διαγραφή εργασίας', 'admin.event.admin_report_reviewed': 'Αναφορά εξετάστηκε', 'admin.event.admin_report_dismissed': 'Αναφορά απορρίφθηκε', 'admin.event.task_created': 'Δημιουργία εργασίας', 'user.online': 'Σε σύνδεση', 'user.seen_minutes': 'ήταν εδώ πριν {n} λεπτά', 'user.seen_hours': 'ήταν εδώ πριν {n} ώρες', 'user.seen_yesterday': 'ήταν εδώ χθες', 'user.seen_days': 'ήταν εδώ πριν {n} μέρες', // Specialists 'specialists.title': 'Ειδικοί', 'specialists.search': 'Αναζήτηση ειδικού...', 'specialists.search.btn': 'Αναζήτηση', 'specialists.empty': 'Δεν βρέθηκαν ειδικοί', 'specialists.no_bio': 'Χωρίς περιγραφή', 'specialists.view': 'Προβολή προφίλ', 'specialists.reviews': 'αξιολογήσεις', 'specialist.favorite': 'Προσθήκη στα αγαπημένα', 'specialist.unfavorite': 'Αφαίρεση από αγαπημένα', 'specialist.site_link': 'Προσωπικό site', 'favorites.specialists.title': 'Αγαπημένοι ειδικοί', 'favorites.specialists.empty': 'Δεν έχετε αγαπημένους ειδικούς', 'nav.favorites': 'Αγαπημένα', 'nav.schedule': 'Πρόγραμμα', 'nav.find_tasks': 'Αναζήτηση εργασιών', 'schedule.title': 'Το πρόγραμμά μου', 'schedule.subtitle': 'Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας', 'schedule.available': 'Ελεύθερος', 'schedule.busy': 'Απασχολημένος', 'schedule.unset': 'Μη ορισμένο', 'schedule.click_hint': '← κλικ για εναλλαγή κατάστασης', 'schedule.range_mode': 'Επιλογή εύρους', 'schedule.range_from': 'Από {date} — επιλέξτε τελική ημερομηνία', 'schedule.click_to_set': 'Κλικ για ορισμό', 'schedule.free': 'ελεύθερα', 'schedule.busy_count': 'απασχολημένα', 'schedule.free_days': 'ελεύθερες ημέρες', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Σύνδεση με Google Calendar', 'schedule.disconnectGoogle': 'Αποσύνδεση', 'schedule.connectedAs': 'Συνδεδεμένο ως', 'schedule.importFromGoogle': 'Συγχρονισμός από Google', 'schedule.gcalConnected': '✓ Google Calendar συνδέθηκε', 'schedule.gcalError': 'Σφάλμα σύνδεσης Google Calendar', 'schedule.gcalImportDone': 'Εισήχθησαν {n} ημερ. από Google Calendar', 'schedule.gcalAutoSyncNote': 'Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar', 'schedule.gcalConnectDesc': 'Συνδέστε το Google Calendar για αυτόματο συγχρονισμό', 'schedule.gcalDisconnectConfirm': 'Αποσύνδεση Google Calendar;', 'find_tasks.title': 'Αναζήτηση εργασιών', 'find_tasks.for_me': 'Για μένα', 'find_tasks.all': 'Όλες οι εργασίες', 'find_tasks.by_category': 'Ανά κατηγορία', 'find_tasks.list': 'Λίστα', 'find_tasks.already_offered': 'Προσφορά υποβλήθηκε', 'find_tasks.offer_now': 'Υποβολή προσφοράς', 'find_tasks.empty_for_me': 'Δεν βρέθηκαν εργασίες στις κατηγορίες σας', 'find_tasks.banner_hint': 'Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας', 'find_tasks.no_cards': 'Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς', 'find_tasks.add_card': 'Δημιουργία χαρτοφυλακίου', 'find_tasks.search': 'Αναζήτηση εργασιών...', 'find_tasks.tasks_count': 'εργασίες', // Footer 'footer.tagline': 'Η πλατφόρμα εργασιών για την Ελλάδα', 'footer.rights': 'Όλα τα δικαιώματα διατηρούνται.', // App download section 'app.download_title': 'Κατεβάστε την εφαρμογή CanHelp', 'app.download_desc': 'Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.', // Nav 'nav.pricing': 'Τιμές', // Pricing page 'pricing.title': 'Τιμολόγηση', 'pricing.subtitle': 'Επιλέξτε το κατάλληλο πρόγραμμα', 'pricing.role.customer': 'Πελάτης', 'pricing.role.specialist': 'Ειδικός', 'pricing.free': 'Δωρεάν', 'pricing.per_month': 'μήνα', 'pricing.duration': 'Διάρκεια', 'pricing.days': 'ημ.', 'pricing.current_plan': 'Το πρόγραμμά σας', 'pricing.popular': 'Δημοφιλές', 'pricing.choose': 'Επιλογή', 'pricing.your_plan': 'Ενεργό πρόγραμμα', 'pricing.free_default': 'Προεπιλογή', 'pricing.compare': 'Σύγκριση λειτουργιών', 'pricing.feature': 'Λειτουργία', 'pricing.faq_note': 'Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.', 'pricing.feat.messages': 'Μηνύματα / ημέρα', 'pricing.feat.orders': 'Παραγγελίες / ημέρα', 'pricing.feat.contact_all': 'Επικοινωνία με όλους', 'pricing.feat.view_phone': 'Εμφάνιση τηλεφώνου', 'pricing.feat.show_contact': 'Εμφάνιση στοιχείων επαφής', 'pricing.feat.favorites': 'Αγαπημένα', 'pricing.feat.verified_badge': 'Επαληθευμένο badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Προσωπικό site', 'pricing.feat.auto_response': 'Αυτόματη απάντηση', 'pricing.feat.auto_match': 'Αυτόματη αντιστοίχιση', 'pricing.feat.highlighted_reviews': 'Επισημασμένες αξιολογήσεις', 'pricing.feat.portfolio': 'Στοιχεία χαρτοφυλακίου', 'pricing.feat.cards': 'Κάρτες ειδικού', 'pricing.feat.notify_tasks': 'Ειδοποιήσεις νέων εργασιών', 'pricing.feat.video': 'Βίντεο στο χαρτοφυλάκιο', // Upgrade prompt 'upgrade.available_in': 'Διαθέσιμο στο', 'upgrade.cta': 'Αναβάθμιση', // Dashboard plan block 'dashboard.plan.title': 'Το πρόγραμμά μου', 'dashboard.plan.expires': 'Λήγει σε {n} ημέρες', 'dashboard.plan.upgrade': 'Αναβάθμιση προγράμματος', 'dashboard.plan.no_plan': 'Δωρεάν πρόγραμμα', 'dashboard.plan.messages': 'Μηνύματα σήμερα', 'dashboard.plan.orders': 'Παραγγελίες σήμερα', 'dashboard.plan.limits': 'Ημερήσια όρια', 'dashboard.plan.features': 'Λειτουργίες', 'dashboard.plan.stats': 'Στατιστικά', 'dashboard.stats.cards': 'Χαρτοφυλάκια', 'dashboard.stats.maxCards': 'Μέγ. χαρτοφυλάκια', 'dashboard.stats.portfolioItems': 'Στοιχεία portfolio', 'dashboard.stats.maxPortfolioItems': 'Μέγ. στοιχεία', 'dashboard.stats.activeOffers': 'Ενεργές προσφορές', 'dashboard.stats.reviewsReceived': 'Αξιολογήσεις', 'dashboard.stats.activeTasks': 'Ενεργές εργασίες', 'dashboard.stats.completedTasks': 'Ολοκληρωμένες', 'status.can_help_now': 'Είμαι διαθέσιμος τώρα', 'status.need_help': 'Χρειάζομαι βοήθεια', 'status.active': 'Ενεργό', 'status.toggle_on': 'Ενεργοποίηση', 'status.toggle_off': 'Απενεργοποίηση', // FOMO 'fomo.missed_orders': 'Χάσατε {n} παραγγελίες', 'fomo.missed_value': 'Αξία €{v}', 'fomo.upgrade_hint': 'Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες', 'fomo.conversion': 'Μετατροπές εργασιών', 'fomo.active': 'Ενεργές', 'fomo.with_offers': 'Με προσφορές', 'fomo.completed': 'Ολοκληρωμένες', 'fomo.already_offered': '{n} ειδικοί έχουν ήδη απαντήσει', 'fomo.specialist_missed': 'Χάσατε {n} παραγγελίες', 'fomo.top_categories': 'Κατηγορίες', 'fomo.offers_received': 'προσφορές ελήφθησαν', 'fomo.avg_offers': 'Μέσο {n}/εργασία', 'fomo.completion_rate': 'ολοκληρωμένες', // Task auto-match 'task.auto_match': 'Αυτόματη αντιστοίχιση', 'task.auto_match_results': 'Κορυφαίοι ειδικοί', 'task.no_offer_yet': 'Δεν έχετε στείλει προσφορά ακόμα', 'task.make_offer': 'Αποστολή προσφοράς', 'auto_response.title': 'Αυτόματη Απάντηση', 'auto_response.enabled': 'Ενεργοποίηση αυτόματης απάντησης', 'auto_response.min_budget': 'Ελάχ. προϋπολογισμός', 'auto_response.max_budget': 'Μέγ. προϋπολογισμός', 'auto_response.default_price': 'Προεπιλεγμένη τιμή', 'auto_response.default_message': 'Προεπιλεγμένο μήνυμα', 'auto_response.max_per_day': 'Μέγ. αυτόματες προσφορές/ημέρα', 'auto_response.save': 'Αποθήκευση', 'auto_response.saved': 'Αποθηκεύτηκε', 'auto_response.categories': 'Κατηγορίες', 'auto_response.locations': 'Τοποθεσίες', // Personal site 'profile.personal_site': 'Προσωπικό Site', 'profile.site_slug': 'Slug URL', 'profile.site_slug_hint': 'Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _', 'profile.site_open': 'Άνοιγμα site', 'profile.site_preview': 'Το site σας', 'profile.show_contact': 'Εμφάνιση στοιχείων επαφής', 'profile.show_contact_hint': 'Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας', // Google Calendar plan gate 'gcal.upgrade_required': 'Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα', // Chat limits 'chat.limit_warning': 'Απομένουν {n} μηνύματα σήμερα', 'chat.limit_reached': 'Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας', 'chat.upgrade': 'Αναβάθμιση', // Site page 'site.member_since': 'Μαζί μας από', 'site.rating': 'Βαθμολογία', 'site.completed_tasks': 'Ολοκληρώθηκαν', 'site.languages': 'Γλώσσες', 'site.photos': 'φωτ.', 'site.contact_form': 'Επικοινωνία', 'site.contact_sent': 'Το μήνυμα στάλθηκε!', 'site.contact_sent_desc': 'Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα', 'site.contact_name': 'Όνομα', 'site.contact_name_ph': 'Το όνομά σας', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Μήνυμα', 'site.contact_message_ph': 'Περιγράψτε την εργασία σας...', 'site.contact_send': 'Αποστολή', 'site.share': 'Κοινοποίηση', 'site.speaks_languages': 'Μιλάει', 'site.message_sent': 'Το μήνυμα εστάλη!', 'site.message_sent_desc': 'Ο ειδικός θα το λάβει στη συνομιλία', 'site.message_placeholder': 'Γράψτε το μήνυμά σας...', 'site.write_to_chat': 'Γράψτε στο chat', 'site.auth_required_title': 'Απαιτείται σύνδεση', 'site.auth_required_desc': 'Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.', 'site.auth_login_btn': 'Σύνδεση', 'site.auth_contact_form_btn': 'Επικοινωνία μέσω φόρμας', 'specialist.services': 'Υπηρεσίες', 'portfolio.title': 'Χαρτοφυλάκιο', 'common.not_found': 'Η σελίδα δεν βρέθηκε', 'common.anonymous': 'Ανώνυμα', 'specialist_setup.page_title': 'Ρύθμιση προφίλ ειδικού', 'specialist_setup.step_of': 'Βήμα {current} από {total}', 'specialist_setup.next': 'Επόμενο', 'specialist_setup.back': 'Πίσω', 'specialist_setup.skip': 'Παράλειψη', 'specialist_setup.finish': 'Ολοκλήρωση', 'specialist_setup.go_to_profile': 'Μεταβείτε στο προφίλ', 'specialist_setup.browse_tasks': 'Εξερεύνηση εργασιών', 'specialist_setup.step1.title': 'Καλωσήλθατε!', 'specialist_setup.step1.subtitle': 'Ας ρυθμίσουμε το προφίλ σας', 'specialist_setup.step1.desc': 'Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.', 'specialist_setup.step1.what_next': 'Τι θα κάνουμε:', 'specialist_setup.step1.item1': 'Συμπλήρωση βασικών πληροφοριών', 'specialist_setup.step1.item2': 'Δημιουργία κάρτας υπηρεσίας', 'specialist_setup.step1.item3': 'Προσθήκη δεξιοτήτων και κατηγοριών', 'specialist_setup.step1.item4': 'Επιλογή γεωγραφικής περιοχής', 'specialist_setup.step1.item5': 'Μεταφόρτωση φωτογραφιών χαρτοφυλακίου', 'specialist_setup.step2.title': 'Βασικό προφίλ', 'specialist_setup.step2.subtitle': 'Πείτε μας για σας', 'specialist_setup.step2.bio_label': 'Σχετικά με εμένα', 'specialist_setup.step2.bio_placeholder': 'Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...', 'specialist_setup.step2.phone_label': 'Τηλέφωνο', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Φωτογραφία προφίλ', 'specialist_setup.step2.photo_btn': 'Μεταφόρτωση φωτογραφίας', 'specialist_setup.step2.photo_uploading': 'Μεταφόρτωση...', 'specialist_setup.step2.photo_hint': 'Εμφανίζεται στο προφίλ σας', 'specialist_setup.step3.title': 'Κάρτα υπηρεσίας', 'specialist_setup.step3.subtitle': 'Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας', 'specialist_setup.step3.title_label': 'Τίτλος κάρτας', 'specialist_setup.step3.title_placeholder': 'Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...', 'specialist_setup.step3.desc_label': 'Περιγραφή', 'specialist_setup.step3.desc_placeholder': 'Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...', 'specialist_setup.step3.title_required': 'Απαιτείται τίτλος', 'specialist_setup.step4.title': 'Δεξιότητες & Κατηγορίες', 'specialist_setup.step4.subtitle': 'Προσθέστε δεξιότητες και επιλέξτε κατηγορίες', 'specialist_setup.step4.skills_label': 'Δεξιότητες', 'specialist_setup.step4.skills_placeholder': 'Π.χ. Εγκατάσταση σωληνώσεων...', 'specialist_setup.step4.skills_add': 'Προσθήκη', 'specialist_setup.step4.categories_label': 'Κατηγορίες', 'specialist_setup.step5.title': 'Γεωγραφική περιοχή', 'specialist_setup.step5.subtitle': 'Πού παρέχετε υπηρεσίες;', 'specialist_setup.step5.hint': 'Επιλέξτε πόλεις ή συγκεκριμένες περιοχές', 'specialist_setup.done.title': 'Το προφίλ σας είναι έτοιμο!', 'specialist_setup.done.subtitle': 'Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί', 'specialist_setup.done.desc': 'Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας.' }, en: { 'footer.slogan': 'Your task — our care! We solve any issue quickly and easily.', 'footer.links': 'Links', 'footer.socials': 'Socials', 'nav.home': 'Home', 'nav.tasks': 'Tasks', 'nav.post': '+ Post task', 'nav.dashboard': 'Dashboard', 'nav.chat': 'Messages', 'nav.notifications': 'Notifications', 'nav.profile': 'Profile', 'nav.admin': 'Admin Panel', 'nav.specialists': 'Specialists', 'nav.new_task': 'New task', 'nav.login': 'Login', 'nav.register': 'Register', 'nav.logout': 'Logout', 'hero.title': 'Find a specialist for any job', 'hero.subtitle': 'Post a task, receive offers and choose the best professional', 'hero.cta.post': 'Post a task', 'hero.cta.browse': 'Become a specialist', 'hero.search.placeholder': 'What do you need? e.g. electrician, cleaning...', 'stats.specialists': 'specialists', 'stats.tasks': 'tasks', 'stats.categories': 'categories', 'stats.free': 'free sign-up', 'section.categories': 'Create a task in any category', 'section.how': 'How it works', 'section.recent': 'Recent tasks', 'section.all': 'See all →', 'section.more': 'more', 'section.cities': 'Cities & Districts', 'section.community': 'A community project for everyone', 'community.subtitle': 'CanHelp is not just a marketplace — it\'s a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.', 'community.point1.title': 'Are you good at something?', 'community.point1.desc': 'Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.', 'community.point2.title': 'Need help with something?', 'community.point2.desc': 'Post a task in under a minute and receive offers from verified specialists in your city.', 'community.point3.title': 'Help the project grow', 'community.point3.desc': 'CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.', 'community.share': 'Share with friends', 'community.share.copied': 'Link copied!', // Referral section on home page 'section.referral': 'Referral Program', 'referral.home.subtitle': 'Share your link — every new user who signs up through it earns you a reward.', 'referral.home.step1.title': 'Sign up and get your link', 'referral.home.step1.desc': 'Create an account and find your unique referral link in your profile.', 'referral.home.step2.title': 'Share with friends', 'referral.home.step2.desc': 'Send the link to friends, acquaintances, or post it on social media.', 'referral.home.step3.title': 'Earn rewards', 'referral.home.step3.desc': 'Once your friend verifies their email, you automatically receive your reward.', 'referral.home.cta': 'Get your link', 'referral.home.badge': 'Referral Program', // FAQ section 'section.faq': 'Frequently Asked Questions', 'faq.q1': 'How does CanHelp work?', 'faq.a1': 'Post a task, receive offers from specialists, choose the best one and start working together. It\'s fast, simple and free for customers.', 'faq.q2': 'How much does it cost to use the platform?', 'faq.a2': 'Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.', 'faq.q3': 'How can I become a specialist?', 'faq.a3': 'Register, go to «Become a Specialist», fill in your profile with skills and categories, and start receiving tasks.', 'faq.q4': 'How do I choose the right specialist?', 'faq.a4': 'Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.', 'faq.q5': 'What if I am not satisfied?', 'faq.a5': 'You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.', 'faq.q6': 'Can I contact a specialist before accepting their offer?', 'faq.a6': 'Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.', 'faq.q7': 'How long does it take to receive offers?', 'faq.a7': 'Usually within a few hours. Specialists get notified about new tasks and can respond quickly.', 'faq.q8': 'Can I post a task in any city in Greece?', 'faq.a8': 'Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.', 'faq.q9': 'What types of tasks can I find on CanHelp?', 'faq.a9': 'Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.', 'faq.q10': 'Is there a mobile app?', 'faq.a10': 'Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.', 'how.step1.title': 'Post a task', 'how.step1.desc': 'Describe what you need and set your budget', 'how.step2.title': 'Receive offers', 'how.step2.desc': 'Specialists will send you offers with price and timeline', 'how.step3.title': 'Choose & start', 'how.step3.desc': 'Pick the best professional and start the collaboration', 'tasks.title': 'tasks', 'tasks.filters': 'Filters', 'tasks.search': 'Search', 'tasks.search.placeholder': 'Title or keyword...', 'tasks.search.btn': 'Search', 'tasks.publish': 'Post', 'tasks.category.all': 'All', 'tasks.category.all_in': 'All in', 'tasks.category.label': 'Category', 'tasks.location.label': 'City', 'tasks.location.placeholder': 'e.g. Athens', 'tasks.empty': 'No tasks found', 'tasks.empty.cta': 'Post the first one', 'task.status.open': 'Open', 'task.status.in_progress': 'In progress', 'task.status.completed': 'Completed', 'task.status.cancelled': 'Cancelled', 'task.status.draft': 'Draft', 'task.budget': 'Budget', 'task.location': 'Location', 'task.deadline': 'Start date', 'task.created_at': 'Created', 'task.customer': 'Customer', 'task.offer.btn': 'Submit offer', 'task.invite.banner_title': "You've been invited to this task", 'task.invite.banner_hint': 'The customer personally invited you', 'task.invite.accept': 'Send offer', 'task.invite.decline': 'Decline', 'offer.accept': 'Accept', 'offer.decline': 'Decline', 'task.complete': 'Complete task', 'task.complete.confirm': 'Mark this task as complete?', 'task.edit': 'Edit', 'task.status_label': 'Status', 'task.yours': 'Your task', 'task.offer.yours': 'Your offer', 'review.leave': 'Leave a review', 'review.rating': 'Rating', 'review.comment': 'Comment', 'review.comment.placeholder': 'Tell us about your experience...', 'review.submit': 'Submit review', 'review.submitting': 'Submitting...', 'review.done': 'Review submitted!', 'profile.reviews': 'Reviews', 'profile.no_reviews': 'No reviews yet', 'profile.rating': 'Rating', 'profile.skills.label': 'Skills', 'profile.member_since': 'Member since', 'task.offers': 'Offers', 'task.offers.none': 'No offers yet', 'create.title': 'Post a task', 'create.field.title': 'Title', 'create.field.description': 'Description', 'create.field.category': 'Category', 'create.field.category.select': 'Select...', 'create.field.location': 'Location', 'create.field.location.any': 'Anywhere', 'create.field.location.all': 'Entire city', 'create.field.budget': 'Budget (€)', 'create.field.deadline': 'Start date', 'create.field.budget_negotiable': 'Price is negotiable', 'create.field.time_slot': 'Time slot', 'create.field.time_slot.any': 'Anytime', 'create.field.time_slot.morning': 'Morning (08:00–13:00)', 'create.field.time_slot.afternoon': 'Afternoon (13:00–18:00)', 'create.field.time_slot.evening': 'Evening (18:00–22:00)', 'create.field.time_slot.weekend': 'Weekend', 'create.field.address': 'Address (optional)', 'create.field.address.district': 'District', 'create.field.address.street': 'Street', 'create.field.address.house': 'Number', 'create.field.confidential': 'Confidential note', 'create.field.confidential.placeholder': 'Details visible only to the assigned specialist...', 'create.field.confidential.hint': 'Not shown publicly', 'create.field.photos': 'Photos', 'create.field.photos.add': 'Add photo', 'create.field.photos.uploading': 'Uploading...', 'task.budget_negotiable': 'Price negotiable', 'task.time_slot': 'Time slot', 'task.confidential': 'Confidential note', 'create.field.title.placeholder': 'e.g. Clean 80sqm apartment', 'create.field.description.placeholder': 'Describe in detail what you need...', 'create.field.location.placeholder': 'e.g. Athens, Kolonaki', 'create.field.budget.placeholder': 'e.g. 100', 'create.submit': 'Post task', 'create.submitting': 'Posting...', 'login.title': 'Welcome back', 'login.subtitle': 'Sign in to CanHelp', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.submitting': 'Signing in...', 'login.error': 'Invalid email or password', 'login.unverified.title': 'Verify your email address', 'login.unverified.desc': 'We sent a verification link to your email. Check your inbox (or spam) and click the link.', 'login.unverified.resend': 'Resend verification email', 'login.unverified.sending': 'Sending...', 'login.unverified.sent': '✓ Sent — check your inbox', 'profile.email.verified': 'Email verified', 'profile.email.not_verified': 'Email not verified', 'login.no_account': "Don't have an account?", 'login.register_link': 'Register', 'login.forgot_password': 'Forgot password?', 'login.or_continue_with': 'or continue with', 'login.continue_google': 'Continue with Google', 'forgot.title': 'Forgot password', 'forgot.subtitle': 'Enter your email to receive a reset link', 'forgot.email': 'Email', 'forgot.submit': 'Send reset link', 'forgot.submitting': 'Sending...', 'forgot.sent.title': 'Check your inbox', 'forgot.sent.desc': 'If an account exists with that email, we\'ll send you a password reset link.', 'forgot.back_to_login': 'Back to sign in', 'forgot.error': 'Could not send reset link. Check the email address and try again.', 'forgot.error.not_found': 'No account found with this email address.', 'forgot.error.send_failed': 'Failed to send email. Please try again later.', 'reset.title': 'New password', 'reset.subtitle': 'Enter your new password', 'reset.password': 'New password', 'reset.confirm': 'Confirm password', 'reset.submit': 'Change password', 'reset.submitting': 'Saving...', 'reset.success': 'Password changed successfully. Redirecting to sign in...', 'reset.back_to_login': 'Back to sign in', 'reset.error.mismatch': 'Passwords do not match', 'reset.error.invalid': 'Invalid or expired link. Please request a new one.', 'register.title': 'Register', 'register.subtitle': 'Create a CanHelp account', 'register.first_name': 'First name', 'register.last_name': 'Last name', 'register.email': 'Email', 'register.password': 'Password (min 8 characters)', 'register.role': 'Role', 'register.role.customer': 'User', 'register.role.customer.desc': 'I post tasks', 'register.role.specialist': 'Specialist', 'register.role.specialist.desc': 'I take on tasks', 'register.submit': 'Create account', 'register.submitting': 'Registering...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Sign in', 'register.continue_google': 'Continue with Google', 'register.check_email.title': 'Check your email', 'register.check_email.desc': 'We sent a verification link to your email address. Check your inbox (or spam) and click the link.', 'register.check_email.login': 'Back to sign in', 'dashboard.title': 'Dashboard', 'dashboard.new_task': '+ New task', 'dashboard.my_tasks': 'My tasks', 'dashboard.my_offers': 'My offers', 'dashboard.invitations': 'Job invitations', 'dashboard.offers_count': 'offers', 'dashboard.declined_count': 'declined', 'dashboard.completed_tasks': 'Completed tasks', 'dashboard.completed_offers': 'Completed offers', 'dashboard.review_pending': 'Review not yet submitted', 'tasks.new.top_specialists': 'Top specialists', 'tasks.new.select_category': 'Select a category to see matching specialists', 'tasks.new.invite': 'Offer work', 'tasks.new.invited': 'Selected ✓', 'reviews.count': 'reviews', 'filter.location': 'Location', 'filter.language': 'Languages', 'filter.language.any': 'Any language', 'filter.category.all': 'All categories', 'user.categories': 'Categories', 'user.work_area': 'Work area', 'dashboard.tasks.empty': "You haven't posted any tasks", 'dashboard.tasks.empty.cta': 'Post your first one', 'dashboard.tasks.add_new': 'Add a new task', 'dashboard.offers.empty': "You haven't submitted any offers", 'dashboard.offers.empty.cta': 'Find tasks', 'dashboard.customer.specialists_title': 'Looking for a specialist?', 'dashboard.customer.specialists_hint': 'Browse specialist profiles, read reviews and invite them to your tasks', 'dashboard.customer.specialists_cta': 'Find a specialist', 'dashboard.customer.how_title': 'How it works', 'dashboard.customer.step1': 'Create a task with a description and budget', 'dashboard.customer.step2': 'Specialists will send offers with price and timeline', 'dashboard.customer.step3': 'Choose the right one and start working', 'notif.title': 'Notifications', 'notif.mark_all': 'Mark all as read', 'notif.empty': 'No notifications', 'notif.type.new_offer': 'New offer', 'notif.type.offer_accepted': 'Your offer was accepted', 'notif.type.offer_declined': 'Your offer was declined', 'notif.type.task_completed': 'Task completed', 'notif.type.task_cancelled': 'Task cancelled', 'notif.type.new_message': 'New message', 'notif.type.new_review': 'New review', 'notif.type.task_invite': 'Job invitation', 'notif.body.new_offer': 'New offer for «{title}»', 'notif.body.offer_accepted': 'Your offer for «{title}» was accepted', 'notif.body.offer_declined': 'Your offer for «{title}» was declined', 'notif.body.task_invite': 'You\'ve been invited for «{title}»', 'notif.body.new_review': 'You received a {rating}★ review', 'offer.status.pending': 'Pending', 'offer.status.accepted': 'Accepted', 'offer.status.declined': 'Declined', 'offer.status.withdrawn': 'Withdrawn', 'offer.status.other_accepted': 'Another specialist was chosen', 'common.loading': 'Loading...', 'common.error': 'Error', 'common.save': 'Save', 'common.saving': 'Saving...', 'common.cancel': 'Cancel', 'common.add': 'Add', 'common.close': 'Close', 'common.edit': 'Edit', 'common.delete': 'Delete', 'common.from': 'by', 'common.currency': '€', 'common.greece': 'Greece', // Chat 'chat.connected': 'Connected', 'chat.disconnected': 'Disconnected', 'chat.no_rooms': 'No conversations yet', 'chat.task_fallback': 'Task', 'chat.select': 'Select a conversation', 'chat.no_messages': 'No messages yet', 'chat.placeholder': 'Write a message... (Enter to send)', 'chat.conversation_fallback': 'Conversation', 'chat.direct_chat': 'Direct chat', 'chat.linked_task': 'Linked task', 'chat.write_btn': 'Message', 'chat.just_now': 'just now', 'chat.min_ago': 'm', 'chat.write_specialist': 'Write to specialist', 'chat.write_customer': 'Write to customer', 'chat.notif_settings': 'Notification settings', 'chat.notif_messages': 'Notifications for new messages', 'chat.toast_title': 'New message', 'chat.toast_open': 'Open chat', // Offer form 'offer.price': 'Price', 'offer.price.placeholder': 'e.g. 80', 'offer.customer_budget': 'Client budget', 'offer.message': 'Message', 'offer.optional': 'optional', 'offer.message.placeholder': 'Introduce yourself, your experience and why you are the best choice...', 'offer.submitting': 'Sending...', // Profile 'profile.photo': 'Profile photo', 'profile.photo.change': 'Change photo', 'profile.photo.hint': 'JPEG, PNG, WebP · up to 5MB', 'profile.basic_info': 'Basic info', 'profile.phone': 'Phone', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Short bio', 'profile.bio.placeholder': 'Tell us a bit about yourself...', 'profile.language': 'Language', 'profile.language.hint': 'App interface and email notification language', 'profile.languages': 'Languages spoken', 'profile.languages.hint': 'Select all languages you speak', 'profile.skills': 'Skills', 'profile.skills.subtitle': 'Add the services you offer', 'profile.skills.placeholder': 'e.g. Cleaning, IT, Tutoring...', 'profile.role': 'Account role', 'profile.role.specialist': '🔧 Specialist', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 User', 'profile.role.change': 'To change your role please contact support.', 'profile.become_specialist': 'Become a Specialist', 'profile.become_specialist.desc': 'Upgrade to Specialist to take on tasks and build your profile.', 'become_specialist.hero.title': 'Earn money doing what you do best', 'become_specialist.hero.subtitle': 'Create a specialist profile and receive orders from clients across Greece', 'become_specialist.how.title': 'How it works', 'become_specialist.step1.title': 'Create a specialist portfolio', 'become_specialist.step1.desc': 'Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks', 'become_specialist.step2.title': 'Find tasks', 'become_specialist.step2.desc': 'Discover tasks in your categories in the "Find Orders" section', 'become_specialist.step3.title': 'Send an offer & earn', 'become_specialist.step3.desc': 'Submit offers with price and timeline, chat with clients and complete tasks', 'become_specialist.benefits.title': 'Specialist profile advantages', 'become_specialist.benefit1': 'Task search filtered by your categories and location', 'become_specialist.benefit2': 'Public profile with client reviews', 'become_specialist.benefit3': 'Availability schedule visible to clients', 'become_specialist.benefit4': 'Saved to favourites by clients', 'become_specialist.cta': 'Learn more', 'become_specialist.free_badge': 'Free registration', 'profile.tab.notifications': 'Notifications', 'profile.tab.reviews': 'Reviews', 'profile.tab.referral': 'Referrals', 'profile.tab.auto_response': 'Auto-response', 'profile.tab.site': 'Site', 'profile.site.title': 'Personal page', 'profile.site.url_label': 'Personal site', 'profile.site.copy': 'Copy', 'profile.site.copied': 'Copied', 'profile.site.visible_title': "What's on your page", 'profile.site.visible.name': 'Name and photo', 'profile.site.visible.bio': 'Bio', 'profile.site.visible.rating': 'Rating and reviews', 'profile.site.visible.portfolio': 'Portfolio / Cards', 'profile.site.visible.contacts': 'Contact info', 'profile.site.visible.full_last_name': 'Full last name', 'profile.site.visible.services': 'Service cards', 'profile.site.visible.reviews': 'Reviews section', 'profile.site.visible.status': '"Ready to help" status', 'profile.site.theme': 'Appearance theme', 'profile.site.theme.dark': 'Dark', 'profile.site.theme.light': 'Light', 'profile.site.slug_taken': 'This address is already taken', 'profile.site.stats.title': 'Site analytics', 'profile.site.stats.days': 'last 30 days', 'profile.site.stats.views': 'Views', 'profile.site.stats.unique': 'Unique visitors', 'profile.site.stats.messages': 'Messages', 'profile.site.stats.total_views': 'Total views', 'profile.site.stats.total_unique': 'Unique visitors', 'profile.site.stats.total_messages': 'Messages', 'profile.site.stats.empty': 'No data yet', 'profile.site.stats.loading': 'Loading analytics...', 'profile.site.stats.no_slug': 'Set your site URL to see analytics', 'profile.site.edit_bio_hint': 'Bio and photo are edited in the "Basic info" tab.', 'status.title': 'Status', 'status.can_help_now_hint': 'Your card is shown higher in search', 'status.need_help_hint': 'Specialists can offer you help', 'profile.referral.title': 'Referral program', 'profile.referral.desc': 'Share your link and earn rewards for every new user you invite.', 'profile.referral.link_label': 'Your referral link', 'profile.referral.copy': 'Copy', 'profile.referral.copied': 'Copied!', 'profile.referral.invited_count': 'successful referrals', 'profile.referral.no_code': 'Referral code is not available.', 'notifications.title': 'Notification settings', 'notifications.email.new_tasks': 'Email for new tasks', 'notifications.email.new_tasks.desc': 'Receive an email when a new task is posted in your categories', 'notifications.messages.desc': 'Receive a notification when a new message arrives', 'notifications.saved': 'Settings saved', 'notifications.plan_required': 'Not available in your plan', 'profile.tab.info': 'Basic info', 'profile.tab.finance': 'Finance', 'profile.tab.skills': 'Skills', 'profile.tab.categories': 'Categories', 'profile.tab.geography': 'Geography', 'profile.specialist.categories': 'Work categories', 'profile.specialist.categories.desc': 'Select the categories you work in', 'profile.specialist.geography': 'Coverage areas', 'profile.specialist.geography.desc': 'Select the cities / districts where you are active', 'profile.saving': 'Saving...', 'profile.upload.error': 'Error uploading photo', 'profile.saved': 'Saved', 'profile.tab.cards': 'Portfolio', 'profile.cards.count': 'Portfolio', 'profile.cards.add': 'Add portfolio', 'profile.cards.new_title': 'New portfolio title', 'profile.cards.placeholder': 'e.g. Plumbing', 'profile.cards.create': 'Create', 'profile.cards.cancel': 'Cancel', 'profile.cards.empty': 'No portfolio yet', 'profile.cards.create_first': 'Create your first portfolio', 'profile.cards.delete_confirm': 'Delete portfolio?', 'profile.card.tab.main': 'General', 'profile.card.tab.skills': 'Skills', 'profile.card.tab.categories': 'Categories', 'profile.card.tab.geography': 'Geography', 'profile.card.tab.portfolio': 'Portfolio', 'profile.card.active': 'Active', 'profile.card.save': 'Save', 'profile.card.saved': 'Saved', 'profile.card.delete': 'Delete', 'profile.card.skill.add': 'Add skill', 'profile.card.photo.add': 'Add photo', 'profile.card.photo.uploading': 'Uploading...', 'profile.card.photo.empty': 'No photos yet', 'profile.card.item.title': 'Title', 'profile.card.item.desc': 'Description', 'profile.card.item.save': 'Save', 'profile.card.item.cancel': 'Cancel', 'profile.card.item.edit': 'Edit', 'profile.upgrade.cards_limit': 'Portfolio limit reached', 'profile.upgrade.plan': 'Current plan:', 'profile.upgrade.contact': 'Contact the administrator to change your plan', 'profile.upgrade.ok': 'Got it', 'profile.plan.title': 'Subscription plan', 'profile.balance': 'Balance', 'profile.balance.topup': 'Top Up Balance', 'profile.balance.topup.title': 'Top Up Balance', 'profile.balance.topup.amount': 'Amount (EUR)', 'profile.balance.topup.hint': 'Choose a preset or enter a custom amount', 'profile.balance.topup.submit': 'Proceed to Payment', 'profile.balance.topup.loading': 'Redirecting...', 'profile.balance.topup.error': 'Payment initiation failed. Please try again.', 'payment.success.title': 'Payment Successful!', 'payment.success.desc': 'Your balance has been updated.', 'payment.cancelled.title': 'Payment Cancelled', 'payment.cancelled.desc': 'Payment was cancelled. No charges were made.', 'payment.pending.title': 'Processing...', 'payment.pending.desc': 'Your payment is being processed.', 'payment.back_to_profile': 'Back to Profile', 'profile.plan.basic': 'Basic (free)', 'profile.plan.contact_upgrade': 'Contact admin to upgrade your plan', 'profile.plan.cards_up_to': 'Portfolio: up to', 'profile.plan.cards_unlimited': 'Portfolio: unlimited', 'profile.plan.tasks_up_to': 'Tasks: up to', 'profile.plan.offers_up_to': 'Offers: up to', 'profile.plan.valid_until': 'Valid until', 'profile.plan.no_expiry': 'No expiry', // Create task 'create.error': 'Error posting task', // Tasks list extras 'tasks.category.general': 'General', 'tasks.budget.range': 'Range:', 'tasks.budget.from': 'from', 'tasks.budget.to': 'to', 'tasks.filter.reset': 'Reset filters', 'tasks.load_more': 'Load more', 'tasks.showing': 'Results:', 'tasks.field.budget': 'Budget, €', // Admin 'admin.title': 'Admin Panel', 'admin.tab.stats': 'Statistics', 'admin.tab.users': 'Users', 'admin.tab.tasks': 'Tasks', 'admin.tab.reports': 'Reports', 'admin.stats.users': 'Users', 'admin.stats.tasks': 'Tasks', 'admin.stats.offers': 'Offers', 'admin.stats.reviews': 'Reviews', 'admin.tasks.by_status': 'Tasks by status', 'admin.col.user': 'User', 'admin.col.email': 'Email', 'admin.col.role': 'Role', 'admin.col.registered': 'Registered', 'admin.col.status': 'Status', 'admin.col.title': 'Title', 'admin.col.budget': 'Budget', 'admin.col.created': 'Created', 'admin.users.active': 'Active', 'admin.users.inactive': 'Inactive', 'admin.users.deactivate': 'Deactivate', 'admin.users.activate': 'Activate', 'admin.tasks.cancel': 'Cancel', 'admin.reports.none': 'No reports', 'admin.reports.reviewed': 'Reviewed', 'admin.reports.dismiss': 'Dismiss', 'admin.pagination.total': 'Total', 'admin.users.role.change': 'Change role', 'admin.users.search.placeholder': 'Search name or email...', 'admin.tasks.delete': 'Delete', 'admin.tasks.delete.confirm': 'Permanently delete this task?', 'admin.tasks.search.placeholder': 'Search title...', 'admin.col.customer': 'Customer', 'admin.col.reporter': 'Reporter', 'admin.col.target': 'Target', 'admin.filter.all_roles': 'All roles', 'admin.filter.all_statuses': 'All statuses', 'admin.reports.target.task': 'Task', 'admin.reports.target.user': 'User', 'admin.tab.categories': 'Categories', 'admin.tab.locations': 'Cities & Districts', 'admin.tab.logs': 'Logs', 'admin.tab.plans': 'Plans', 'admin.tab.settings': 'Settings', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Activity', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Notifications', 'admin.notif_logs.type': 'Type', 'admin.notif_logs.title': 'Title', 'admin.notif_logs.read': 'Read', 'admin.notif_logs.empty': 'No notification logs', 'admin.stats.notif_chart_title': 'Notifications per day', 'admin.stats.notif_label': 'Notifications', 'admin.stats.mail_chart_title': 'Emails per day', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'All', 'admin.stats.specialists': 'Specialists', 'admin.col.plan': 'Plan', 'admin.back_home': 'Home', 'admin.plans.title': 'Subscription plans', 'admin.plans.add': '+ New plan', 'admin.plans.empty': 'No plans created', 'admin.plans.form.new': 'New plan', 'admin.plans.form.edit': 'Edit plan', 'admin.plans.form.name': 'Name', 'admin.plans.form.price': 'Price (EUR)', 'admin.plans.form.old_price': 'Old price (EUR, optional)', 'admin.plans.form.max_offers': 'Max offers (empty = no limit)', 'admin.plans.form.max_cards': 'Max portfolio (empty = no limit)', 'admin.plans.form.duration_days': 'Duration (days, empty = no expiry)', 'admin.plans.form.description': 'Description', 'admin.plans.form.features': 'Features (one per line)', 'admin.plans.form.notify': 'Notify about new tasks', 'admin.plans.form.default': 'Default', 'admin.plans.form.active': 'Active', 'admin.plans.form.order': 'Order', 'admin.plans.form.role': 'Role', 'admin.plans.form.tier': 'Tier', 'admin.plans.form.role.customer': 'Customer', 'admin.plans.form.role.specialist': 'Specialist', 'admin.plans.form.tier.free': 'Free', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Limits (empty = unlimited)', 'admin.plans.form.max_messages_day': 'Max Messages/Day', 'admin.plans.form.max_orders_day': 'Max Orders/Day', 'admin.plans.form.max_skills': 'Max Skills', 'admin.plans.form.max_profiles': 'Max Profiles', 'admin.plans.form.max_portfolio': 'Max Portfolio Items', 'admin.plans.form.section.boost': 'Multipliers & Boost', 'admin.plans.form.search_boost': 'Search Boost', 'admin.plans.form.offers_multiplier': 'Offers Multiplier', 'admin.plans.form.section.contact': 'Contact Permissions', 'admin.plans.form.can_contact_free': 'Contact Free Plan users', 'admin.plans.form.can_contact_pro': 'Contact Pro Plan users', 'admin.plans.form.can_contact_all': 'Contact All users', 'admin.plans.form.can_show_contact': 'Show Contact Info', 'admin.plans.form.can_view_phone': 'View Phone', 'admin.plans.form.section.features': 'Feature Flags', 'admin.plans.form.upload_video': 'Upload Video', 'admin.plans.form.favorites': 'Favorites', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Verified Badge', 'admin.plans.form.highlighted_reviews': 'Highlighted Reviews', 'admin.plans.form.personal_site': 'Personal Site', 'admin.plans.form.can_help_now': 'Can Help Now Status', 'admin.plans.form.need_help': 'Need Help Status', 'admin.plans.form.auto_response': 'Auto Response', 'admin.plans.form.auto_match': 'Auto Match', 'admin.plans.form.instant_dispatch_free': 'Instant Dispatch (Free)', 'admin.plans.form.instant_dispatch_pro': 'Instant Dispatch (Pro)', 'admin.plans.badge.default': 'Default', 'admin.plans.badge.inactive': 'Inactive', 'admin.plans.make_default': 'Set as default', 'admin.plans.tasks': 'Tasks', 'admin.plans.offers': 'Offers', 'admin.plans.cards': 'Portfolio', 'admin.plans.notify_tasks': 'Task notifications', 'admin.plans.delete.confirm': 'Delete plan', 'admin.activity.title': 'Activity log', 'admin.activity.event': 'Event', 'admin.activity.all_events': 'All events', 'admin.activity.from': 'From', 'admin.activity.to': 'To', 'admin.activity.reset': 'Reset', 'admin.activity.total': 'Total', 'admin.activity.empty': 'No records', 'admin.mail.event': 'Email event', 'admin.mail.all_events': 'All email events', 'admin.mail.from': 'From', 'admin.mail.to': 'To', 'admin.mail.reset': 'Reset', 'admin.mail.total': 'Total', 'admin.mail.empty': 'No email logs', 'admin.mail.recipient': 'Recipient', 'admin.mail.provider': 'Provider', 'admin.mail.details': 'Details', 'admin.mail.status': 'Status', 'admin.mail.success': 'Success', 'admin.mail.failed': 'Failed', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'No records', 'admin.logs.date': 'Date', 'admin.logs.provider': 'Provider', 'admin.logs.model': 'Model', 'admin.logs.action': 'Action', 'admin.logs.langs': 'Languages', 'admin.logs.in': 'In', 'admin.logs.out': 'Out', 'admin.logs.total': 'Total', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Status', 'admin.stats.activity_30d': 'Activity over 30 days', 'admin.stats.tasks_label': 'Tasks', 'admin.stats.users_label': 'Users', 'admin.stats.specialists_label': 'Specialists', 'admin.stats.tokens_title': 'Token usage (by month)', 'admin.stats.tokens_out': 'Output', 'admin.stats.tokens_in': 'Input', 'admin.stats.tokens_out_label': 'Output tokens', 'admin.stats.tokens_in_label': 'Input tokens', 'admin.stats.cost_label': 'Cost (USD)', 'admin.stats.tasks_by_status': 'Tasks by status', 'admin.task_status.open': 'Open', 'admin.task_status.in_progress': 'In progress', 'admin.task_status.completed': 'Completed', 'admin.task_status.cancelled': 'Cancelled', 'admin.task_status.draft': 'Drafts', 'admin.settings.tab.general': 'General', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Notifications', 'admin.settings.tab.payment': 'Payment', 'admin.settings.tab.referral': 'Referrals', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Socials', 'admin.settings.socials.title': 'Social Network Links', 'admin.settings.socials.hint': 'Filled links are displayed in the site footer', 'admin.settings.seo.maintenance_label': 'Maintenance Mode', 'admin.settings.seo.maintenance_hint': 'Show a maintenance page to all visitors', 'admin.settings.seo.indexing_label': 'Search Engine Indexing', 'admin.settings.seo.indexing_hint': 'Allow search engines to index the site', 'admin.settings.seo.head_scripts_label': ' Scripts (JS)', 'admin.settings.seo.head_scripts_hint': 'Runs on every page (Google Tag Manager, analytics, etc.)', 'admin.settings.seo.site_title_label': 'Site Title', 'admin.settings.seo.site_description_label': 'Site Description (meta description)', 'admin.settings.referral.title': 'Referral program', 'admin.settings.referral.hint': 'Reward users who bring new registrations.', 'admin.settings.referral.enabled_label': 'Enabled', 'admin.settings.referral.enabled_hint': 'Enable / disable reward application', 'admin.settings.referral.customer_section': 'For customers', 'admin.settings.referral.specialist_section': 'For specialists', 'admin.settings.referral.plan_label': 'Reward plan', 'admin.settings.referral.no_plan': '— no plan —', 'admin.settings.referral.plan_hint': 'This plan will be assigned to the referrer. If their current plan is higher, only days will be added.', 'admin.settings.referral.days_label': 'Reward days', 'admin.settings.referral.days_hint': 'Number of days added to the plan expiry.', 'admin.settings.general.title': 'General settings', 'admin.settings.general.site_name': 'Site name', 'admin.settings.general.site_url': 'Site URL', 'admin.settings.general.contact_email': 'Contact email', 'admin.settings.general.support_phone': 'Support phone', 'admin.settings.smtp.title': 'SMTP settings', 'admin.settings.smtp.hint': 'Used to send email notifications.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Port', 'admin.settings.smtp.encryption': 'Encryption', 'admin.settings.smtp.enc.none': 'None', 'admin.settings.smtp.enc.tls': 'STARTTLS (port 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (port 465)', 'admin.settings.smtp.username': 'Username', 'admin.settings.smtp.password': 'Password / App Password', 'admin.settings.smtp.from_name': 'Sender name', 'admin.settings.smtp.from_email': 'Sender email', 'admin.settings.smtp.test': 'Send test email', 'admin.settings.smtp.sending': 'Sending...', 'admin.settings.payment.hint': 'ePay Piraeus Bank credentials.', 'admin.settings.env.test': 'Test (sandbox)', 'admin.settings.env.prod': 'Production', 'admin.settings.env.label': 'Environment', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Active', 'admin.settings.saving': 'Saving...', 'admin.settings.saved': 'Saved', 'admin.notif.vars_hint': 'Available variables in templates', 'admin.notif.tmpl.not_set': 'Template not configured', 'admin.notif.tmpl.subject_label': 'Email subject', 'admin.notif.tmpl.body_label': 'Email body (HTML)', 'admin.notif.tmpl.save': 'Save', 'admin.notif.tmpl.close': 'Close', 'admin.notif.tmpl.translate': 'Auto-translate to other languages', 'admin.notif.tmpl.translating': 'Translating...', 'admin.notif.tmpl.saving': 'Saving...', 'admin.notif.email_verification': 'Email verification', 'admin.notif.registration_success': 'Successful registration', 'admin.notif.password_reset': 'Password reset', 'admin.notif.new_offer': 'New offer', 'admin.notif.new_task': 'New task', 'admin.notif.offer_accepted': 'Offer accepted', 'admin.notif.new_message': 'New message', 'admin.notif.offer_declined': 'Offer declined', 'admin.notif.offer_other_accepted': 'Another specialist chosen', 'admin.notif.task_updated': 'Task updated', 'admin.notif.deadline_reminder': 'Deadline reminder', 'admin.notif.task_archived': 'Task unpublished automatically', 'admin.notif.referral_reward': 'Referral reward', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Plan activated', 'admin.email_template.plan_upgraded': 'Plan upgraded', 'admin.email_template.plan_downgrade_scheduled': 'Downgrade scheduled', 'admin.email_template.plan_downgrade_applied': 'Downgrade applied', 'admin.email_template.plan_renewal_reminder': 'Renewal reminder', 'admin.email_template.plan_insufficient_funds': 'Insufficient funds warning', // Pricing confirm modal 'pricing.confirm.title': 'Confirm plan selection', 'pricing.confirm.plan': 'Plan', 'pricing.confirm.prorated': 'Prorated credit', 'pricing.confirm.effective_price': 'Amount due', 'pricing.confirm.your_balance': 'Your balance', 'pricing.confirm.downgrade_info': 'The switch to the new plan will happen automatically after the current period ends.', 'pricing.confirm.insufficient': 'Insufficient balance.', 'pricing.confirm.top_up': 'Top up', 'pricing.confirm.schedule_downgrade': 'Schedule downgrade', 'pricing.confirm.pay': 'Pay', 'admin.user_edit.title': 'Edit user', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email verified', 'admin.user_edit.email_not_verified': 'Email not verified', 'admin.user_edit.verify_email_btn': 'Verify manually', 'admin.user_edit.verify_email_done': 'Email verified!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Registered', 'admin.user_edit.last_seen': 'Last seen', 'admin.user_edit.lang': 'Language', 'admin.user_edit.first_name': 'First name', 'admin.user_edit.last_name': 'Last name', 'admin.user_edit.phone': 'Phone', 'admin.user_edit.bio': 'Bio', 'admin.user_edit.role': 'Role', 'admin.user_edit.plan': 'Plan', 'admin.user_edit.no_plan': '— No plan —', 'admin.user_edit.active': 'Active account', 'admin.user_edit.balance': 'Balance (EUR)', 'admin.user_edit.skills': 'Skills', 'admin.user_edit.tab.profile': 'Profile', 'admin.user_edit.tab.account': 'Account', 'admin.user_edit.tab.balance': 'Balance', 'admin.user_edit.tab.settings': 'Settings', 'admin.user_edit.tab.specialist': 'Portfolio', 'admin.user_edit.tab.site': 'Website', 'admin.user_edit.plan_expires': 'Plan expires', 'admin.user_edit.interface_lang': 'Interface language', 'admin.user_edit.comm_languages': 'Communication languages', 'admin.user_edit.personal_site_slug': 'Personal page', 'admin.user_edit.show_contact_info': 'Show contact info', 'admin.user_edit.show_contact_info.hint': 'Visible to customers', 'admin.user_edit.notify_new_tasks': 'Notify about new tasks', 'admin.user_edit.notify_new_tasks.hint': 'Push and email notifications', 'admin.user_edit.notif_messages': 'Message notifications', 'admin.user_edit.notif_messages.hint': 'New messages in chat', 'admin.user_edit.site_settings': 'Personal page settings', 'admin.user_edit.categories': 'Service categories', 'admin.user_edit.locations': 'Service areas', 'admin.user_edit.skill_placeholder': 'New skill...', 'admin.user_edit.add_category': '— Select category —', 'admin.user_edit.add_location': '— Select location —', 'admin.user_edit.specialist_cards': 'Portfolio', 'admin.user_edit.no_cards': 'No portfolio found', 'admin.user_edit.card_title': 'Portfolio title', 'admin.user_edit.card_description': 'Description', 'admin.balance.topup.btn': 'Top up', 'admin.balance.withdraw.btn': 'Withdraw', 'admin.balance.modal_hint': 'Changes take effect immediately and are recorded in history', 'admin.balance.topup.title': 'Top up balance', 'admin.balance.topup.amount': 'Amount', 'admin.balance.topup.description': 'Comment', 'admin.balance.topup.description.placeholder': 'For example: bonus or manual top-up', 'admin.balance.topup.submit': 'Top up balance', 'admin.balance.withdraw.title': 'Withdraw balance', 'admin.balance.withdraw.amount': 'Amount', 'admin.balance.withdraw.description': 'Comment', 'admin.balance.withdraw.description.placeholder': 'For example: refund or manual debit', 'admin.balance.withdraw.submit': 'Withdraw from balance', 'admin.user_edit.role.customer': 'Customer', 'admin.user_edit.role.specialist': 'Specialist', 'admin.user_edit.role.admin': 'Administrator', 'common.refresh': 'Refresh', 'common.back_home': 'Home', 'admin.loc.hint': 'Manage cities and districts', 'admin.loc.add_city': 'New city', 'admin.loc.add_district': 'Add district', 'admin.loc.new': 'New location', 'admin.loc.edit': 'Edit location', 'admin.loc.district': 'district', 'admin.loc.empty': 'No locations', 'admin.loc.delete.confirm': 'Delete location? All districts will also be deleted.', 'admin.cat.add_root': 'New category', 'admin.cat.add_sub': 'Subcategory', 'admin.cat.edit': 'Edit', 'admin.cat.delete': 'Delete', 'admin.cat.delete.confirm': 'Delete category? All subcategories will also be deleted.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Icon', 'admin.cat.name_el': 'Greek', 'admin.cat.name_en': 'English', 'admin.cat.name_ru': 'Russian', 'admin.cat.order': 'Order', 'admin.cat.active': 'Active', 'admin.cat.parent': 'Parent category', 'admin.cat.no_parent': 'Top level', 'admin.cat.save': 'Save', 'admin.cat.cancel': 'Cancel', 'admin.cat.empty': 'No categories', 'admin.cat.hint': 'Manage categories with multi-level hierarchy', 'admin.cat.new': 'New category', 'admin.cat.subcategory': 'subcategory', 'admin.cat.add_child': 'Add subcategory', 'admin.cat.inactive': 'Inactive', 'admin.event.user_login': 'Login', 'admin.event.user_register': 'Registration', 'admin.event.admin_user_deactivate': 'User blocked', 'admin.event.admin_user_activate': 'User activated', 'admin.event.admin_user_role_changed': 'Role changed', 'admin.event.admin_task_cancelled': 'Task cancelled', 'admin.event.admin_task_deleted': 'Task deleted', 'admin.event.admin_report_reviewed': 'Report reviewed', 'admin.event.admin_report_dismissed': 'Report dismissed', 'admin.event.task_created': 'Task created', // User status 'user.online': 'Online', 'user.seen_minutes': 'was here {n} min ago', 'user.seen_hours': 'was here {n} hr ago', 'user.seen_yesterday': 'was here yesterday', 'user.seen_days': 'was here {n} days ago', // Specialists 'specialists.title': 'Specialists', 'specialists.search': 'Search specialist...', 'specialists.search.btn': 'Search', 'specialists.empty': 'No specialists found', 'specialists.no_bio': 'No description', 'specialists.view': 'View profile', 'specialists.reviews': 'reviews', 'specialist.favorite': 'Add to favorites', 'specialist.unfavorite': 'Remove from favorites', 'specialist.site_link': 'Personal site', 'favorites.specialists.title': 'Favourite specialists', 'favorites.specialists.empty': 'No favourite specialists yet', 'nav.favorites': 'Favourites', 'nav.schedule': 'Schedule', 'nav.find_tasks': 'Find Orders', 'schedule.title': 'My Schedule', 'schedule.subtitle': 'Mark the days when you are free or busy — clients will see your availability', 'schedule.available': 'Available', 'schedule.busy': 'Busy', 'schedule.unset': 'Not set', 'schedule.click_hint': '← click to cycle status', 'schedule.range_mode': 'Select range', 'schedule.range_from': 'From {date} — select end date', 'schedule.click_to_set': 'Click to set', 'schedule.free': 'free', 'schedule.busy_count': 'busy', 'schedule.free_days': 'free days', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Connect Google Calendar', 'schedule.disconnectGoogle': 'Disconnect', 'schedule.connectedAs': 'Connected as', 'schedule.importFromGoogle': 'Sync from Google', 'schedule.gcalConnected': '\u2713 Google Calendar connected', 'schedule.gcalError': 'Google Calendar connection error', 'schedule.gcalImportDone': 'Imported {n} days from Google Calendar', 'schedule.gcalAutoSyncNote': 'Availability changes are automatically synced to Google Calendar', 'schedule.gcalConnectDesc': 'Connect Google Calendar to automatically sync your availability', 'schedule.gcalDisconnectConfirm': 'Disconnect Google Calendar?', 'find_tasks.title': 'Find Orders', 'find_tasks.for_me': 'For me', 'find_tasks.all': 'All orders', 'find_tasks.by_category': 'By category', 'find_tasks.list': 'List', 'find_tasks.already_offered': 'Offer sent', 'find_tasks.offer_now': 'Make an offer', 'find_tasks.empty_for_me': 'No tasks found in your categories', 'find_tasks.banner_hint': 'Find tasks matching your portfolio categories', 'find_tasks.no_cards': 'Create a specialist portfolio to see tasks matched to you', 'find_tasks.add_card': 'Create portfolio', 'find_tasks.search': 'Search tasks...', 'find_tasks.tasks_count': 'tasks', 'footer.tagline': 'The task platform for Greece', 'footer.rights': 'All rights reserved.', // App download section 'app.download_title': 'Download the CanHelp mobile app', 'app.download_desc': 'All of CanHelp — always at your fingertips. Available for Android and iOS.', // Nav 'nav.pricing': 'Pricing', // Pricing page 'pricing.title': 'Pricing', 'pricing.subtitle': 'Choose the right plan for you', 'pricing.role.customer': 'Customer', 'pricing.role.specialist': 'Specialist', 'pricing.free': 'Free', 'pricing.per_month': 'mo', 'pricing.duration': 'Duration', 'pricing.days': 'days', 'pricing.current_plan': 'Your plan', 'pricing.popular': 'Popular', 'pricing.choose': 'Choose', 'pricing.your_plan': 'Active plan', 'pricing.free_default': 'Default', 'pricing.compare': 'Compare features', 'pricing.feature': 'Feature', 'pricing.faq_note': 'Payment is deducted from your CanHelp balance. Top up available in Payments.', 'pricing.feat.messages': 'Messages / day', 'pricing.feat.orders': 'Orders / day', 'pricing.feat.contact_all': 'Contact everyone', 'pricing.feat.view_phone': 'View phone number', 'pricing.feat.show_contact': 'Show contact info', 'pricing.feat.favorites': 'Favorites', 'pricing.feat.verified_badge': 'Verified badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Personal site', 'pricing.feat.auto_response': 'Auto-response', 'pricing.feat.auto_match': 'Auto-match', 'pricing.feat.highlighted_reviews': 'Highlighted reviews', 'pricing.feat.portfolio': 'Portfolio items', 'pricing.feat.cards': 'Specialist cards', 'pricing.feat.notify_tasks': 'New task notifications', 'pricing.feat.video': 'Video in portfolio', // Upgrade prompt 'upgrade.available_in': 'Available in', 'upgrade.cta': 'Upgrade', // Dashboard plan block 'dashboard.plan.title': 'My Plan', 'dashboard.plan.expires': 'Expires in {n} days', 'dashboard.plan.upgrade': 'Upgrade plan', 'dashboard.plan.no_plan': 'Free plan', 'dashboard.plan.messages': 'Messages today', 'dashboard.plan.orders': 'Orders today', 'dashboard.plan.limits': 'Daily limits', 'dashboard.plan.features': 'Features', 'dashboard.plan.stats': 'Stats', 'dashboard.stats.cards': 'Portfolios', 'dashboard.stats.maxCards': 'Max portfolios', 'dashboard.stats.portfolioItems': 'Portfolio items', 'dashboard.stats.maxPortfolioItems': 'Max items', 'dashboard.stats.activeOffers': 'Active offers', 'dashboard.stats.reviewsReceived': 'Reviews', 'dashboard.stats.activeTasks': 'Active tasks', 'dashboard.stats.completedTasks': 'Completed', 'status.need_help': 'I need help', 'status.active': 'Active', 'status.toggle_on': 'Enable', 'status.toggle_off': 'Disable', // FOMO 'fomo.missed_orders': 'Missed {n} orders', 'fomo.missed_value': 'Worth €{v}', 'fomo.upgrade_hint': 'Upgrade to receive more orders', 'fomo.conversion': 'Task conversion', 'fomo.active': 'Active', 'fomo.with_offers': 'With offers', 'fomo.completed': 'Completed', 'fomo.already_offered': '{n} specialists have already responded', 'fomo.specialist_missed': 'You missed {n} orders', 'fomo.top_categories': 'Categories', 'fomo.offers_received': 'offers received', 'fomo.avg_offers': 'Avg {n}/task', 'fomo.completion_rate': 'completed', // Task auto-match 'task.auto_match': 'Auto-match', 'task.auto_match_results': 'Top specialists', 'task.no_offer_yet': 'You haven\'t sent an offer yet', 'task.make_offer': 'Send offer', 'auto_response.title': 'Auto-Response', 'auto_response.enabled': 'Enable auto-response', 'auto_response.min_budget': 'Min budget', 'auto_response.max_budget': 'Max budget', 'auto_response.default_price': 'Default price', 'auto_response.default_message': 'Default message', 'auto_response.max_per_day': 'Max auto-offers per day', 'auto_response.save': 'Save', 'auto_response.saved': 'Saved', 'auto_response.categories': 'Categories', 'auto_response.locations': 'Locations', // Personal site 'profile.personal_site': 'Personal Site', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Only latin letters, numbers, - and _', 'profile.site_open': 'Open site', 'profile.site_preview': 'Your site', 'profile.show_contact': 'Show contact info', 'profile.show_contact_hint': 'Customers with Pro/Ultimate plans will see your phone number', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Calendar requires a Pro or Ultimate plan', // Chat limits 'chat.limit_warning': '{n} messages left today', 'chat.limit_reached': 'Message limit reached. Upgrade your plan', 'chat.upgrade': 'Upgrade', // Site page 'site.member_since': 'Member since', 'site.rating': 'Rating', 'site.completed_tasks': 'Completed', 'site.languages': 'Languages', 'site.photos': 'photos', 'site.contact_form': 'Get in touch', 'site.contact_sent': 'Message sent!', 'site.contact_sent_desc': 'The specialist will contact you soon', 'site.contact_name': 'Name', 'site.contact_name_ph': 'Your name', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Message', 'site.contact_message_ph': 'Describe your task...', 'site.contact_send': 'Send', 'site.share': 'Share', 'site.speaks_languages': 'Speaks', 'site.message_sent': 'Message sent!', 'site.message_sent_desc': 'The specialist will receive it in the chat', 'site.message_placeholder': 'Write your message...', 'site.write_to_chat': 'Write to chat', 'site.auth_required_title': 'Sign in required', 'site.auth_required_desc': 'To write in the chat, you need to sign in to your CanHelp account.', 'site.auth_login_btn': 'Sign in', 'site.auth_contact_form_btn': 'Contact via feedback form', 'specialist.services': 'Services', 'portfolio.title': 'Portfolio', 'status.can_help_now': 'Available now', 'common.not_found': 'Page not found', 'common.anonymous': 'Anonymous', 'specialist_setup.page_title': 'Specialist profile setup', 'specialist_setup.step_of': 'Step {current} of {total}', 'specialist_setup.next': 'Next', 'specialist_setup.back': 'Back', 'specialist_setup.skip': 'Skip', 'specialist_setup.finish': 'Finish', 'specialist_setup.go_to_profile': 'Go to profile', 'specialist_setup.browse_tasks': 'Browse tasks', 'specialist_setup.step1.title': 'Welcome!', 'specialist_setup.step1.subtitle': "Let's set up your profile", 'specialist_setup.step1.desc': 'A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.', 'specialist_setup.step1.what_next': 'What we will do:', 'specialist_setup.step1.item1': 'Fill in basic information', 'specialist_setup.step1.item2': 'Create a service card', 'specialist_setup.step1.item3': 'Add skills and categories', 'specialist_setup.step1.item4': 'Select service area', 'specialist_setup.step1.item5': 'Upload portfolio photos', 'specialist_setup.step2.title': 'Basic profile', 'specialist_setup.step2.subtitle': 'Tell us about yourself', 'specialist_setup.step2.bio_label': 'About me', 'specialist_setup.step2.bio_placeholder': 'Describe your experience, services you offer...', 'specialist_setup.step2.phone_label': 'Phone', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Profile photo', 'specialist_setup.step2.photo_btn': 'Upload photo', 'specialist_setup.step2.photo_uploading': 'Uploading...', 'specialist_setup.step2.photo_hint': 'Shown on your profile', 'specialist_setup.step3.title': 'Service card', 'specialist_setup.step3.subtitle': 'Create your first service card', 'specialist_setup.step3.title_label': 'Card title', 'specialist_setup.step3.title_placeholder': 'E.g. Plumber, Electrician, Cleaning...', 'specialist_setup.step3.desc_label': 'Description', 'specialist_setup.step3.desc_placeholder': 'Describe in detail what you offer, your experience, advantages...', 'specialist_setup.step3.title_required': 'Title is required', 'specialist_setup.step4.title': 'Skills & Categories', 'specialist_setup.step4.subtitle': 'Add skills and select categories', 'specialist_setup.step4.skills_label': 'Skills', 'specialist_setup.step4.skills_placeholder': 'E.g. Pipe installation...', 'specialist_setup.step4.skills_add': 'Add', 'specialist_setup.step4.categories_label': 'Categories', 'specialist_setup.step5.title': 'Service area', 'specialist_setup.step5.subtitle': 'Where do you provide services?', 'specialist_setup.step5.hint': 'Select cities or specific areas', 'specialist_setup.done.title': 'Your profile is ready!', 'specialist_setup.done.subtitle': 'Congratulations! Your profile has been set up', 'specialist_setup.done.desc': 'You can now receive orders from clients. Browse tasks that match your skills.' }, ru: { 'footer.slogan': 'Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.', 'footer.links': 'Ссылки', 'footer.socials': 'Мы в соцсетях', 'nav.home': 'Главная', 'nav.tasks': 'Задачи', 'nav.post': '+ Опубликовать', 'nav.dashboard': 'Панель управления', 'nav.chat': 'Сообщения', 'nav.notifications': 'Уведомления', 'nav.profile': 'Профиль', 'nav.admin': 'Админка', 'nav.specialists': 'Специалисты', 'nav.new_task': 'Новая задача', 'nav.login': 'Войти', 'nav.register': 'Регистрация', 'nav.logout': 'Выйти', 'hero.title': 'Найди специалиста для любой работы', 'hero.subtitle': 'Опубликуй задачу, получи предложения и выбери лучшего профессионала', 'hero.cta.post': 'Опубликовать задачу', 'hero.cta.browse': 'Стать специалистом', 'hero.search.placeholder': 'Что нужно? напр. электрик, уборка...', 'stats.specialists': 'специалистов', 'stats.tasks': 'задач', 'stats.categories': 'категорий', 'stats.free': 'бесплатная регистрация', 'section.categories': 'Создай задачу в любой категории', 'section.how': 'Как это работает', 'section.recent': 'Последние задачи', 'section.all': 'Смотреть все →', 'section.more': 'ещё', 'section.cities': 'Города и районы', 'section.community': 'Общественный проект для всех', 'community.subtitle': 'CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.', 'community.point1.title': 'Умеете что-то делать?', 'community.point1.desc': 'Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.', 'community.point2.title': 'Нужна помощь?', 'community.point2.desc': 'Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.', 'community.point3.title': 'Помогите проекту расти', 'community.point3.desc': 'CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.', 'community.share': 'Поделиться с друзьями', 'community.share.copied': 'Ссылка скопирована!', // Referral section on home page 'section.referral': 'Реферальная программа', 'referral.home.subtitle': 'Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.', 'referral.home.step1.title': 'Зарегистрируйтесь и получите ссылку', 'referral.home.step1.desc': 'Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.', 'referral.home.step2.title': 'Поделитесь с друзьями', 'referral.home.step2.desc': 'Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.', 'referral.home.step3.title': 'Получайте награды', 'referral.home.step3.desc': 'Как только друг подтвердит email, вы автоматически получите свою награду.', 'referral.home.cta': 'Получить ссылку', 'referral.home.badge': 'Реферальная программа', // FAQ section 'section.faq': 'Частые вопросы', 'faq.q1': 'Как работает CanHelp?', 'faq.a1': 'Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.', 'faq.q2': 'Сколько стоит использование платформы?', 'faq.a2': 'Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.', 'faq.q3': 'Как стать специалистом?', 'faq.a3': 'Зарегистрируйтесь, перейдите в «Стать специалистом», заполните профиль навыками и категориями и начните получать задачи.', 'faq.q4': 'Как выбрать подходящего специалиста?', 'faq.a4': 'Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.', 'faq.q5': 'Что если я не доволен результатом?', 'faq.a5': 'Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.', 'faq.q6': 'Можно ли связаться со специалистом до принятия предложения?', 'faq.a6': 'Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.', 'faq.q7': 'Сколько времени ждать предложений?', 'faq.a7': 'Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.', 'faq.q8': 'Можно ли разместить задачу в любом городе Греции?', 'faq.a8': 'Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.', 'faq.q9': 'Какие виды задач есть на CanHelp?', 'faq.a9': 'Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.', 'faq.q10': 'Есть ли мобильное приложение?', 'faq.a10': 'Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.', 'how.step1.title': 'Опубликуй задачу', 'how.step1.desc': 'Опиши что нужно и установи бюджет', 'how.step2.title': 'Получи предложения', 'how.step2.desc': 'Специалисты пришлют предложения с ценой и сроками', 'how.step3.title': 'Выбери и начни', 'how.step3.desc': 'Выбери лучшего профессионала и начни сотрудничество', 'tasks.title': 'задач', 'tasks.filters': 'Фильтры', 'tasks.search': 'Поиск', 'tasks.search.placeholder': 'Название или ключевое слово...', 'tasks.search.btn': 'Поиск', 'tasks.publish': 'Опубликовать', 'tasks.category.all': 'Все', 'tasks.category.all_in': 'Все в', 'tasks.category.label': 'Категория', 'tasks.location.label': 'Город', 'tasks.location.placeholder': 'напр. Афины', 'tasks.empty': 'Задачи не найдены', 'tasks.empty.cta': 'Опубликуй первую', 'task.status.open': 'Открыта', 'task.status.in_progress': 'В работе', 'task.status.completed': 'Завершена', 'task.status.cancelled': 'Отменена', 'task.status.draft': 'Черновик', 'task.budget': 'Бюджет', 'task.location': 'Местоположение', 'task.deadline': 'Дата начала', 'task.created_at': 'Создано', 'task.customer': 'Заказчик', 'task.offer.btn': 'Отправить предложение', 'task.invite.banner_title': 'Вас пригласили на это задание', 'task.invite.banner_hint': 'Заказчик лично пригласил вас', 'task.invite.accept': 'Отправить предложение', 'task.invite.decline': 'Отказаться', 'offer.accept': 'Принять', 'offer.decline': 'Отклонить', 'task.complete': 'Завершить задачу', 'task.complete.confirm': 'Отметить задачу как выполненную?', 'task.edit': 'Редактировать', 'task.status_label': 'Статус', 'task.yours': 'Ваша задача', 'task.offer.yours': 'Ваше предложение', 'review.leave': 'Оставить отзыв', 'review.rating': 'Оценка', 'review.comment': 'Комментарий', 'review.comment.placeholder': 'Расскажите о своём опыте...', 'review.submit': 'Отправить отзыв', 'review.submitting': 'Отправка...', 'review.done': 'Отзыв отправлен!', 'profile.reviews': 'Отзывы', 'profile.no_reviews': 'Отзывов пока нет', 'profile.rating': 'Рейтинг', 'profile.skills.label': 'Навыки', 'profile.member_since': 'Участник с', 'task.offers': 'Предложения', 'task.offers.none': 'Предложений пока нет', 'create.title': 'Опубликовать задачу', 'create.field.title': 'Название', 'create.field.description': 'Описание', 'create.field.category': 'Категория', 'create.field.category.select': 'Выберите...', 'create.field.location': 'Местоположение', 'create.field.location.any': 'Где угодно', 'create.field.location.all': 'Весь город', 'create.field.budget': 'Бюджет (€)', 'create.field.deadline': 'Дата начала', 'create.field.budget_negotiable': 'Цена обсуждается', 'create.field.time_slot': 'Время выполнения', 'create.field.time_slot.any': 'В любое время', 'create.field.time_slot.morning': 'Утром (08:00–13:00)', 'create.field.time_slot.afternoon': 'Днём (13:00–18:00)', 'create.field.time_slot.evening': 'Вечером (18:00–22:00)', 'create.field.time_slot.weekend': 'Выходной', 'create.field.address': 'Адрес (необязательно)', 'create.field.address.district': 'Квартал', 'create.field.address.street': 'Улица', 'create.field.address.house': 'Дом', 'create.field.confidential': 'Конфиденциальная заметка', 'create.field.confidential.placeholder': 'Детали, видные только назначенному специалисту...', 'create.field.confidential.hint': 'Не отображается публично', 'create.field.photos': 'Фотографии', 'create.field.photos.add': 'Добавить фото', 'create.field.photos.uploading': 'Загрузка...', 'task.budget_negotiable': 'Цена обсуждается', 'task.time_slot': 'Время', 'task.confidential': 'Конфид. заметка', 'create.field.title.placeholder': 'напр. Уборка квартиры 80кв', 'create.field.description.placeholder': 'Подробно опишите что нужно...', 'create.field.location.placeholder': 'напр. Афины, Колонаки', 'create.field.budget.placeholder': 'напр. 100', 'create.submit': 'Опубликовать задачу', 'create.submitting': 'Публикация...', 'login.title': 'Добро пожаловать', 'login.subtitle': 'Вход в CanHelp', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.submitting': 'Вход...', 'login.error': 'Неверный email или пароль', 'login.unverified.title': 'Подтвердите ваш email', 'login.unverified.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'login.unverified.resend': 'Отправить письмо повторно', 'login.unverified.sending': 'Отправка...', 'login.unverified.sent': '✓ Отправлено — проверьте входящие', 'profile.email.verified': 'Email подтверждён', 'profile.email.not_verified': 'Email не подтверждён', 'login.no_account': 'Нет аккаунта?', 'login.register_link': 'Зарегистрироваться', 'login.forgot_password': 'Забыл пароль?', 'login.or_continue_with': 'или продолжите через', 'login.continue_google': 'Войти через Google', 'forgot.title': 'Забыл пароль', 'forgot.subtitle': 'Введите email для получения ссылки восстановления', 'forgot.email': 'Email', 'forgot.submit': 'Отправить ссылку', 'forgot.submitting': 'Отправка...', 'forgot.sent.title': 'Проверьте входящие', 'forgot.sent.desc': 'Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.', 'forgot.back_to_login': 'Вернуться ко входу', 'forgot.error': 'Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.', 'forgot.error.not_found': 'Аккаунт с таким email не найден.', 'forgot.error.send_failed': 'Ошибка отправки письма. Попробуйте позже.', 'reset.title': 'Новый пароль', 'reset.subtitle': 'Введите новый пароль', 'reset.password': 'Новый пароль', 'reset.confirm': 'Подтвердите пароль', 'reset.submit': 'Изменить пароль', 'reset.submitting': 'Сохранение...', 'reset.success': 'Пароль успешно изменён. Перенаправление ко входу...', 'reset.back_to_login': 'Вернуться ко входу', 'reset.error.mismatch': 'Пароли не совпадают', 'reset.error.invalid': 'Недействительная или устаревшая ссылка. Запросите новую.', 'register.title': 'Регистрация', 'register.subtitle': 'Создать аккаунт в CanHelp', 'register.first_name': 'Имя', 'register.last_name': 'Фамилия', 'register.email': 'Email', 'register.password': 'Пароль (мин. 8 символов)', 'register.role': 'Роль', 'register.role.customer': 'Пользователь', 'register.role.customer.desc': 'Публикую задачи', 'register.role.specialist': 'Специалист', 'register.role.specialist.desc': 'Беру задачи', 'register.submit': 'Создать аккаунт', 'register.submitting': 'Регистрация...', 'register.has_account': 'Уже есть аккаунт?', 'register.login_link': 'Войти', 'register.continue_google': 'Зарегистрироваться через Google', 'register.check_email.title': 'Проверьте почту', 'register.check_email.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'register.check_email.login': 'Вернуться к входу', 'dashboard.title': 'Панель управления', 'dashboard.new_task': '+ Новая задача', 'dashboard.my_tasks': 'Мои задачи', 'dashboard.my_offers': 'Мои предложения', 'dashboard.invitations': 'Приглашения на задания', 'dashboard.offers_count': 'предл.', 'dashboard.declined_count': 'откл.', 'dashboard.completed_tasks': 'Завершённые задачи', 'dashboard.completed_offers': 'Завершённые предложения', 'dashboard.review_pending': 'Оценка ещё не оставлена', 'tasks.new.top_specialists': 'Топ специалисты', 'tasks.new.select_category': 'Выберите категорию, чтобы увидеть специалистов', 'tasks.new.invite': 'Предложить работу', 'tasks.new.invited': 'Выбран ✓', 'reviews.count': 'отзывов', 'filter.location': 'Локация', 'filter.language': 'Языки', 'filter.language.any': 'Любой язык', 'filter.category.all': 'Все категории', 'user.categories': 'Категории', 'user.work_area': 'Район работы', 'dashboard.tasks.empty': 'Вы не публиковали задачи', 'dashboard.tasks.empty.cta': 'Опубликуйте первую', 'dashboard.tasks.add_new': 'Добавить новую задачу', 'dashboard.offers.empty': 'Вы не отправляли предложений', 'dashboard.offers.empty.cta': 'Найти задачи', 'dashboard.customer.specialists_title': 'Ищете исполнителя?', 'dashboard.customer.specialists_hint': 'Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи', 'dashboard.customer.specialists_cta': 'Найти исполнителя', 'dashboard.customer.how_title': 'Как это работает', 'dashboard.customer.step1': 'Создайте задачу с описанием и бюджетом', 'dashboard.customer.step2': 'Специалисты пришлют предложения с ценой и сроками', 'dashboard.customer.step3': 'Выберите подходящего и начните работу', 'notif.title': 'Уведомления', 'notif.mark_all': 'Отметить все как прочитанные', 'notif.empty': 'Нет уведомлений', 'notif.type.new_offer': 'Новое предложение', 'notif.type.offer_accepted': 'Ваше предложение принято', 'notif.type.offer_declined': 'Ваше предложение отклонено', 'notif.type.task_completed': 'Задание выполнено', 'notif.type.task_cancelled': 'Задание отменено', 'notif.type.new_message': 'Новое сообщение', 'notif.type.new_review': 'Новый отзыв', 'notif.type.task_invite': 'Приглашение на задание', 'notif.body.new_offer': 'Новое предложение на «{title}»', 'notif.body.offer_accepted': 'Ваше предложение на «{title}» принято', 'notif.body.offer_declined': 'Ваше предложение на «{title}» отклонено', 'notif.body.task_invite': 'Вас приглашают на «{title}»', 'notif.body.new_review': 'Вы получили оценку {rating}★', 'offer.status.pending': 'Ожидает', 'offer.status.accepted': 'Принято', 'offer.status.declined': 'Отклонено', 'offer.status.withdrawn': 'Отозвано', 'offer.status.other_accepted': 'Выбран другой исполнитель', 'common.loading': 'Загрузка...', 'common.error': 'Ошибка', 'common.save': 'Сохранить', 'common.saving': 'Сохранение...', 'common.cancel': 'Отмена', 'common.add': 'Добавить', 'common.close': 'Закрыть', 'common.edit': 'Редактировать', 'common.delete': 'Удалить', 'common.from': 'от', 'common.currency': '€', 'common.greece': 'Греция', // Chat 'chat.connected': 'Подключено', 'chat.disconnected': 'Отключено', 'chat.no_rooms': 'Переписок пока нет', 'chat.task_fallback': 'Задача', 'chat.select': 'Выберите переписку', 'chat.no_messages': 'Сообщений пока нет', 'chat.placeholder': 'Напишите сообщение... (Enter для отправки)', 'chat.conversation_fallback': 'Переписка', 'chat.direct_chat': 'Личный чат', 'chat.linked_task': 'Прикреплённый заказ', 'chat.write_btn': 'Написать', 'chat.just_now': 'только что', 'chat.min_ago': 'м', 'chat.write_specialist': 'Написать специалисту', 'chat.write_customer': 'Написать заказчику', 'chat.notif_settings': 'Настройки уведомлений', 'chat.notif_messages': 'Уведомления о новых сообщениях', 'chat.toast_title': 'Новое сообщение', 'chat.toast_open': 'Открыть чат', // Offer form 'offer.price': 'Цена', 'offer.price.placeholder': 'напр. 80', 'offer.customer_budget': 'Бюджет заказчика', 'offer.message': 'Сообщение', 'offer.optional': 'необязательно', 'offer.message.placeholder': 'Представьтесь, расскажите об опыте и почему вы лучший выбор...', 'offer.submitting': 'Отправка...', // Profile 'profile.photo': 'Фото профиля', 'profile.photo.change': 'Изменить фото', 'profile.photo.hint': 'JPEG, PNG, WebP · до 5MB', 'profile.basic_info': 'Основная информация', 'profile.phone': 'Телефон', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Краткое описание', 'profile.bio.placeholder': 'Расскажите немного о себе...', 'profile.language': 'Язык', 'profile.language.hint': 'Язык интерфейса и email-уведомлений', 'profile.languages': 'Языки общения', 'profile.languages.hint': 'Выберите все языки, на которых вы общаетесь', 'profile.skills': 'Навыки', 'profile.skills.subtitle': 'Добавьте услуги, которые вы предлагаете', 'profile.skills.placeholder': 'напр. Уборка, IT, Репетиторство...', 'profile.role': 'Роль аккаунта', 'profile.role.specialist': '🔧 Специалист', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Пользователь', 'profile.role.change': 'Для смены роли обратитесь в службу поддержки.', 'profile.become_specialist': 'Стать специалистом', 'profile.become_specialist.desc': 'Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.', 'become_specialist.hero.title': 'Зарабатывай, делая то, что умеешь', 'become_specialist.hero.subtitle': 'Создай профиль специалиста и получай заказы от клиентов по всей Греции', 'become_specialist.how.title': 'Как это работает', 'become_specialist.step1.title': 'Создай портфолио специалиста', 'become_specialist.step1.desc': 'Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы', 'become_specialist.step2.title': 'Ищи заказы', 'become_specialist.step2.desc': 'Просматривай задачи по своим категориям в разделе «Поиск заказов»', 'become_specialist.step3.title': 'Откликайся и зарабатывай', 'become_specialist.step3.desc': 'Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы', 'become_specialist.benefits.title': 'Преимущества профиля специалиста', 'become_specialist.benefit1': 'Поиск заказов по вашим категориям и локации', 'become_specialist.benefit2': 'Публичный профиль с отзывами клиентов', 'become_specialist.benefit3': 'Расписание доступности, видимое клиентам', 'become_specialist.benefit4': 'Добавление в избранное клиентами', 'become_specialist.cta': 'Подробнее', 'become_specialist.free_badge': 'Бесплатная регистрация', 'profile.tab.notifications': 'Уведомления', 'profile.tab.reviews': 'Отзывы', 'profile.tab.referral': 'Рефералы', 'profile.tab.auto_response': 'Авто-ответ', 'profile.tab.site': 'Сайт', 'profile.site.title': 'Персональная страница', 'profile.site.url_label': 'Личный сайт', 'profile.site.copy': 'Копировать', 'profile.site.copied': 'Скопировано', 'profile.site.visible_title': 'Что отображается на вашей странице', 'profile.site.visible.name': 'Имя и фото', 'profile.site.visible.bio': 'Биография', 'profile.site.visible.rating': 'Рейтинг и отзывы', 'profile.site.visible.portfolio': 'Портфолио / Карточки', 'profile.site.visible.contacts': 'Контактные данные', 'profile.site.visible.full_last_name': 'Фамилия полностью', 'profile.site.visible.services': 'Карточки услуг', 'profile.site.visible.reviews': 'Раздел с отзывами', 'profile.site.visible.status': 'Статус «Готов помочь»', 'profile.site.theme': 'Тема оформления', 'profile.site.theme.dark': 'Тёмная', 'profile.site.theme.light': 'Светлая', 'profile.site.slug_taken': 'Этот адрес уже занят', 'profile.site.stats.title': 'Аналитика сайта', 'profile.site.stats.days': 'последние 30 дней', 'profile.site.stats.views': 'Просмотры', 'profile.site.stats.unique': 'Уникальные посетители', 'profile.site.stats.messages': 'Сообщения', 'profile.site.stats.total_views': 'Просмотры', 'profile.site.stats.total_unique': 'Уник. посетители', 'profile.site.stats.total_messages': 'Сообщения', 'profile.site.stats.empty': 'Данных пока нет', 'profile.site.stats.loading': 'Загрузка аналитики...', 'profile.site.stats.no_slug': 'Укажите адрес сайта, чтобы видеть статистику', 'profile.site.edit_bio_hint': 'Биография и фото настраиваются во вкладке «Основное».', 'status.title': 'Статус', 'status.can_help_now_hint': 'Ваша карточка показывается выше в поиске', 'status.need_help_hint': 'Специалисты могут предложить вам помощь', 'profile.referral.title': 'Партнёрская программа', 'profile.referral.desc': 'Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.', 'profile.referral.link_label': 'Ваша реферальная ссылка', 'profile.referral.copy': 'Копировать', 'profile.referral.copied': 'Скопировано!', 'profile.referral.invited_count': 'успешных приглашений', 'profile.referral.no_code': 'Реферальный код недоступен.', 'notifications.title': 'Настройки уведомлений', 'notifications.email.new_tasks': 'Email о новых заказах', 'notifications.email.new_tasks.desc': 'Получать email, когда в ваших категориях публикуется новый заказ', 'notifications.messages.desc': 'Получать уведомление при новом входящем сообщении', 'notifications.saved': 'Настройки сохранены', 'notifications.plan_required': 'Недоступно в вашем тарифе', 'profile.tab.info': 'Основное', 'profile.tab.finance': 'Финансы', 'profile.tab.skills': 'Навыки', 'profile.tab.categories': 'Категории', 'profile.tab.geography': 'География', 'profile.specialist.categories': 'Категории работ', 'profile.specialist.categories.desc': 'Выберите категории, в которых вы работаете', 'profile.specialist.geography': 'Города покрытия', 'profile.specialist.geography.desc': 'Выберите города / районы, где вы работаете', 'profile.saving': 'Сохранение...', 'profile.upload.error': 'Ошибка загрузки фото', 'profile.saved': 'Сохранено', 'profile.tab.cards': 'Портфолио', 'profile.cards.count': 'Портфолио', 'profile.cards.add': 'Добавить портфолио', 'profile.cards.new_title': 'Название нового портфолио', 'profile.cards.placeholder': 'Например: Сантехника', 'profile.cards.create': 'Создать', 'profile.cards.cancel': 'Отмена', 'profile.cards.empty': 'У вас нет портфолио', 'profile.cards.create_first': 'Создать первое портфолио', 'profile.cards.delete_confirm': 'Удалить портфолио?', 'profile.card.tab.main': 'Основное', 'profile.card.tab.skills': 'Навыки', 'profile.card.tab.categories': 'Категории', 'profile.card.tab.geography': 'География', 'profile.card.tab.portfolio': 'Галерея', 'profile.card.active': 'Активна', 'profile.card.save': 'Сохранить', 'profile.card.saved': 'Сохранено', 'profile.card.delete': 'Удалить', 'profile.card.skill.add': 'Добавить навык', 'profile.card.photo.add': 'Добавить фото', 'profile.card.photo.uploading': 'Загрузка...', 'profile.card.photo.empty': 'Нет фотографий', 'profile.card.item.title': 'Заголовок', 'profile.card.item.desc': 'Описание', 'profile.card.item.save': 'Сохранить', 'profile.card.item.cancel': 'Отмена', 'profile.card.item.edit': 'Описание работы', 'profile.upgrade.cards_limit': 'Лимит портфолио исчерпан', 'profile.upgrade.plan': 'Текущий тариф:', 'profile.upgrade.contact': 'Обратитесь к администратору для смены тарифа', 'profile.upgrade.ok': 'Понятно', 'profile.plan.title': 'Тарифный план', 'profile.balance': 'Баланс', 'profile.balance.topup': 'Пополнить баланс', 'profile.balance.topup.title': 'Пополнить баланс', 'profile.balance.topup.amount': 'Сумма (в EUR)', 'profile.balance.topup.hint': 'Выберите сумму или введите вручную', 'profile.balance.topup.submit': 'Перейти к оплате', 'profile.balance.topup.loading': 'Перенаправление...', 'profile.balance.topup.error': 'Ошибка инициализации платежа. Попробуйте снова.', 'payment.success.title': 'Оплата прошла успешно!', 'payment.success.desc': 'Ваш баланс обновлён.', 'payment.cancelled.title': 'Оплата отменена', 'payment.cancelled.desc': 'Оплата была отменена. Средства не списаны.', 'payment.pending.title': 'Обрабатывается...', 'payment.pending.desc': 'Ваш платёж в обработке.', 'payment.back_to_profile': 'Вернуться в профиль', 'profile.plan.basic': 'Базовый (бесплатный)', 'profile.plan.contact_upgrade': 'Обратитесь к администратору для подключения тарифа', 'profile.plan.cards_up_to': 'Портфолио: до', 'profile.plan.cards_unlimited': 'Портфолио: безлимитно', 'profile.plan.tasks_up_to': 'Задач: до', 'profile.plan.offers_up_to': 'Откликов: до', 'profile.plan.valid_until': 'Действителен до', 'profile.plan.no_expiry': 'Бессрочно', // Create task 'create.error': 'Ошибка при публикации', // Tasks list extras 'tasks.category.general': 'Общее', 'tasks.budget.range': 'Диапазон:', 'tasks.budget.from': 'от', 'tasks.budget.to': 'до', 'tasks.filter.reset': 'Сбросить фильтры', 'tasks.load_more': 'Загрузить ещё', 'tasks.showing': 'Результатов:', 'tasks.field.budget': 'Бюджет, €', // Admin 'admin.title': 'Панель администратора', 'admin.tab.stats': 'Статистика', 'admin.tab.users': 'Пользователи', 'admin.tab.tasks': 'Задачи', 'admin.tab.reports': 'Жалобы', 'admin.stats.users': 'Пользователи', 'admin.stats.tasks': 'Задачи', 'admin.stats.offers': 'Предложения', 'admin.stats.reviews': 'Отзывы', 'admin.tasks.by_status': 'Задачи по статусу', 'admin.col.user': 'Пользователь', 'admin.col.email': 'Email', 'admin.col.role': 'Роль', 'admin.col.registered': 'Регистрация', 'admin.col.status': 'Статус', 'admin.col.title': 'Название', 'admin.col.budget': 'Бюджет', 'admin.col.created': 'Создано', 'admin.users.active': 'Активен', 'admin.users.inactive': 'Неактивен', 'admin.users.deactivate': 'Деактивировать', 'admin.users.activate': 'Активировать', 'admin.tasks.cancel': 'Отменить', 'admin.reports.none': 'Жалоб нет', 'admin.reports.reviewed': 'Рассмотрено', 'admin.reports.dismiss': 'Отклонить', 'admin.pagination.total': 'Всего', 'admin.users.role.change': 'Изменить роль', 'admin.users.search.placeholder': 'Поиск по имени или email...', 'admin.tasks.delete': 'Удалить', 'admin.tasks.delete.confirm': 'Удалить эту задачу навсегда?', 'admin.tasks.search.placeholder': 'Поиск по названию...', 'admin.col.customer': 'Заказчик', 'admin.col.reporter': 'Жалобщик', 'admin.col.target': 'Цель', 'admin.filter.all_roles': 'Все роли', 'admin.filter.all_statuses': 'Все статусы', 'admin.reports.target.task': 'Задача', 'admin.reports.target.user': 'Пользователь', 'admin.tab.categories': 'Категории', 'admin.tab.locations': 'Города и районы', 'admin.tab.logs': 'Логи', 'admin.tab.plans': 'Тарифы', 'admin.tab.settings': 'Настройки', 'admin.logs.subtab.ai': 'AI логи', 'admin.logs.subtab.activity': 'Активность', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Уведомления', 'admin.notif_logs.type': 'Тип', 'admin.notif_logs.title': 'Заголовок', 'admin.notif_logs.read': 'Прочитано', 'admin.notif_logs.empty': 'Логи уведомлений пусты', 'admin.stats.notif_chart_title': 'Уведомления по дням', 'admin.stats.notif_label': 'Уведомления', 'admin.stats.mail_chart_title': 'Email по дням', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Все', 'admin.stats.specialists': 'Исполнители', 'admin.col.plan': 'Тариф', 'admin.back_home': 'На главную', 'admin.plans.title': 'Тарифные пакеты', 'admin.plans.add': '+ Добавить тариф', 'admin.plans.empty': 'Тарифы не созданы', 'admin.plans.form.new': 'Новый тариф', 'admin.plans.form.edit': 'Редактировать тариф', 'admin.plans.form.name': 'Название', 'admin.plans.form.price': 'Цена (EUR)', 'admin.plans.form.old_price': 'Старая цена (EUR, необязательно)', 'admin.plans.form.max_offers': 'Макс. откликов (пусто = без лимита)', 'admin.plans.form.max_cards': 'Макс. портфолио (пусто = без лимита)', 'admin.plans.form.duration_days': 'Срок (дней, пусто = без истечения)', 'admin.plans.form.description': 'Описание', 'admin.plans.form.features': 'Возможности (по одной на строку)', 'admin.plans.form.notify': 'Уведомления о новых заказах', 'admin.plans.form.default': 'По умолчанию', 'admin.plans.form.active': 'Активен', 'admin.plans.form.order': 'Порядок', 'admin.plans.form.role': 'Роль', 'admin.plans.form.tier': 'Уровень', 'admin.plans.form.role.customer': 'Заказчик', 'admin.plans.form.role.specialist': 'Специалист', 'admin.plans.form.tier.free': 'Бесплатный', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Лимиты (пусто = без ограничений)', 'admin.plans.form.max_messages_day': 'Макс. сообщений/день', 'admin.plans.form.max_orders_day': 'Макс. заказов/день', 'admin.plans.form.max_skills': 'Макс. навыков', 'admin.plans.form.max_profiles': 'Макс. профилей', 'admin.plans.form.max_portfolio': 'Макс. элементов портфолио', 'admin.plans.form.section.boost': 'Множители & Буст', 'admin.plans.form.search_boost': 'Буст в поиске', 'admin.plans.form.offers_multiplier': 'Множитель откликов', 'admin.plans.form.section.contact': 'Права контактов', 'admin.plans.form.can_contact_free': 'Контакт с бесплатными пользователями', 'admin.plans.form.can_contact_pro': 'Контакт с Pro пользователями', 'admin.plans.form.can_contact_all': 'Контакт со всеми', 'admin.plans.form.can_show_contact': 'Показывать контакты', 'admin.plans.form.can_view_phone': 'Просмотр телефона', 'admin.plans.form.section.features': 'Возможности', 'admin.plans.form.upload_video': 'Загрузка видео', 'admin.plans.form.favorites': 'Избранное', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Знак верификации', 'admin.plans.form.highlighted_reviews': 'Выделенные отзывы', 'admin.plans.form.personal_site': 'Личный сайт', 'admin.plans.form.can_help_now': 'Статус «Могу помочь»', 'admin.plans.form.need_help': 'Статус «Нужна помощь»', 'admin.plans.form.auto_response': 'Автоответ', 'admin.plans.form.auto_match': 'Автоподбор', 'admin.plans.form.instant_dispatch_free': 'Мгновенная рассылка (бесплатно)', 'admin.plans.form.instant_dispatch_pro': 'Мгновенная рассылка (Pro)', 'admin.plans.badge.default': 'По умолчанию', 'admin.plans.badge.inactive': 'Неактивен', 'admin.plans.make_default': 'Сделать по умолчанию', 'admin.plans.tasks': 'Задач', 'admin.plans.offers': 'Откликов', 'admin.plans.cards': 'Портфолио', 'admin.plans.notify_tasks': 'Уведомления о заказах', 'admin.plans.delete.confirm': 'Удалить тариф', 'admin.activity.title': 'Журнал активности', 'admin.activity.event': 'Событие', 'admin.activity.all_events': 'Все события', 'admin.activity.from': 'От', 'admin.activity.to': 'До', 'admin.activity.reset': 'Сбросить', 'admin.activity.total': 'Всего', 'admin.activity.empty': 'Нет записей', 'admin.mail.event': 'Email событие', 'admin.mail.all_events': 'Все email события', 'admin.mail.from': 'От', 'admin.mail.to': 'До', 'admin.mail.reset': 'Сбросить', 'admin.mail.total': 'Всего', 'admin.mail.empty': 'Нет email логов', 'admin.mail.recipient': 'Получатель', 'admin.mail.provider': 'Провайдер', 'admin.mail.details': 'Детали', 'admin.mail.status': 'Статус', 'admin.mail.success': 'Успешно', 'admin.mail.failed': 'Ошибка', 'admin.event.email_sent': 'Email отправлен', 'admin.event.email_failed': 'Email не отправлен', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Тестовый email отправлен', 'admin.event.admin_email_test_failed': 'Тестовый email не отправлен', 'admin.logs.empty': 'Нет записей', 'admin.logs.date': 'Дата', 'admin.logs.provider': 'Провайдер', 'admin.logs.model': 'Модель', 'admin.logs.action': 'Действие', 'admin.logs.langs': 'Языки', 'admin.logs.in': 'Вход', 'admin.logs.out': 'Выход', 'admin.logs.total': 'Итого', 'admin.logs.ms': 'мс', 'admin.logs.status': 'Статус', 'admin.stats.activity_30d': 'Активность за 30 дней', 'admin.stats.tasks_label': 'Заявки', 'admin.stats.users_label': 'Пользователи', 'admin.stats.specialists_label': 'Исполнители', 'admin.stats.tokens_title': 'Расход токенов (по месяцам)', 'admin.stats.tokens_out': 'Исходящие', 'admin.stats.tokens_in': 'Входящие', 'admin.stats.tokens_out_label': 'Исходящие токены', 'admin.stats.tokens_in_label': 'Входящие токены', 'admin.stats.cost_label': 'Стоимость (USD)', 'admin.stats.tasks_by_status': 'Заявки по статусам', 'admin.task_status.open': 'Открытые', 'admin.task_status.in_progress': 'В работе', 'admin.task_status.completed': 'Завершённые', 'admin.task_status.cancelled': 'Отменённые', 'admin.task_status.draft': 'Черновики', 'admin.settings.tab.general': 'Общие', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Уведомления', 'admin.settings.tab.payment': 'Оплата', 'admin.settings.tab.referral': 'Реферальная', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Соцсети', 'admin.settings.socials.title': 'Ссылки на социальные сети', 'admin.settings.socials.hint': 'Заполненные ссылки отображаются в подвале сайта', 'admin.settings.seo.maintenance_label': 'Режим обслуживания', 'admin.settings.seo.maintenance_hint': 'Показывать страницу обслуживания всем посетителям', 'admin.settings.seo.indexing_label': 'Индексация поисковыми системами', 'admin.settings.seo.indexing_hint': 'Разрешить поисковым системам индексировать сайт', 'admin.settings.seo.head_scripts_label': 'Скрипты в (JS)', 'admin.settings.seo.head_scripts_hint': 'Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)', 'admin.settings.seo.site_title_label': 'Заголовок сайта', 'admin.settings.seo.site_description_label': 'Описание сайта (meta description)', 'admin.settings.referral.title': 'Партнёрская программа', 'admin.settings.referral.hint': 'Награждайте пользователей, приводящих новых участников.', 'admin.settings.referral.enabled_label': 'Включено', 'admin.settings.referral.enabled_hint': 'Включить / отключить выдачу наград', 'admin.settings.referral.customer_section': 'Для клиентов', 'admin.settings.referral.specialist_section': 'Для специалистов', 'admin.settings.referral.plan_label': 'Тарифный план за реферала', 'admin.settings.referral.no_plan': '— без плана —', 'admin.settings.referral.plan_hint': 'Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.', 'admin.settings.referral.days_label': 'Дней награды', 'admin.settings.referral.days_hint': 'Количество дней, добавляемых к сроку действия плана.', 'admin.settings.general.title': 'Общие настройки', 'admin.settings.general.site_name': 'Название сайта', 'admin.settings.general.site_url': 'URL сайта', 'admin.settings.general.contact_email': 'Email для связи', 'admin.settings.general.support_phone': 'Телефон поддержки', 'admin.settings.smtp.title': 'Настройки SMTP сервера', 'admin.settings.smtp.hint': 'Используется для отправки email-уведомлений.', 'admin.settings.smtp.host': 'SMTP Хост', 'admin.settings.smtp.port': 'Порт', 'admin.settings.smtp.encryption': 'Шифрование', 'admin.settings.smtp.enc.none': 'Нет', 'admin.settings.smtp.enc.tls': 'STARTTLS (порт 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (порт 465)', 'admin.settings.smtp.username': 'Имя пользователя', 'admin.settings.smtp.password': 'Пароль / App Password', 'admin.settings.smtp.from_name': 'Имя отправителя', 'admin.settings.smtp.from_email': 'Email отправителя', 'admin.settings.smtp.test': 'Отправить тестовый email', 'admin.settings.smtp.sending': 'Отправка...', 'admin.settings.payment.hint': 'Данные для подключения к ePay Piraeus Bank.', 'admin.settings.env.test': 'Тест (sandbox)', 'admin.settings.env.prod': 'Боевой режим', 'admin.settings.env.label': 'Среда', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Активен', 'admin.settings.saving': 'Сохранение...', 'admin.settings.saved': 'Сохранено', 'admin.notif.vars_hint': 'Доступные переменные в шаблонах', 'admin.notif.tmpl.not_set': 'Шаблон не настроен', 'admin.notif.tmpl.subject_label': 'Тема письма', 'admin.notif.tmpl.body_label': 'Текст письма (HTML)', 'admin.notif.tmpl.save': 'Сохранить', 'admin.notif.tmpl.close': 'Закрыть', 'admin.notif.tmpl.translate': 'Авто-перевод на другие языки', 'admin.notif.tmpl.translating': 'Перевод...', 'admin.notif.tmpl.saving': 'Сохранение...', 'admin.notif.email_verification': 'Подтверждение email адреса', 'admin.notif.registration_success': 'Успешная регистрация', 'admin.notif.password_reset': 'Восстановление пароля', 'admin.notif.new_offer': 'Новое предложение', 'admin.notif.new_task': 'Новая задача', 'admin.notif.offer_accepted': 'Предложение принято', 'admin.notif.new_message': 'Новое сообщение', 'admin.notif.offer_declined': 'Отклонение предложения', 'admin.notif.offer_other_accepted': 'Выбран другой исполнитель', 'admin.notif.task_updated': 'Изменение задания', 'admin.notif.deadline_reminder': 'Напоминание о дедлайне', 'admin.notif.task_archived': 'Автоснятие задания', 'admin.notif.referral_reward': 'Реферальная награда', // Шаблоны email для тарифов 'admin.email_template.plan_activated': 'Тарифы — активация тарифа', 'admin.email_template.plan_upgraded': 'Тарифы — повышение тарифа', 'admin.email_template.plan_downgrade_scheduled': 'Тарифы — запланированное понижение', 'admin.email_template.plan_downgrade_applied': 'Тарифы — применение понижения', 'admin.email_template.plan_renewal_reminder': 'Тарифы — напоминание о продлении', 'admin.email_template.plan_insufficient_funds': 'Тарифы — нехватка средств', // Модальное окно подтверждения тарифа 'pricing.confirm.title': 'Подтвердите выбор тарифа', 'pricing.confirm.plan': 'Тариф', 'pricing.confirm.prorated': 'Зачёт остатка', 'pricing.confirm.effective_price': 'К оплате', 'pricing.confirm.your_balance': 'Ваш баланс', 'pricing.confirm.downgrade_info': 'Переход на новый тариф произойдёт автоматически после окончания текущего периода.', 'pricing.confirm.insufficient': 'Недостаточно средств на балансе.', 'pricing.confirm.top_up': 'Пополнить', 'pricing.confirm.schedule_downgrade': 'Запланировать переход', 'pricing.confirm.pay': 'Оплатить', 'admin.user_edit.title': 'Редактирование пользователя', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email подтверждён', 'admin.user_edit.email_not_verified': 'Email не подтверждён', 'admin.user_edit.verify_email_btn': 'Подтвердить вручную', 'admin.user_edit.verify_email_done': 'Email подтверждён!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Регистрация', 'admin.user_edit.last_seen': 'Последний визит', 'admin.user_edit.lang': 'Язык', 'admin.user_edit.first_name': 'Имя', 'admin.user_edit.last_name': 'Фамилия', 'admin.user_edit.phone': 'Телефон', 'admin.user_edit.bio': 'О себе', 'admin.user_edit.role': 'Роль', 'admin.user_edit.plan': 'Тариф', 'admin.user_edit.no_plan': '— Без тарифа —', 'admin.user_edit.active': 'Активный аккаунт', 'admin.user_edit.balance': 'Баланс (EUR)', 'admin.user_edit.skills': 'Навыки', 'admin.user_edit.tab.profile': 'Профиль', 'admin.user_edit.tab.account': 'Аккаунт', 'admin.user_edit.tab.balance': 'Баланс', 'admin.user_edit.tab.settings': 'Настройки', 'admin.user_edit.tab.specialist': 'Портфолио', 'admin.user_edit.tab.site': 'Сайт', 'admin.user_edit.plan_expires': 'Тариф истекает', 'admin.user_edit.interface_lang': 'Язык интерфейса', 'admin.user_edit.comm_languages': 'Языки общения', 'admin.user_edit.personal_site_slug': 'Персональная страница', 'admin.user_edit.show_contact_info': 'Показывать контакты', 'admin.user_edit.show_contact_info.hint': 'Видно заказчикам', 'admin.user_edit.notify_new_tasks': 'Уведомлять о новых задачах', 'admin.user_edit.notify_new_tasks.hint': 'Push и email уведомления', 'admin.user_edit.notif_messages': 'Уведомления о сообщениях', 'admin.user_edit.notif_messages.hint': 'Новые сообщения в чате', 'admin.user_edit.site_settings': 'Настройки персональной страницы', 'admin.user_edit.categories': 'Категории услуг', 'admin.user_edit.locations': 'Районы обслуживания', 'admin.user_edit.skill_placeholder': 'Новый навык...', 'admin.user_edit.add_category': '— Выберите категорию —', 'admin.user_edit.add_location': '— Выберите район —', 'admin.user_edit.specialist_cards': 'Портфолио специалиста', 'admin.user_edit.no_cards': 'Портфолио не найдено', 'admin.user_edit.card_title': 'Заголовок портфолио', 'admin.user_edit.card_description': 'Описание', 'admin.balance.topup.btn': 'Пополнить', 'admin.balance.withdraw.btn': 'Списать', 'admin.balance.modal_hint': 'Изменения применяются сразу и фиксируются в истории', 'admin.balance.topup.title': 'Пополнение баланса', 'admin.balance.topup.amount': 'Сумма', 'admin.balance.topup.description': 'Комментарий', 'admin.balance.topup.description.placeholder': 'Например: бонус или ручное пополнение', 'admin.balance.topup.submit': 'Пополнить баланс', 'admin.balance.withdraw.title': 'Снятие баланса', 'admin.balance.withdraw.amount': 'Сумма', 'admin.balance.withdraw.description': 'Комментарий', 'admin.balance.withdraw.description.placeholder': 'Например: возврат или ручное списание', 'admin.balance.withdraw.submit': 'Списать баланс', 'admin.user_edit.role.customer': 'Заказчик', 'admin.user_edit.role.specialist': 'Исполнитель', 'admin.user_edit.role.admin': 'Администратор', 'common.refresh': 'Обновить', 'common.back_home': 'На главную', 'admin.loc.hint': 'Управление городами и районами', 'admin.loc.add_city': 'Новый город', 'admin.loc.add_district': 'Добавить район', 'admin.loc.new': 'Новая локация', 'admin.loc.edit': 'Редактировать локацию', 'admin.loc.district': 'район', 'admin.loc.empty': 'Нет локаций', 'admin.loc.delete.confirm': 'Удалить локацию? Все районы также будут удалены.', 'admin.cat.add_root': 'Новая категория', 'admin.cat.add_sub': 'Подкатегория', 'admin.cat.edit': 'Редактировать', 'admin.cat.delete': 'Удалить', 'admin.cat.delete.confirm': 'Удалить категорию? Все подкатегории также будут удалены.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Иконка', 'admin.cat.name_el': 'Греческий', 'admin.cat.name_en': 'Английский', 'admin.cat.name_ru': 'Русский', 'admin.cat.order': 'Порядок', 'admin.cat.active': 'Активна', 'admin.cat.parent': 'Родительская категория', 'admin.cat.no_parent': 'Верхний уровень', 'admin.cat.save': 'Сохранить', 'admin.cat.cancel': 'Отмена', 'admin.cat.empty': 'Нет категорий', 'admin.cat.hint': 'Управление категориями с многоуровневой иерархией', 'admin.cat.new': 'Новая категория', 'admin.cat.subcategory': 'подкатегория', 'admin.cat.add_child': 'Добавить подкатегорию', 'admin.cat.inactive': 'Неактивна', 'admin.event.user_login': 'Вход', 'admin.event.user_register': 'Регистрация', 'admin.event.admin_user_deactivate': 'Блокировка юзера', 'admin.event.admin_user_activate': 'Разблокировка юзера', 'admin.event.admin_user_role_changed': 'Смена роли', 'admin.event.admin_task_cancelled': 'Отмена задачи', 'admin.event.admin_task_deleted': 'Удаление задачи', 'admin.event.admin_report_reviewed': 'Жалоба рассмотрена', 'admin.event.admin_report_dismissed': 'Жалоба отклонена', 'admin.event.task_created': 'Создана задача', // User status 'user.online': 'Онлайн', 'user.seen_minutes': 'был здесь {n} мин назад', 'user.seen_hours': 'был здесь {n} ч назад', 'user.seen_yesterday': 'был здесь вчера', 'user.seen_days': 'был здесь {n} дн назад', // Specialists 'specialists.title': 'Специалисты', 'specialists.search': 'Поиск специалиста...', 'specialists.search.btn': 'Поиск', 'specialists.empty': 'Специалисты не найдены', 'specialists.no_bio': 'Без описания', 'specialists.view': 'Смотреть профиль', 'specialists.reviews': 'отзывов', 'specialist.favorite': 'Добавить в избранное', 'specialist.unfavorite': 'Убрать из избранного', 'specialist.site_link': 'Личный сайт', 'favorites.specialists.title': 'Избранные специалисты', 'favorites.specialists.empty': 'Вы ещё не добавили специалистов в избранное', 'nav.favorites': 'Избранное', 'nav.schedule': 'Расписание', 'nav.find_tasks': 'Поиск заказов', 'schedule.title': 'Моё расписание', 'schedule.subtitle': 'Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность', 'schedule.available': 'Свободен', 'schedule.busy': 'Занят', 'schedule.unset': 'Не указано', 'schedule.click_hint': '← клик меняет статус по кругу', 'schedule.range_mode': 'Выделить диапазон', 'schedule.range_from': 'С {date} — выберите конечную дату', 'schedule.click_to_set': 'Нажмите чтобы отметить', 'schedule.free': 'свободно', 'schedule.busy_count': 'занято', 'schedule.free_days': 'свободных дней', 'schedule.googleCalendar': 'Google Календарь', 'schedule.connectGoogle': 'Подключить Google Календарь', 'schedule.disconnectGoogle': 'Отключить', 'schedule.connectedAs': 'Подключено как', 'schedule.importFromGoogle': 'Синхр. из Google', 'schedule.gcalConnected': '\u2713 Google Календарь подключён', 'schedule.gcalError': 'Ошибка подключения Google Календарь', 'schedule.gcalImportDone': 'Импортировано {n} дней из Google Календарь', 'schedule.gcalAutoSyncNote': 'Изменения доступности автоматически отправляются в Google Календарь', 'schedule.gcalConnectDesc': 'Подключите Google Календарь для автоматической синхронизации расписания', 'schedule.gcalDisconnectConfirm': 'Отключить Google Календарь?', 'find_tasks.title': 'Поиск заказов', 'find_tasks.for_me': 'Для меня', 'find_tasks.all': 'Все заказы', 'find_tasks.by_category': 'По категориям', 'find_tasks.list': 'Списком', 'find_tasks.already_offered': 'Предложение отправлено', 'find_tasks.offer_now': 'Откликнуться', 'find_tasks.empty_for_me': 'Нет заказов в ваших категориях', 'find_tasks.banner_hint': 'Найдите заказы по категориям вашего портфолио', 'find_tasks.no_cards': 'Создайте портфолио специалиста, чтобы видеть подходящие заказы', 'find_tasks.add_card': 'Создать портфолио', 'find_tasks.search': 'Поиск заказов...', 'find_tasks.tasks_count': 'заданий', 'footer.tagline': 'Платформа задач для Греции', 'footer.rights': 'Все права защищены.', // App download section 'app.download_title': 'Скачайте мобильное приложение CanHelp', 'app.download_desc': 'Всё CanHelp — всегда под рукой. Доступно для Android и iOS.', // Nav 'nav.pricing': 'Тарифы', // Pricing page 'pricing.title': 'Тарифы', 'pricing.subtitle': 'Выберите подходящий план', 'pricing.role.customer': 'Заказчик', 'pricing.role.specialist': 'Специалист', 'pricing.free': 'Бесплатно', 'pricing.per_month': 'мес', 'pricing.duration': 'Срок', 'pricing.days': 'дн.', 'pricing.current_plan': 'Ваш план', 'pricing.popular': 'Популярный', 'pricing.choose': 'Выбрать', 'pricing.your_plan': 'Активный план', 'pricing.free_default': 'По умолчанию', 'pricing.compare': 'Сравнение функций', 'pricing.feature': 'Функция', 'pricing.faq_note': 'Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.', 'pricing.feat.messages': 'Сообщений / день', 'pricing.feat.orders': 'Заказов / день', 'pricing.feat.contact_all': 'Связь со всеми', 'pricing.feat.view_phone': 'Просмотр телефона', 'pricing.feat.show_contact': 'Показывать контакты', 'pricing.feat.favorites': 'Избранное', 'pricing.feat.verified_badge': 'Верифицированный бейдж', 'pricing.feat.google_calendar': 'Google Календарь', 'pricing.feat.personal_site': 'Персональный сайт', 'pricing.feat.auto_response': 'Авто-ответ', 'pricing.feat.auto_match': 'Авто-подбор', 'pricing.feat.highlighted_reviews': 'Выделенные отзывы', 'pricing.feat.portfolio': 'Элементов портфолио', 'pricing.feat.cards': 'Карточки специалиста', 'pricing.feat.notify_tasks': 'Уведомления о новых задачах', 'pricing.feat.video': 'Видео в портфолио', // Upgrade prompt 'upgrade.available_in': 'Доступно в', 'upgrade.cta': 'Улучшить', // Dashboard plan block 'dashboard.plan.title': 'Мой план', 'dashboard.plan.expires': 'Истекает через {n} дней', 'dashboard.plan.upgrade': 'Улучшить план', 'dashboard.plan.no_plan': 'Бесплатный план', 'dashboard.plan.messages': 'Сообщений сегодня', 'dashboard.plan.orders': 'Заказов сегодня', 'dashboard.plan.limits': 'Дневные лимиты', 'dashboard.plan.features': 'Функции', 'dashboard.plan.stats': 'Статистика', 'dashboard.stats.cards': 'Портфолио', 'dashboard.stats.maxCards': 'Макс. портфолио', 'dashboard.stats.portfolioItems': 'Элементы портфолио', 'dashboard.stats.maxPortfolioItems': 'Макс. элементы', 'dashboard.stats.activeOffers': 'Активные отклики', 'dashboard.stats.reviewsReceived': 'Отзывы', 'dashboard.stats.activeTasks': 'Активные задачи', 'dashboard.stats.completedTasks': 'Завершённые', 'status.need_help': 'Нужна помощь', 'status.active': 'Активен', 'status.toggle_on': 'Включить', 'status.toggle_off': 'Выключить', // FOMO 'fomo.missed_orders': 'Пропущено {n} заказов', 'fomo.missed_value': 'На сумму €{v}', 'fomo.upgrade_hint': 'Улучшите план — получайте больше заказов', 'fomo.conversion': 'Конверсия задач', 'fomo.active': 'Активные', 'fomo.with_offers': 'С офертами', 'fomo.completed': 'Завершённые', 'fomo.already_offered': '{n} специалистов уже откликнулись', 'fomo.specialist_missed': 'Вы пропустили {n} заказов', 'fomo.top_categories': 'Категории', 'fomo.offers_received': 'предложений получено', 'fomo.avg_offers': 'В среднем {n}/задача', 'fomo.completion_rate': 'завершено', // Task auto-match 'task.auto_match': 'Авто-матч', 'task.auto_match_results': 'Топ специалисты', 'task.no_offer_yet': 'Вы ещё не отправили предложение', 'task.make_offer': 'Отправить предложение', 'auto_response.title': 'Авто-ответ', 'auto_response.enabled': 'Включить авто-ответ', 'auto_response.min_budget': 'Мин. бюджет', 'auto_response.max_budget': 'Макс. бюджет', 'auto_response.default_price': 'Цена по умолчанию', 'auto_response.default_message': 'Сообщение по умолчанию', 'auto_response.max_per_day': 'Макс. авто-офертов в день', 'auto_response.save': 'Сохранить', 'auto_response.saved': 'Сохранено', 'auto_response.categories': 'Категории', 'auto_response.locations': 'Локации', // Personal site 'profile.personal_site': 'Персональный сайт', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Только латинские буквы, цифры, - и _', 'profile.site_open': 'Открыть сайт', 'profile.site_preview': 'Ваш сайт', 'profile.show_contact': 'Показывать контакты', 'profile.show_contact_hint': 'Заказчики с Pro/Ultimate-планом увидят ваш телефон', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Календарь требует план Pro или Ultimate', // Chat limits 'chat.limit_warning': 'Осталось {n} сообщений сегодня', 'chat.limit_reached': 'Лимит сообщений исчерпан. Улучшите план', 'chat.upgrade': 'Улучшить', // Site page 'site.member_since': 'С нами с', 'site.rating': 'Рейтинг', 'site.completed_tasks': 'Выполнено', 'site.languages': 'Языков', 'site.photos': 'фото', 'site.contact_form': 'Связаться', 'site.contact_sent': 'Сообщение отправлено!', 'site.contact_sent_desc': 'Специалист свяжется с вами в ближайшее время', 'site.contact_name': 'Имя', 'site.contact_name_ph': 'Ваше имя', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Сообщение', 'site.contact_message_ph': 'Опишите вашу задачу...', 'site.contact_send': 'Отправить', 'site.share': 'Поделиться', 'site.speaks_languages': 'Говорит на языках', 'site.message_sent': 'Сообщение отправлено!', 'site.message_sent_desc': 'Специалист получит его в чате', 'site.message_placeholder': 'Напишите сообщение...', 'site.write_to_chat': 'Написать в чат', 'site.auth_required_title': 'Нужна авторизация', 'site.auth_required_desc': 'Чтобы написать в чат, необходимо войти в аккаунт CanHelp.', 'site.auth_login_btn': 'Войти в аккаунт', 'site.auth_contact_form_btn': 'Написать через форму обратной связи', 'specialist.services': 'Услуги', 'portfolio.title': 'Портфолио', 'status.can_help_now': 'Готов помочь', 'common.not_found': 'Страница не найдена', 'common.anonymous': 'Анонимно', 'specialist_setup.page_title': 'Настройка профиля специалиста', 'specialist_setup.step_of': 'Шаг {current} из {total}', 'specialist_setup.next': 'Далее', 'specialist_setup.back': 'Назад', 'specialist_setup.skip': 'Пропустить', 'specialist_setup.finish': 'Завершить', 'specialist_setup.go_to_profile': 'Перейти в профиль', 'specialist_setup.browse_tasks': 'Найти задачи', 'specialist_setup.step1.title': 'Добро пожаловать!', 'specialist_setup.step1.subtitle': 'Давайте настроим ваш профиль', 'specialist_setup.step1.desc': 'Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.', 'specialist_setup.step1.what_next': 'Что мы сделаем:', 'specialist_setup.step1.item1': 'Заполним основную информацию', 'specialist_setup.step1.item2': 'Создадим карточку услуги', 'specialist_setup.step1.item3': 'Добавим навыки и категории', 'specialist_setup.step1.item4': 'Выберем географию обслуживания', 'specialist_setup.step1.item5': 'Загрузим фото портфолио', 'specialist_setup.step2.title': 'Базовый профиль', 'specialist_setup.step2.subtitle': 'Расскажите о себе', 'specialist_setup.step2.bio_label': 'О себе', 'specialist_setup.step2.bio_placeholder': 'Опишите ваш опыт, услуги которые вы предлагаете...', 'specialist_setup.step2.phone_label': 'Телефон', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Фото профиля', 'specialist_setup.step2.photo_btn': 'Загрузить фото', 'specialist_setup.step2.photo_uploading': 'Загрузка...', 'specialist_setup.step2.photo_hint': 'Отображается в вашем профиле', 'specialist_setup.step3.title': 'Карточка услуги', 'specialist_setup.step3.subtitle': 'Создайте вашу первую карточку услуги', 'specialist_setup.step3.title_label': 'Название карточки', 'specialist_setup.step3.title_placeholder': 'Напр. Сантехник, Электрик, Уборка...', 'specialist_setup.step3.desc_label': 'Описание', 'specialist_setup.step3.desc_placeholder': 'Подробно опишите что вы предлагаете, опыт, преимущества...', 'specialist_setup.step3.title_required': 'Название обязательно', 'specialist_setup.step4.title': 'Навыки и категории', 'specialist_setup.step4.subtitle': 'Добавьте навыки и выберите категории', 'specialist_setup.step4.skills_label': 'Навыки', 'specialist_setup.step4.skills_placeholder': 'Напр. Монтаж труб...', 'specialist_setup.step4.skills_add': 'Добавить', 'specialist_setup.step4.categories_label': 'Категории', 'specialist_setup.step5.title': 'География обслуживания', 'specialist_setup.step5.subtitle': 'Где вы оказываете услуги?', 'specialist_setup.step5.hint': 'Выберите города или конкретные районы', 'specialist_setup.done.title': 'Ваш профиль готов!', 'specialist_setup.done.subtitle': 'Поздравляем! Профиль настроен', 'specialist_setup.done.desc': 'Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам.' } }; export function getTranslations(locale) { const t = translations[locale] ?? translations.el; return (key, fallback)=>t[key] ?? translations.el[key] ?? fallback ?? key; } /06undefined268274undefined187763187769undefined, /***/ 13260:   webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource xwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource import { createAuthClient } from 'better-auth/react'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export const authClient = createAuthClient({ baseURL: API_URL }); export const { signIn, signOut, signUp, useSession } = authClient; d4FdiE"https://api.canhelp.gr"0(0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)buffersourcesizemapshash/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); const API_URL = "https://api.canhelp.gr" || 0; const authClient = (0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)({ baseURL: API_URL }); const { signIn, signOut, signUp, useSession } = authClient; {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); ReplaceSourceRawSource import { createAuthClient } from 'better-auth/react'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export const authClient = createAuthClient({ baseURL: API_URL }); export const { signIn, signOut, signUp, useSession } = authClient; 052undefined70100"https://api.canhelp.gr"undefined1051270undefined130136undefined156171(0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)undefined200206undefined /***/ }) 6/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); const API_URL = "https://api.canhelp.gr" || 0; const authClient = (0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)({ baseURL: API_URL }); const { signIn, signOut, signUp, useSession } = authClient; /***/ })   /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183);  import { createAuthClient } from 'better-auth/react'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export const authClient = createAuthClient({ baseURL: API_URL }); export const { signIn, signOut, signUp, useSession } = authClient; 052undefined70100"https://api.canhelp.gr"undefined1051270undefined130136undefined156171(0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)undefined200206undefined, /***/ 14276:  4webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource buffersourcesizemapshash {"finalSource":true}mapbufferedMap ReplaceSourceRawSource /***/ }) /***/ (() => { /***/ })  , /***/ 15043:  ;@webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource )webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcepimport { jsx as _jsx } from "react/jsx-runtime"; const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; export function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ _jsx("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ _jsx("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ _jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } `/G"%03__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._buffersourcesizemapshash const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } {"finalSource":false}mapbufferedMap ReplaceSourceRawSourcepimport { jsx as _jsx } from "react/jsx-runtime"; const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; export function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ _jsx("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ _jsx("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ _jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } 1047undefined63606366undefined65426545__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined66906693__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69606963__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefinedEW2|(0,react_jsx_runtime.jsx)! ;// ./src/components/Footer.tsx  webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcez/* __next_internal_client_entry_do_not_use__ Footer auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useLocale } from '@/context/locale'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { SocialIcons } from './SocialIcons'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Footer() { const { t } = useLocale(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = useState({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ _jsx("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ _jsx("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ _jsx("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ _jsxs("ul", { className: "space-y-2", children: [ /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ _jsx(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); } c&FZ^2_6 O R $'uxz} \_adVZH "https://api.canhelp.gr"0__WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._/* __next_internal_client_entry_do_not_use__ Footer auto */ const API = "https://api.canhelp.gr" || 0; function Footer() { const { t } = __WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = __WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__._({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("ul", { className: "space-y-2", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("li", { children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); }  z/* __next_internal_client_entry_do_not_use__ Footer auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useLocale } from '@/context/locale'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { SocialIcons } from './SocialIcons'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Footer() { const { t } = useLocale(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = useState({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ _jsx("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ _jsx("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ _jsx("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ _jsxs("ul", { className: "space-y-2", children: [ /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ _jsx(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); }  60122undefined124168undefined170213undefined215243undefined245288undefined302332"https://api.canhelp.gr"undefined3373590undefined362368undefined407415__WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined505512__WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__._undefined574582__WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined939942__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined10501054__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined11901194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13701374__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined15601563__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18111814__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined20982102__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined22622265__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined25122516__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined26882691__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27692772__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27742777__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined31513154__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32323235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32373240__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined36203623__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37013704__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37063709__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined41074110__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41884191__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41934196__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined46944698__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined48584861__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51105113__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53455348__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53505360__WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._undefined56395643__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined`_B*Eeae]  < 2 ['qs< mE,j TM 7(0,locale/* useLocale */.Y)(0,react.useState)(0,react.useEffect)(0,react_jsx_runtime.jsxs)(link_default())SocialIconsbuffersourcesizemapshash8 // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ (0,react_jsx_runtime.jsx)("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } ;// ./src/components/Footer.tsx /* __next_internal_client_entry_do_not_use__ Footer auto */ const API = "https://api.canhelp.gr" || 0; function Footer() { const { t } = (0,locale/* useLocale */.Y)(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = (0,react.useState)({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("ul", { className: "space-y-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); } {"finalSource":true}mapbufferedMap ` ConcatSourceRawSource // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx  ReplaceSourceReplaceSourceRawSourcepimport { jsx as _jsx } from "react/jsx-runtime"; const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; export function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ _jsx("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ _jsx("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ _jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } 1047undefined63606366undefined65426545__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined66906693__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69606963__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined64876561(0,react_jsx_runtime.jsx)undefined67066780(0,react_jsx_runtime.jsx)undefined70477121(0,react_jsx_runtime.jsx)undefinedRawSource! ;// ./src/components/Footer.tsx z/* __next_internal_client_entry_do_not_use__ Footer auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useLocale } from '@/context/locale'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { SocialIcons } from './SocialIcons'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Footer() { const { t } = useLocale(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = useState({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ _jsx("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ _jsx("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ _jsx("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ _jsxs("ul", { className: "space-y-2", children: [ /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ _jsx(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); }  60122undefined124168undefined170213undefined215243undefined245288undefined302332"https://api.canhelp.gr"undefined3373590undefined362368undefined407415__WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined505512__WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__._undefined574582__WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined939942__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined10501054__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined11901194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13701374__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined15601563__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18111814__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined20982102__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined22622265__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined25122516__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined26882691__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27692772__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27742777__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined31513154__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32323235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32373240__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined36203623__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37013704__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37063709__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined41074110__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41884191__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41934196__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined46944698__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined48584861__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51105113__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53455348__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53505360__WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._undefined56395643__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined146232(0,locale/* useLocale */.Y)undefined322406(0,react.useState)undefined468554(0,react.useEffect)undefined911985(0,react_jsx_runtime.jsx)undefined10931169(0,react_jsx_runtime.jsxs)undefined13051381(0,react_jsx_runtime.jsxs)undefined15571633(0,react_jsx_runtime.jsxs)undefined18191893(0,react_jsx_runtime.jsx)undefined21412215(0,react_jsx_runtime.jsx)undefined24992575(0,react_jsx_runtime.jsxs)undefined27352809(0,react_jsx_runtime.jsx)undefined30563132(0,react_jsx_runtime.jsxs)undefined33043378(0,react_jsx_runtime.jsx)undefined34563530(0,react_jsx_runtime.jsx)undefined35323609(link_default())undefined39834057(0,react_jsx_runtime.jsx)undefined41354209(0,react_jsx_runtime.jsx)undefined42114288(link_default())undefined46684742(0,react_jsx_runtime.jsx)undefined48204894(0,react_jsx_runtime.jsx)undefined48964973(link_default())undefined53715445(0,react_jsx_runtime.jsx)undefined55235597(0,react_jsx_runtime.jsx)undefined55995676(link_default())undefined61746250(0,react_jsx_runtime.jsxs)undefined64106484(0,react_jsx_runtime.jsx)undefined67336807(0,react_jsx_runtime.jsx)undefined70397113(0,react_jsx_runtime.jsx)undefined71157200SocialIconsundefined74797555(0,react_jsx_runtime.jsxs)undefined /***/ }) i8/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ (0,react_jsx_runtime.jsx)("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } ;// ./src/components/Footer.tsx /* __next_internal_client_entry_do_not_use__ Footer auto */ const API = "https://api.canhelp.gr" || 0; function Footer() { const { t } = (0,locale/* useLocale */.Y)(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = (0,react.useState)({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("ul", { className: "space-y-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); } /***/ })  ` // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx  ReplaceSourcepimport { jsx as _jsx } from "react/jsx-runtime"; const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; export function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ _jsx("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ _jsx("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ _jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } 1047undefined63606366undefined65426545__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined66906693__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69606963__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined64876561(0,react_jsx_runtime.jsx)undefined67066780(0,react_jsx_runtime.jsx)undefined70477121(0,react_jsx_runtime.jsx)undefinedRawSource! ;// ./src/components/Footer.tsx z/* __next_internal_client_entry_do_not_use__ Footer auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useLocale } from '@/context/locale'; import { useEffect, useState } from 'react'; import Link from 'next/link'; import { SocialIcons } from './SocialIcons'; const API = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Footer() { const { t } = useLocale(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = useState({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ _jsx("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ _jsx("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ _jsx("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ _jsxs("ul", { className: "space-y-2", children: [ /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ _jsx("li", { children: /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ _jsx("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ _jsx("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ _jsx(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ _jsxs("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); }  60122undefined124168undefined170213undefined215243undefined245288undefined302332"https://api.canhelp.gr"undefined3373590undefined362368undefined407415__WEBPACK_MODULE_REFERENCE__1_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined505512__WEBPACK_MODULE_REFERENCE__2_5b227573655374617465225d_call_directImport_asiSafe1__._undefined574582__WEBPACK_MODULE_REFERENCE__2_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined939942__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined10501054__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined11901194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13701374__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined15601563__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18111814__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined20982102__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined22622265__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined25122516__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined26882691__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27692772__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined27742777__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined31513154__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32323235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32373240__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined36203623__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37013704__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined37063709__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined41074110__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41884191__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined41934196__WEBPACK_MODULE_REFERENCE__3_5b2264656661756c74225d_directImport_asiSafe1__._undefined46944698__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined48584861__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51105113__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53455348__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined53505360__WEBPACK_MODULE_REFERENCE__4_5b22536f6369616c49636f6e73225d_directImport_asiSafe1__._undefined56395643__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined146232(0,locale/* useLocale */.Y)undefined322406(0,react.useState)undefined468554(0,react.useEffect)undefined911985(0,react_jsx_runtime.jsx)undefined10931169(0,react_jsx_runtime.jsxs)undefined13051381(0,react_jsx_runtime.jsxs)undefined15571633(0,react_jsx_runtime.jsxs)undefined18191893(0,react_jsx_runtime.jsx)undefined21412215(0,react_jsx_runtime.jsx)undefined24992575(0,react_jsx_runtime.jsxs)undefined27352809(0,react_jsx_runtime.jsx)undefined30563132(0,react_jsx_runtime.jsxs)undefined33043378(0,react_jsx_runtime.jsx)undefined34563530(0,react_jsx_runtime.jsx)undefined35323609(link_default())undefined39834057(0,react_jsx_runtime.jsx)undefined41354209(0,react_jsx_runtime.jsx)undefined42114288(link_default())undefined46684742(0,react_jsx_runtime.jsx)undefined48204894(0,react_jsx_runtime.jsx)undefined48964973(link_default())undefined53715445(0,react_jsx_runtime.jsx)undefined55235597(0,react_jsx_runtime.jsx)undefined55995676(link_default())undefined61746250(0,react_jsx_runtime.jsxs)undefined64106484(0,react_jsx_runtime.jsx)undefined67336807(0,react_jsx_runtime.jsx)undefined70397113(0,react_jsx_runtime.jsx)undefined71157200SocialIconsundefined74797555(0,react_jsx_runtime.jsxs)undefined, /***/ 20138:  ?webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider) /* harmony export */ }); /* unused harmony export useLocale */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocaleProvider = registerClientReference( function() { throw new Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "LocaleProvider", );export const useLocale = registerClientReference( function() { throw new Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "useLocale", ); `=H(>(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)buffersourcesizemapshash/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider) /* harmony export */ }); /* unused harmony export useLocale */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const LocaleProvider = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "LocaleProvider", );const useLocale = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "useLocale", ); {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider) /* harmony export */ }); /* unused harmony export useLocale */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); ReplaceSourceRawSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocaleProvider = registerClientReference( function() { throw new Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "LocaleProvider", );export const useLocale = registerClientReference( function() { throw new Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "useLocale", );61134undefined136142undefined166188(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined527533undefined552574(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined /***/ }) /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider) /* harmony export */ }); /* unused harmony export useLocale */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const LocaleProvider = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "LocaleProvider", );const useLocale = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "useLocale", ); /***/ })   /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider) /* harmony export */ }); /* unused harmony export useLocale */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocaleProvider = registerClientReference( function() { throw new Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "LocaleProvider", );export const useLocale = registerClientReference( function() { throw new Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "useLocale", );61134undefined136142undefined166188(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined527533undefined552574(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined, /***/ 21046:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource/* __next_internal_client_entry_do_not_use__ ScrollToTopButton auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { useEffect, useState } from 'react'; export function ScrollToTopButton() { const [visible, setVisible] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ setVisible(window.scrollY > 200); }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsx("button", { className: `scroll-to-top-btn${visible ? ' visible' : ''}`, "aria-label": "Наверх", onClick: ()=>window.scrollTo({ top: 0, behavior: 'smooth' }), children: /*#__PURE__*/ _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /*#__PURE__*/ _jsx("path", { d: "M10 16V4M10 4L4 10M10 4L16 10", stroke: "white", strokeWidth: "2.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }); } bGvxL5=:=AD(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)buffersourcesizemapshash7/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* __next_internal_client_entry_do_not_use__ ScrollToTopButton auto */ function ScrollToTopButton() { const [visible, setVisible] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const onScroll = ()=>{ setVisible(window.scrollY > 200); }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { className: `scroll-to-top-btn${visible ? ' visible' : ''}`, "aria-label": "Наверх", onClick: ()=>window.scrollTo({ top: 0, behavior: 'smooth' }), children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M10 16V4M10 4L4 10M10 4L16 10", stroke: "white", strokeWidth: "2.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }); } {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); ReplaceSourceRawSource/* __next_internal_client_entry_do_not_use__ ScrollToTopButton auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { useEffect, useState } from 'react'; export function ScrollToTopButton() { const [visible, setVisible] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ setVisible(window.scrollY > 200); }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsx("button", { className: `scroll-to-top-btn${visible ? ' visible' : ''}`, "aria-label": "Наверх", onClick: ()=>window.scrollTo({ top: 0, behavior: 'smooth' }), children: /*#__PURE__*/ _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /*#__PURE__*/ _jsx("path", { d: "M10 16V4M10 4L4 10M10 4L16 10", stroke: "white", strokeWidth: "2.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }); } z71118undefined120163undefined165171undefined237244(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined309317(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined570573(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined833836(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined10431046(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined /***/ }) /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* __next_internal_client_entry_do_not_use__ ScrollToTopButton auto */ function ScrollToTopButton() { const [visible, setVisible] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const onScroll = ()=>{ setVisible(window.scrollY > 200); }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { className: `scroll-to-top-btn${visible ? ' visible' : ''}`, "aria-label": "Наверх", onClick: ()=>window.scrollTo({ top: 0, behavior: 'smooth' }), children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M10 16V4M10 4L4 10M10 4L16 10", stroke: "white", strokeWidth: "2.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }); } /***/ })   /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* __next_internal_client_entry_do_not_use__ ScrollToTopButton auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { useEffect, useState } from 'react'; export function ScrollToTopButton() { const [visible, setVisible] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ setVisible(window.scrollY > 200); }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsx("button", { className: `scroll-to-top-btn${visible ? ' visible' : ''}`, "aria-label": "Наверх", onClick: ()=>window.scrollTo({ top: 0, behavior: 'smooth' }), children: /*#__PURE__*/ _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /*#__PURE__*/ _jsx("path", { d: "M10 16V4M10 4L4 10M10 4L16 10", stroke: "white", strokeWidth: "2.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }); } z71118undefined120163undefined165171undefined237244(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined309317(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined570573(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined833836(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined10431046(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined, /***/ 30460:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { /* (ignored) */  /***/ })   , /***/ 32948:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource wwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource)// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const ScrollToTopButton = registerClientReference( function() { throw new Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx", "ScrollToTopButton", ); `=D(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)buffersourcesizemapshash/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const ScrollToTopButton = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx", "ScrollToTopButton", ); {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); ReplaceSourceRawSource)// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const ScrollToTopButton = registerClientReference( function() { throw new Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx", "ScrollToTopButton", );61134undefined136142undefined169191(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined /***/ }) e/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const ScrollToTopButton = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx", "ScrollToTopButton", ); /***/ })   /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); )// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const ScrollToTopButton = registerClientReference( function() { throw new Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx", "ScrollToTopButton", );61134undefined136142undefined169191(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined, /***/ 33506:  zwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NotFound) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import Link from 'next/link'; export default function NotFound() { return /*#__PURE__*/ _jsx("div", { className: "min-h-screen flex items-center justify-center text-center px-4", children: /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h1", { className: "text-8xl font-bold text-blue-600 mb-4", children: "404" }), /*#__PURE__*/ _jsx("p", { className: "text-xl text-gray-700 mb-6", children: "Η σελίδα δεν βρέθηκε" }), /*#__PURE__*/ _jsx(Link, { href: "/", className: "bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700", children: "Επιστροφή στην Αρχική" }) ] }) }); }  d>@\^lK#dg(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(next_link__WEBPACK_IMPORTED_MODULE_1___default())buffersourcesizemapshashl__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NotFound) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); function NotFound() { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "min-h-screen flex items-center justify-center text-center px-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-8xl font-bold text-blue-600 mb-4", children: "404" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xl text-gray-700 mb-6", children: "Η σελίδα δεν βρέθηκε" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)((next_link__WEBPACK_IMPORTED_MODULE_1___default()), { href: "/", className: "bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700", children: "Επιστροφή στην Αρχική" }) ] }) }); } {"finalSource":true}mapbufferedMap ConcatSourceRawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NotFound) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); ReplaceSourceRawSourceimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import Link from 'next/link'; export default function NotFound() { return /*#__PURE__*/ _jsx("div", { className: "min-h-screen flex items-center justify-center text-center px-4", children: /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h1", { className: "text-8xl font-bold text-blue-600 mb-4", children: "404" }), /*#__PURE__*/ _jsx("p", { className: "text-xl text-gray-700 mb-6", children: "Η σελίδα δεν βρέθηκε" }), /*#__PURE__*/ _jsx(Link, { href: "/", className: "bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700", children: "Επιστροφή στην Αρχική" }) ] }) }); } 062undefined6492undefined94108undefined156159(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined287291(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined356359(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined527530(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined703706(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined708711(next_link__WEBPACK_IMPORTED_MODULE_1___default())undefined /***/ }) /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NotFound) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); function NotFound() { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "min-h-screen flex items-center justify-center text-center px-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-8xl font-bold text-blue-600 mb-4", children: "404" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xl text-gray-700 mb-6", children: "Η σελίδα δεν βρέθηκε" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)((next_link__WEBPACK_IMPORTED_MODULE_1___default()), { href: "/", className: "bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700", children: "Επιστροφή στην Αρχική" }) ] }) }); } /***/ })   __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NotFound) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import Link from 'next/link'; export default function NotFound() { return /*#__PURE__*/ _jsx("div", { className: "min-h-screen flex items-center justify-center text-center px-4", children: /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h1", { className: "text-8xl font-bold text-blue-600 mb-4", children: "404" }), /*#__PURE__*/ _jsx("p", { className: "text-xl text-gray-700 mb-6", children: "Η σελίδα δεν βρέθηκε" }), /*#__PURE__*/ _jsx(Link, { href: "/", className: "bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700", children: "Επιστροφή στην Αρχική" }) ] }) }); } 062undefined6492undefined94108undefined156159(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined287291(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined356359(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined527530(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined703706(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined708711(next_link__WEBPACK_IMPORTED_MODULE_1___default())undefined, /***/ 39348:  (webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource *webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Footer: () => (/* binding */ Footer) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Footer = registerClientReference( function() { throw new Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Footer.tsx", "Footer", ); `=D(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)buffersourcesizemapshash/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Footer: () => (/* binding */ Footer) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const Footer = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Footer.tsx", "Footer", ); {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Footer: () => (/* binding */ Footer) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); ReplaceSourceRawSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Footer = registerClientReference( function() { throw new Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Footer.tsx", "Footer", );61134undefined136142undefined158180(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined /***/ }) ~/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Footer: () => (/* binding */ Footer) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const Footer = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Footer.tsx", "Footer", ); /***/ })   /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Footer: () => (/* binding */ Footer) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Footer = registerClientReference( function() { throw new Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Footer.tsx", "Footer", );61134undefined136142undefined158180(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined, /***/ 47570:  Pwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ RootLayout), /* harmony export */ generateMetadata: () => (/* binding */ generateMetadata) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56057); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14276); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_globals_css__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _components_Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67674); /* harmony import */ var _components_Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39348); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(20138); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1697); /* harmony import */ var _components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32948); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { cookies, headers } from 'next/headers'; import './globals.css'; import { Header } from '@/components/Header'; import { Footer } from '@/components/Footer'; import { LocaleProvider } from '@/context/locale'; import { LocationProvider } from '@/context/location'; import { ScrollToTopButton } from '@/components/ScrollToTopButton'; async function fetchSeoSettings() { try { const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const res = await fetch(`${apiBase}/api/admin/seo-public`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return res.json(); } catch { return {}; } } export async function generateMetadata() { const seo = await fetchSeoSettings(); return { title: seo['seo.siteTitle'] || 'CanHelp — Βρες ειδικό για κάθε δουλειά', description: seo['seo.siteDescription'] || 'Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.', keywords: 'εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά', robots: seo['seo.indexingEnabled'] === 'false' ? 'noindex, nofollow' : undefined }; } export default async function RootLayout({ children }) { const cookieStore = await cookies(); const headerStore = await headers(); const pathname = headerStore.get('x-pathname') ?? ''; const isStandalone = pathname.startsWith('/site/'); const rawLocale = cookieStore.get('canhelp_locale')?.value; const locales = [ 'el', 'en', 'ru' ]; const initialLocale = locales.includes(rawLocale) ? rawLocale : 'el'; const initialLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const seo = await fetchSeoSettings(); const headScripts = seo['seo.headScripts'] ?? ''; const parsedScripts = []; if (headScripts.trim()) { const re = /]*)>([\s\S]*?)<\/script>|]*)\/>/gi; let m; while((m = re.exec(headScripts)) !== null){ const attrs = m[1] ?? m[3] ?? ''; const inline = (m[2] ?? '').trim(); const srcMatch = attrs.match(/src=["']([^"']+)["']/); parsedScripts.push({ src: srcMatch?.[1], async: /\basync\b/i.test(attrs), defer: /\bdefer\b/i.test(attrs), inline: inline || undefined }); } } return /*#__PURE__*/ _jsxs("html", { lang: initialLocale, children: [ /*#__PURE__*/ _jsx("head", { children: parsedScripts.map((s, i)=>{ if (s.src) return /*#__PURE__*/ _jsx("script", { src: s.src, async: s.async, defer: s.defer }, i); if (s.inline) return /*#__PURE__*/ _jsx("script", { dangerouslySetInnerHTML: { __html: s.inline } }, i); return null; }) }), /*#__PURE__*/ _jsx("body", { children: /*#__PURE__*/ _jsx(LocaleProvider, { initialLocale: initialLocale, children: /*#__PURE__*/ _jsxs(LocationProvider, { initialSlug: initialLocation, children: [ !isStandalone && /*#__PURE__*/ _jsx(Header, {}), /*#__PURE__*/ _jsx("main", { className: "min-h-screen", children: children }), !isStandalone && /*#__PURE__*/ _jsx(ScrollToTopButton, {}), !isStandalone && /*#__PURE__*/ _jsx(Footer, {}) ] }) }) }) ] }); } e>@oq_MO  .w}( , V    146;mpEHJZ"https://api.canhelp.gr"0(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .cookies */ .UL)(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .headers */ .b3)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)_context_locale__WEBPACK_IMPORTED_MODULE_5__.LocaleProvider_context_location__WEBPACK_IMPORTED_MODULE_6__.LocationProvider_components_Header__WEBPACK_IMPORTED_MODULE_3__.Header_components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__.ScrollToTopButton_components_Footer__WEBPACK_IMPORTED_MODULE_4__.Footerbuffersourcesizemapshash__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ RootLayout), /* harmony export */ generateMetadata: () => (/* binding */ generateMetadata) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56057); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14276); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_globals_css__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _components_Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67674); /* harmony import */ var _components_Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39348); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(20138); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1697); /* harmony import */ var _components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32948); async function fetchSeoSettings() { try { const apiBase = "https://api.canhelp.gr" || 0; const res = await fetch(`${apiBase}/api/admin/seo-public`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return res.json(); } catch { return {}; } } async function generateMetadata() { const seo = await fetchSeoSettings(); return { title: seo['seo.siteTitle'] || 'CanHelp — Βρες ειδικό για κάθε δουλειά', description: seo['seo.siteDescription'] || 'Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.', keywords: 'εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά', robots: seo['seo.indexingEnabled'] === 'false' ? 'noindex, nofollow' : undefined }; } async function RootLayout({ children }) { const cookieStore = await (0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .cookies */ .UL)(); const headerStore = await (0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .headers */ .b3)(); const pathname = headerStore.get('x-pathname') ?? ''; const isStandalone = pathname.startsWith('/site/'); const rawLocale = cookieStore.get('canhelp_locale')?.value; const locales = [ 'el', 'en', 'ru' ]; const initialLocale = locales.includes(rawLocale) ? rawLocale : 'el'; const initialLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const seo = await fetchSeoSettings(); const headScripts = seo['seo.headScripts'] ?? ''; const parsedScripts = []; if (headScripts.trim()) { const re = /]*)>([\s\S]*?)<\/script>|]*)\/>/gi; let m; while((m = re.exec(headScripts)) !== null){ const attrs = m[1] ?? m[3] ?? ''; const inline = (m[2] ?? '').trim(); const srcMatch = attrs.match(/src=["']([^"']+)["']/); parsedScripts.push({ src: srcMatch?.[1], async: /\basync\b/i.test(attrs), defer: /\bdefer\b/i.test(attrs), inline: inline || undefined }); } } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("html", { lang: initialLocale, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("head", { children: parsedScripts.map((s, i)=>{ if (s.src) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("script", { src: s.src, async: s.async, defer: s.defer }, i); if (s.inline) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("script", { dangerouslySetInnerHTML: { __html: s.inline } }, i); return null; }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("body", { children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_context_locale__WEBPACK_IMPORTED_MODULE_5__.LocaleProvider, { initialLocale: initialLocale, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_context_location__WEBPACK_IMPORTED_MODULE_6__.LocationProvider, { initialSlug: initialLocation, children: [ !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_Header__WEBPACK_IMPORTED_MODULE_3__.Header, {}), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("main", { className: "min-h-screen", children: children }), !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__.ScrollToTopButton, {}), !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_Footer__WEBPACK_IMPORTED_MODULE_4__.Footer, {}) ] }) }) }) ] }); } {"finalSource":true}mapbufferedMap ConcatSourceRawSource__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ RootLayout), /* harmony export */ generateMetadata: () => (/* binding */ generateMetadata) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56057); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14276); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_globals_css__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _components_Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67674); /* harmony import */ var _components_Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39348); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(20138); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1697); /* harmony import */ var _components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32948); ReplaceSourceRawSourceimport { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { cookies, headers } from 'next/headers'; import './globals.css'; import { Header } from '@/components/Header'; import { Footer } from '@/components/Footer'; import { LocaleProvider } from '@/context/locale'; import { LocationProvider } from '@/context/location'; import { ScrollToTopButton } from '@/components/ScrollToTopButton'; async function fetchSeoSettings() { try { const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const res = await fetch(`${apiBase}/api/admin/seo-public`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return res.json(); } catch { return {}; } } export async function generateMetadata() { const seo = await fetchSeoSettings(); return { title: seo['seo.siteTitle'] || 'CanHelp — Βρες ειδικό για κάθε δουλειά', description: seo['seo.siteDescription'] || 'Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.', keywords: 'εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά', robots: seo['seo.indexingEnabled'] === 'false' ? 'noindex, nofollow' : undefined }; } export default async function RootLayout({ children }) { const cookieStore = await cookies(); const headerStore = await headers(); const pathname = headerStore.get('x-pathname') ?? ''; const isStandalone = pathname.startsWith('/site/'); const rawLocale = cookieStore.get('canhelp_locale')?.value; const locales = [ 'el', 'en', 'ru' ]; const initialLocale = locales.includes(rawLocale) ? rawLocale : 'el'; const initialLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const seo = await fetchSeoSettings(); const headScripts = seo['seo.headScripts'] ?? ''; const parsedScripts = []; if (headScripts.trim()) { const re = /]*)>([\s\S]*?)<\/script>|]*)\/>/gi; let m; while((m = re.exec(headScripts)) !== null){ const attrs = m[1] ?? m[3] ?? ''; const inline = (m[2] ?? '').trim(); const srcMatch = attrs.match(/src=["']([^"']+)["']/); parsedScripts.push({ src: srcMatch?.[1], async: /\basync\b/i.test(attrs), defer: /\bdefer\b/i.test(attrs), inline: inline || undefined }); } } return /*#__PURE__*/ _jsxs("html", { lang: initialLocale, children: [ /*#__PURE__*/ _jsx("head", { children: parsedScripts.map((s, i)=>{ if (s.src) return /*#__PURE__*/ _jsx("script", { src: s.src, async: s.async, defer: s.defer }, i); if (s.inline) return /*#__PURE__*/ _jsx("script", { dangerouslySetInnerHTML: { __html: s.inline } }, i); return null; }) }), /*#__PURE__*/ _jsx("body", { children: /*#__PURE__*/ _jsx(LocaleProvider, { initialLocale: initialLocale, children: /*#__PURE__*/ _jsxs(LocationProvider, { initialSlug: initialLocation, children: [ !isStandalone && /*#__PURE__*/ _jsx(Header, {}), /*#__PURE__*/ _jsx("main", { className: "min-h-screen", children: children }), !isStandalone && /*#__PURE__*/ _jsx(ScrollToTopButton, {}), !isStandalone && /*#__PURE__*/ _jsx(Footer, {}) ] }) }) }) ] }); } 062undefined64111undefined113135undefined137181undefined183227undefined229278undefined280333undefined335401undefined473503"https://api.canhelp.gr"undefined5085300undefined780786undefined13121326undefined13991405(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .cookies */ .UL)undefined14401446(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .headers */ .b3)undefined26002604(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined26912694(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined28122815(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined30263029(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined32863289(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33413344(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33463359_context_locale__WEBPACK_IMPORTED_MODULE_5__.LocaleProviderundefined34583462(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined34643479_context_location__WEBPACK_IMPORTED_MODULE_6__.LocationProviderundefined36333636(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined36383643_components_Header__WEBPACK_IMPORTED_MODULE_3__.Headerundefined36933696(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined39093912(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined39143930_components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__.ScrollToTopButtonundefined39974000(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined40024007_components_Footer__WEBPACK_IMPORTED_MODULE_4__.Footerundefined /***/ }) sz/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ RootLayout), /* harmony export */ generateMetadata: () => (/* binding */ generateMetadata) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56057); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14276); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_globals_css__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _components_Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67674); /* harmony import */ var _components_Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39348); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(20138); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1697); /* harmony import */ var _components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32948); async function fetchSeoSettings() { try { const apiBase = "https://api.canhelp.gr" || 0; const res = await fetch(`${apiBase}/api/admin/seo-public`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return res.json(); } catch { return {}; } } async function generateMetadata() { const seo = await fetchSeoSettings(); return { title: seo['seo.siteTitle'] || 'CanHelp — Βρες ειδικό για κάθε δουλειά', description: seo['seo.siteDescription'] || 'Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.', keywords: 'εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά', robots: seo['seo.indexingEnabled'] === 'false' ? 'noindex, nofollow' : undefined }; } async function RootLayout({ children }) { const cookieStore = await (0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .cookies */ .UL)(); const headerStore = await (0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .headers */ .b3)(); const pathname = headerStore.get('x-pathname') ?? ''; const isStandalone = pathname.startsWith('/site/'); const rawLocale = cookieStore.get('canhelp_locale')?.value; const locales = [ 'el', 'en', 'ru' ]; const initialLocale = locales.includes(rawLocale) ? rawLocale : 'el'; const initialLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const seo = await fetchSeoSettings(); const headScripts = seo['seo.headScripts'] ?? ''; const parsedScripts = []; if (headScripts.trim()) { const re = /]*)>([\s\S]*?)<\/script>|]*)\/>/gi; let m; while((m = re.exec(headScripts)) !== null){ const attrs = m[1] ?? m[3] ?? ''; const inline = (m[2] ?? '').trim(); const srcMatch = attrs.match(/src=["']([^"']+)["']/); parsedScripts.push({ src: srcMatch?.[1], async: /\basync\b/i.test(attrs), defer: /\bdefer\b/i.test(attrs), inline: inline || undefined }); } } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("html", { lang: initialLocale, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("head", { children: parsedScripts.map((s, i)=>{ if (s.src) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("script", { src: s.src, async: s.async, defer: s.defer }, i); if (s.inline) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("script", { dangerouslySetInnerHTML: { __html: s.inline } }, i); return null; }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("body", { children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_context_locale__WEBPACK_IMPORTED_MODULE_5__.LocaleProvider, { initialLocale: initialLocale, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_context_location__WEBPACK_IMPORTED_MODULE_6__.LocationProvider, { initialSlug: initialLocation, children: [ !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_Header__WEBPACK_IMPORTED_MODULE_3__.Header, {}), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("main", { className: "min-h-screen", children: children }), !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__.ScrollToTopButton, {}), !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_Footer__WEBPACK_IMPORTED_MODULE_4__.Footer, {}) ] }) }) }) ] }); } /***/ }) tw  xx__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ RootLayout), /* harmony export */ generateMetadata: () => (/* binding */ generateMetadata) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56057); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14276); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_globals_css__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _components_Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67674); /* harmony import */ var _components_Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39348); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(20138); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1697); /* harmony import */ var _components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32948); import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { cookies, headers } from 'next/headers'; import './globals.css'; import { Header } from '@/components/Header'; import { Footer } from '@/components/Footer'; import { LocaleProvider } from '@/context/locale'; import { LocationProvider } from '@/context/location'; import { ScrollToTopButton } from '@/components/ScrollToTopButton'; async function fetchSeoSettings() { try { const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const res = await fetch(`${apiBase}/api/admin/seo-public`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return res.json(); } catch { return {}; } } export async function generateMetadata() { const seo = await fetchSeoSettings(); return { title: seo['seo.siteTitle'] || 'CanHelp — Βρες ειδικό για κάθε δουλειά', description: seo['seo.siteDescription'] || 'Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.', keywords: 'εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά', robots: seo['seo.indexingEnabled'] === 'false' ? 'noindex, nofollow' : undefined }; } export default async function RootLayout({ children }) { const cookieStore = await cookies(); const headerStore = await headers(); const pathname = headerStore.get('x-pathname') ?? ''; const isStandalone = pathname.startsWith('/site/'); const rawLocale = cookieStore.get('canhelp_locale')?.value; const locales = [ 'el', 'en', 'ru' ]; const initialLocale = locales.includes(rawLocale) ? rawLocale : 'el'; const initialLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const seo = await fetchSeoSettings(); const headScripts = seo['seo.headScripts'] ?? ''; const parsedScripts = []; if (headScripts.trim()) { const re = /]*)>([\s\S]*?)<\/script>|]*)\/>/gi; let m; while((m = re.exec(headScripts)) !== null){ const attrs = m[1] ?? m[3] ?? ''; const inline = (m[2] ?? '').trim(); const srcMatch = attrs.match(/src=["']([^"']+)["']/); parsedScripts.push({ src: srcMatch?.[1], async: /\basync\b/i.test(attrs), defer: /\bdefer\b/i.test(attrs), inline: inline || undefined }); } } return /*#__PURE__*/ _jsxs("html", { lang: initialLocale, children: [ /*#__PURE__*/ _jsx("head", { children: parsedScripts.map((s, i)=>{ if (s.src) return /*#__PURE__*/ _jsx("script", { src: s.src, async: s.async, defer: s.defer }, i); if (s.inline) return /*#__PURE__*/ _jsx("script", { dangerouslySetInnerHTML: { __html: s.inline } }, i); return null; }) }), /*#__PURE__*/ _jsx("body", { children: /*#__PURE__*/ _jsx(LocaleProvider, { initialLocale: initialLocale, children: /*#__PURE__*/ _jsxs(LocationProvider, { initialSlug: initialLocation, children: [ !isStandalone && /*#__PURE__*/ _jsx(Header, {}), /*#__PURE__*/ _jsx("main", { className: "min-h-screen", children: children }), !isStandalone && /*#__PURE__*/ _jsx(ScrollToTopButton, {}), !isStandalone && /*#__PURE__*/ _jsx(Footer, {}) ] }) }) }) ] }); } 062undefined64111undefined113135undefined137181undefined183227undefined229278undefined280333undefined335401undefined473503"https://api.canhelp.gr"undefined5085300undefined780786undefined13121326undefined13991405(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .cookies */ .UL)undefined14401446(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .headers */ .b3)undefined26002604(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined26912694(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined28122815(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined30263029(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined32863289(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33413344(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33463359_context_locale__WEBPACK_IMPORTED_MODULE_5__.LocaleProviderundefined34583462(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined34643479_context_location__WEBPACK_IMPORTED_MODULE_6__.LocationProviderundefined36333636(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined36383643_components_Header__WEBPACK_IMPORTED_MODULE_3__.Headerundefined36933696(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined39093912(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined39143930_components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__.ScrollToTopButtonundefined39974000(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined40024007_components_Footer__WEBPACK_IMPORTED_MODULE_4__.Footerundefinedwy, /***/ 48178:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ E: () => (/* binding */ shortName), /* harmony export */ H: () => (/* binding */ formatShortName) /* harmony export */ }); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource$/** * Shortens the last name to first letter + period. * "Иван Петров" → "Иван П." * Works with a pre-composed full name string. */ export function shortName(fullName) { if (!fullName?.trim()) return '—'; const parts = fullName.trim().split(/\s+/); if (parts.length < 2 || !parts[1]) return parts[0]; return `${parts[0]} ${parts[1][0].toUpperCase()}.`; } /** * Formats separate firstName + lastName fields, shortening the last name. * Falls back to parsing fullName if firstName is not available. */ export function formatShortName(firstName, lastName, fallbackName) { if (firstName?.trim()) { const l = lastName?.trim(); return l ? `${firstName.trim()} ${l[0].toUpperCase()}.` : firstName.trim(); } return shortName(fallbackName); } C buffersourcesizemapshash/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ E: () => (/* binding */ shortName), /* harmony export */ H: () => (/* binding */ formatShortName) /* harmony export */ }); /** * Shortens the last name to first letter + period. * "Иван Петров" → "Иван П." * Works with a pre-composed full name string. */ function shortName(fullName) { if (!fullName?.trim()) return '—'; const parts = fullName.trim().split(/\s+/); if (parts.length < 2 || !parts[1]) return parts[0]; return `${parts[0]} ${parts[1][0].toUpperCase()}.`; } /** * Formats separate firstName + lastName fields, shortening the last name. * Falls back to parsing fullName if firstName is not available. */ function formatShortName(firstName, lastName, fallbackName) { if (firstName?.trim()) { const l = lastName?.trim(); return l ? `${firstName.trim()} ${l[0].toUpperCase()}.` : firstName.trim(); } return shortName(fallbackName); } {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ E: () => (/* binding */ shortName), /* harmony export */ H: () => (/* binding */ formatShortName) /* harmony export */ }); ReplaceSourceRawSource$/** * Shortens the last name to first letter + period. * "Иван Петров" → "Иван П." * Works with a pre-composed full name string. */ export function shortName(fullName) { if (!fullName?.trim()) return '—'; const parts = fullName.trim().split(/\s+/); if (parts.length < 2 || !parts[1]) return parts[0]; return `${parts[0]} ${parts[1][0].toUpperCase()}.`; } /** * Formats separate firstName + lastName fields, shortening the last name. * Falls back to parsing fullName if firstName is not available. */ export function formatShortName(firstName, lastName, fallbackName) { if (firstName?.trim()) { const l = lastName?.trim(); return l ? `${firstName.trim()} ${l[0].toUpperCase()}.` : firstName.trim(); } return shortName(fallbackName); } 136142undefined523529undefined /***/ }) hU/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ E: () => (/* binding */ shortName), /* harmony export */ H: () => (/* binding */ formatShortName) /* harmony export */ }); /** * Shortens the last name to first letter + period. * "Иван Петров" → "Иван П." * Works with a pre-composed full name string. */ function shortName(fullName) { if (!fullName?.trim()) return '—'; const parts = fullName.trim().split(/\s+/); if (parts.length < 2 || !parts[1]) return parts[0]; return `${parts[0]} ${parts[1][0].toUpperCase()}.`; } /** * Formats separate firstName + lastName fields, shortening the last name. * Falls back to parsing fullName if firstName is not available. */ function formatShortName(firstName, lastName, fallbackName) { if (firstName?.trim()) { const l = lastName?.trim(); return l ? `${firstName.trim()} ${l[0].toUpperCase()}.` : firstName.trim(); } return shortName(fallbackName); } /***/ }) il  mzm/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ E: () => (/* binding */ shortName), /* harmony export */ H: () => (/* binding */ formatShortName) /* harmony export */ }); {$/** * Shortens the last name to first letter + period. * "Иван Петров" → "Иван П." * Works with a pre-composed full name string. */ export function shortName(fullName) { if (!fullName?.trim()) return '—'; const parts = fullName.trim().split(/\s+/); if (parts.length < 2 || !parts[1]) return parts[0]; return `${parts[0]} ${parts[1][0].toUpperCase()}.`; } /** * Formats separate firstName + lastName fields, shortening the last name. * Falls back to parsing fullName if firstName is not available. */ export function formatShortName(firstName, lastName, fallbackName) { if (firstName?.trim()) { const l = lastName?.trim(); return l ? `${firstName.trim()} ${l[0].toUpperCase()}.` : firstName.trim(); } return shortName(fallbackName); } 136142undefined523529undefinedln, /***/ 49046:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceV/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceimport(/* webpackMode: "eager", webpackExports: ["__esModule","default"] */ "/opt/canhelp/node_modules/next/dist/client/app-dir/link.js"); @Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 94496, 23))buffersourcesizemapshashhPromise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 94496, 23)); {"finalSource":true}mapbufferedMap ReplaceSourceRawSourceimport(/* webpackMode: "eager", webpackExports: ["__esModule","default"] */ "/opt/canhelp/node_modules/next/dist/client/app-dir/link.js"); s0136Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 94496, 23))undefined /***/ }) ]/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 94496, 23)); /***/ }) ^a bV/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { pimport(/* webpackMode: "eager", webpackExports: ["__esModule","default"] */ "/opt/canhelp/node_modules/next/dist/client/app-dir/link.js"); s0136Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 94496, 23))undefinedac, /***/ 56003:  .webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource9/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider), /* harmony export */ z: () => (/* binding */ useLocation) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91864); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceB /* __next_internal_client_entry_do_not_use__ LocationProvider,useLocation auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { getLocations } from '@/lib/api'; const LocationContext = /*#__PURE__*/ createContext({ locationSlug: '', locationTree: [], locationLoading: true, setLocation: ()=>{}, getLabel: ()=>'' }); function readCookieLocation() { if (typeof document === 'undefined') return ''; const match = document.cookie.match(/(?:^|;\s*)canhelp_location=([^;]+)/); return match?.[1] ? decodeURIComponent(match[1]) : ''; } export function LocationProvider({ children, initialSlug = '' }) { const [locationSlug, setLocationSlug] = useState(initialSlug); const [locationTree, setLocationTree] = useState([]); const [locationLoading, setLocationLoading] = useState(true); // Sync from cookie on client mount process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieSlug = readCookieLocation(); setLocationSlug(cookieSlug); }, []); // Load location tree once process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ getLocations().then((tree)=>setLocationTree(tree)).catch(()=>{}).finally(()=>setLocationLoading(false)); }, []); const setLocation = useCallback((slug)=>{ setLocationSlug(slug); const encoded = encodeURIComponent(slug); document.cookie = `canhelp_location=${encoded}; path=/; max-age=31536000; SameSite=Lax`; }, []); const getLabel = useCallback((locale)=>{ if (!locationSlug) return ''; for (const city of locationTree){ if (city.slug === locationSlug) return city.names[locale] ?? city.names.el; for (const d of city.children ?? []){ if (d.slug === locationSlug) return d.names[locale] ?? d.names.el; } } return locationSlug; }, [ locationSlug, locationTree ]); return /*#__PURE__*/ _jsx(LocationContext.Provider, { value: { locationSlug, locationTree, locationLoading, setLocation, getLabel }, children: children }); } export function useLocation() { return useContext(LocationContext); } aR^(4CJ_iHR# , (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(0,_lib_api__WEBPACK_IMPORTED_MODULE_2__/* .getLocations */ .Vs)(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)buffersourcesizemapshash /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider), /* harmony export */ z: () => (/* binding */ useLocation) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91864); /* __next_internal_client_entry_do_not_use__ LocationProvider,useLocation auto */ const LocationContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({ locationSlug: '', locationTree: [], locationLoading: true, setLocation: ()=>{}, getLabel: ()=>'' }); function readCookieLocation() { if (typeof document === 'undefined') return ''; const match = document.cookie.match(/(?:^|;\s*)canhelp_location=([^;]+)/); return match?.[1] ? decodeURIComponent(match[1]) : ''; } function LocationProvider({ children, initialSlug = '' }) { const [locationSlug, setLocationSlug] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialSlug); const [locationTree, setLocationTree] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [locationLoading, setLocationLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true); // Sync from cookie on client mount process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const cookieSlug = readCookieLocation(); setLocationSlug(cookieSlug); }, []); // Load location tree once process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ (0,_lib_api__WEBPACK_IMPORTED_MODULE_2__/* .getLocations */ .Vs)().then((tree)=>setLocationTree(tree)).catch(()=>{}).finally(()=>setLocationLoading(false)); }, []); const setLocation = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((slug)=>{ setLocationSlug(slug); const encoded = encodeURIComponent(slug); document.cookie = `canhelp_location=${encoded}; path=/; max-age=31536000; SameSite=Lax`; }, []); const getLabel = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((locale)=>{ if (!locationSlug) return ''; for (const city of locationTree){ if (city.slug === locationSlug) return city.names[locale] ?? city.names.el; for (const d of city.children ?? []){ if (d.slug === locationSlug) return d.names[locale] ?? d.names.el; } } return locationSlug; }, [ locationSlug, locationTree ]); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(LocationContext.Provider, { value: { locationSlug, locationTree, locationLoading, setLocation, getLabel }, children: children }); } function useLocation() { return (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(LocationContext); } {"finalSource":true}mapbufferedMap ConcatSourceRawSource9/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider), /* harmony export */ z: () => (/* binding */ useLocation) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91864); ReplaceSourceRawSourceB /* __next_internal_client_entry_do_not_use__ LocationProvider,useLocation auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { getLocations } from '@/lib/api'; const LocationContext = /*#__PURE__*/ createContext({ locationSlug: '', locationTree: [], locationLoading: true, setLocation: ()=>{}, getLabel: ()=>'' }); function readCookieLocation() { if (typeof document === 'undefined') return ''; const match = document.cookie.match(/(?:^|;\s*)canhelp_location=([^;]+)/); return match?.[1] ? decodeURIComponent(match[1]) : ''; } export function LocationProvider({ children, initialSlug = '' }) { const [locationSlug, setLocationSlug] = useState(initialSlug); const [locationTree, setLocationTree] = useState([]); const [locationLoading, setLocationLoading] = useState(true); // Sync from cookie on client mount process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieSlug = readCookieLocation(); setLocationSlug(cookieSlug); }, []); // Load location tree once process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ getLocations().then((tree)=>setLocationTree(tree)).catch(()=>{}).finally(()=>setLocationLoading(false)); }, []); const setLocation = useCallback((slug)=>{ setLocationSlug(slug); const encoded = encodeURIComponent(slug); document.cookie = `canhelp_location=${encoded}; path=/; max-age=31536000; SameSite=Lax`; }, []); const getLabel = useCallback((locale)=>{ if (!locationSlug) return ''; for (const city of locationTree){ if (city.slug === locationSlug) return city.names[locale] ?? city.names.el; for (const d of city.children ?? []){ if (d.slug === locationSlug) return d.names[locale] ?? d.names.el; } } return locationSlug; }, [ locationSlug, locationTree ]); return /*#__PURE__*/ _jsx(LocationContext.Provider, { value: { locationSlug, locationTree, locationLoading, setLocation, getLabel }, children: children }); } export function useLocation() { return useContext(LocationContext); } +82129undefined131214undefined216256undefined296308(0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)undefined657663undefined768775(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined835842(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined899906(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10101018(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined12101218(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined12341245(0,_lib_api__WEBPACK_IMPORTED_MODULE_2__/* .getLocations */ .Vs)undefined13751385(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined16081618(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined20712074(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined22962302undefined23392348(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)undefined /***/ }) R /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider), /* harmony export */ z: () => (/* binding */ useLocation) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91864); /* __next_internal_client_entry_do_not_use__ LocationProvider,useLocation auto */ const LocationContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({ locationSlug: '', locationTree: [], locationLoading: true, setLocation: ()=>{}, getLabel: ()=>'' }); function readCookieLocation() { if (typeof document === 'undefined') return ''; const match = document.cookie.match(/(?:^|;\s*)canhelp_location=([^;]+)/); return match?.[1] ? decodeURIComponent(match[1]) : ''; } function LocationProvider({ children, initialSlug = '' }) { const [locationSlug, setLocationSlug] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialSlug); const [locationTree, setLocationTree] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [locationLoading, setLocationLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true); // Sync from cookie on client mount process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const cookieSlug = readCookieLocation(); setLocationSlug(cookieSlug); }, []); // Load location tree once process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ (0,_lib_api__WEBPACK_IMPORTED_MODULE_2__/* .getLocations */ .Vs)().then((tree)=>setLocationTree(tree)).catch(()=>{}).finally(()=>setLocationLoading(false)); }, []); const setLocation = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((slug)=>{ setLocationSlug(slug); const encoded = encodeURIComponent(slug); document.cookie = `canhelp_location=${encoded}; path=/; max-age=31536000; SameSite=Lax`; }, []); const getLabel = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((locale)=>{ if (!locationSlug) return ''; for (const city of locationTree){ if (city.slug === locationSlug) return city.names[locale] ?? city.names.el; for (const d of city.children ?? []){ if (d.slug === locationSlug) return d.names[locale] ?? d.names.el; } } return locationSlug; }, [ locationSlug, locationTree ]); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(LocationContext.Provider, { value: { locationSlug, locationTree, locationLoading, setLocation, getLabel }, children: children }); } function useLocation() { return (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(LocationContext); } /***/ }) SV  WdW9/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider), /* harmony export */ z: () => (/* binding */ useLocation) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91864); eB /* __next_internal_client_entry_do_not_use__ LocationProvider,useLocation auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { getLocations } from '@/lib/api'; const LocationContext = /*#__PURE__*/ createContext({ locationSlug: '', locationTree: [], locationLoading: true, setLocation: ()=>{}, getLabel: ()=>'' }); function readCookieLocation() { if (typeof document === 'undefined') return ''; const match = document.cookie.match(/(?:^|;\s*)canhelp_location=([^;]+)/); return match?.[1] ? decodeURIComponent(match[1]) : ''; } export function LocationProvider({ children, initialSlug = '' }) { const [locationSlug, setLocationSlug] = useState(initialSlug); const [locationTree, setLocationTree] = useState([]); const [locationLoading, setLocationLoading] = useState(true); // Sync from cookie on client mount process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieSlug = readCookieLocation(); setLocationSlug(cookieSlug); }, []); // Load location tree once process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ getLocations().then((tree)=>setLocationTree(tree)).catch(()=>{}).finally(()=>setLocationLoading(false)); }, []); const setLocation = useCallback((slug)=>{ setLocationSlug(slug); const encoded = encodeURIComponent(slug); document.cookie = `canhelp_location=${encoded}; path=/; max-age=31536000; SameSite=Lax`; }, []); const getLabel = useCallback((locale)=>{ if (!locationSlug) return ''; for (const city of locationTree){ if (city.slug === locationSlug) return city.names[locale] ?? city.names.el; for (const d of city.children ?? []){ if (d.slug === locationSlug) return d.names[locale] ?? d.names.el; } } return locationSlug; }, [ locationSlug, locationTree ]); return /*#__PURE__*/ _jsx(LocationContext.Provider, { value: { locationSlug, locationTree, locationLoading, setLocation, getLabel }, children: children }); } export function useLocation() { return useContext(LocationContext); } +82129undefined131214undefined216256undefined296308(0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)undefined657663undefined768775(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined835842(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined899906(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10101018(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined12101218(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined12341245(0,_lib_api__WEBPACK_IMPORTED_MODULE_2__/* .getLocations */ .Vs)undefined13751385(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined16081618(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined20712074(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined22962302undefined23392348(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)undefinedVX, /***/ 58719:  `pwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource fwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceN // EXPORTS __webpack_require__.d(__webpack_exports__, { Header: () => (/* binding */ Header) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); // EXTERNAL MODULE: ../../node_modules/next/dist/api/navigation.js var navigation = __webpack_require__(71159); // EXTERNAL MODULE: ./src/lib/auth.ts var auth = __webpack_require__(13260); // EXTERNAL MODULE: ./src/context/locale.tsx var context_locale = __webpack_require__(96484); // EXTERNAL MODULE: ./src/lib/formatName.ts var formatName = __webpack_require__(48178); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ./src/lib/translations.ts var translations = __webpack_require__(12998); ;// ./src/components/LanguageSwitcher.tsx webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource Rwebpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource]/* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useRef, useEffect } from 'react'; import { useLocale } from '@/context/locale'; import { LOCALES } from '@/lib/translations'; export function LanguageSwitcher() { const { locale, setLocale } = useLocale(); const [open, setOpen] = useState(false); const ref = useRef(null); const current = LOCALES.find((l)=>l.code === locale) ?? LOCALES[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ _jsxs("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ _jsx("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ _jsx("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ _jsx("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: LOCALES.map((loc)=>/*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ _jsx("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } aF_^fS[dgEHcJf  / 3 __WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__.___WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._buffersourcesizemapshash>/* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ function LanguageSwitcher() { const { locale, setLocale } = __WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._(); const [open, setOpen] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false); const ref = __WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._(null); const current = __WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._.find((l)=>l.code === locale) ?? __WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_asiSafe1__._[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: __WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._.map((loc)=>/*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } {"finalSource":false}mapbufferedMap ReplaceSourceRawSource]/* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useRef, useEffect } from 'react'; import { useLocale } from '@/context/locale'; import { LOCALES } from '@/lib/translations'; export function LanguageSwitcher() { const { locale, setLocale } = useLocale(); const [open, setOpen] = useState(false); const ref = useRef(null); const current = LOCALES.find((l)=>l.code === locale) ?? LOCALES[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ _jsxs("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ _jsx("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ _jsx("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ _jsx("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: LOCALES.map((loc)=>/*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ _jsx("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } r70132undefined134185undefined187231undefined233277undefined279285undefined350358__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined391398__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined424429__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined458464__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined498504__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_asiSafe1__._undefined595603__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined908912__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined10181022__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13801383__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined15141517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18611864__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined21472150__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined23182324__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined23512355__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined28092812__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined29732976__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32313234__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined`_Uo!C4eg< ? O:A9(0,context_locale/* useLocale */.Y)(0,react.useState)(0,react.useRef)translations/* LOCALES */.YZ(0,react.useEffect)(0,react_jsx_runtime.jsxs)(0,react_jsx_runtime.jsx) // EXTERNAL MODULE: ./src/lib/api.ts var api = __webpack_require__(91864); // EXTERNAL MODULE: ../../node_modules/socket.io-client/build/esm-debug/index.js + 30 modules var esm_debug = __webpack_require__(44826); ;// ./src/components/Header.tsx  8webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource"(/* __next_internal_client_entry_do_not_use__ Header auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import Link from 'next/link'; import { useRouter, usePathname } from 'next/navigation'; import { useSession, signOut } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { formatShortName } from '@/lib/formatName'; import { LanguageSwitcher } from './LanguageSwitcher'; import { useState, useRef, useEffect } from 'react'; import { getUnreadCount, getMyDashboard } from '@/lib/api'; import { io } from 'socket.io-client'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Header() { const router = useRouter(); const pathname = usePathname(); const { data: session } = useSession(); const { t, locale } = useLocale(); const [menuOpen, setMenuOpen] = useState(false); const [profileOpen, setProfileOpen] = useState(false); const [unreadNotif, setUnreadNotif] = useState(0); const [unreadChat, setUnreadChat] = useState(0); const [msgToast, setMsgToast] = useState(null); const [planTier, setPlanTier] = useState(null); const profileRef = useRef(null); const headerRef = useRef(null); const toastTimer = useRef(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; const socket = io(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>getUnreadCount().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setPlanTier(null); return; } getMyDashboard().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ _jsx(Link, { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ _jsx("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ _jsxs("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ _jsx(Link, { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ _jsx(Link, { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ _jsxs("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ _jsx("span", { className: "truncate max-w-[100px]", children: formatShortName(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ _jsxs("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ _jsx("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ _jsxs("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ _jsx(LanguageSwitcher, {}) ] }), /*#__PURE__*/ _jsxs("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ _jsx(LanguageSwitcher, {}), /*#__PURE__*/ _jsx("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ _jsxs("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setMenuOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ _jsx("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ _jsx("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ _jsx("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ _jsx(Link, { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } @`<_IK}%'L^| ?_Gpw"LS]e%-jk0 8 _ " / MQ.13648"*_-/2mpru %)+. ""M%_P%''''((++z-}-//0022S3a3M4P4 6#6$8'8M:P:<<*>.>0>_8>>>>>AACCGGGGIILIKK;P?PAPIPPPPP1S4SUUY!YZ_Z@^D^F^I^t`w`6c9c*f.fggCkGkIkLk|mmpp}ttttvvxx@|D|F|_I|P~S~!#&*.;?ADJM ru_Z] !$+svxŰ_Ȱ'+z~Ȼ˻ $&)ruPTV_^KNTXZ]cgil^a_&KNKNx{x{jnpsCF_PS{~{~RU"%gj7:A_ELO  9=?Bor14NQSVT*-  F!J!!!""#$$$5&8&:&=&"https://api.canhelp.gr"0__WEBPACK_MODULE_REFERENCE__2_5b22757365526f75746572225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__2_5b22757365506174686e616d65225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b2275736553657373696f6e225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__10_5b22696f225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__9_5b22676574556e72656164436f756e74225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__9_5b226765744d7944617368626f617264225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__5_5b22666f726d617453686f72744e616d65225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__.___WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._d/* __next_internal_client_entry_do_not_use__ Header auto */ const API_URL = "https://api.canhelp.gr" || 0; function Header() { const router = __WEBPACK_MODULE_REFERENCE__2_5b22757365526f75746572225d_call_directImport_asiSafe1__._(); const pathname = __WEBPACK_MODULE_REFERENCE__2_5b22757365506174686e616d65225d_call_directImport_asiSafe1__._(); const { data: session } = __WEBPACK_MODULE_REFERENCE__3_5b2275736553657373696f6e225d_call_directImport_asiSafe1__._(); const { t, locale } = __WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._(); const [menuOpen, setMenuOpen] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false); const [profileOpen, setProfileOpen] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(false); const [unreadNotif, setUnreadNotif] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(0); const [unreadChat, setUnreadChat] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(0); const [msgToast, setMsgToast] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(null); const [planTier, setPlanTier] = __WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._(null); const profileRef = __WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._(null); const headerRef = __WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._(null); const toastTimer = __WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ if (!session) return; const socket = __WEBPACK_MODULE_REFERENCE__10_5b22696f225d_call_directImport_asiSafe1__._(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>__WEBPACK_MODULE_REFERENCE__9_5b22676574556e72656164436f756e74225d_call_directImport_asiSafe1__._().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ if (!session) { setPlanTier(null); return; } __WEBPACK_MODULE_REFERENCE__9_5b226765744d7944617368626f617264225d_call_directImport_asiSafe1__._().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && __WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "truncate max-w-[100px]", children: __WEBPACK_MODULE_REFERENCE__5_5b22666f726d617453686f72744e616d65225d_call_directImport_asiSafe1__._(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); __WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._, {}) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._, {}), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("button", { onClick: ()=>{ setMenuOpen(false); __WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._, { children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ __WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._(__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._, { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); }  "(/* __next_internal_client_entry_do_not_use__ Header auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import Link from 'next/link'; import { useRouter, usePathname } from 'next/navigation'; import { useSession, signOut } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { formatShortName } from '@/lib/formatName'; import { LanguageSwitcher } from './LanguageSwitcher'; import { useState, useRef, useEffect } from 'react'; import { getUnreadCount, getMyDashboard } from '@/lib/api'; import { io } from 'socket.io-client'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Header() { const router = useRouter(); const pathname = usePathname(); const { data: session } = useSession(); const { t, locale } = useLocale(); const [menuOpen, setMenuOpen] = useState(false); const [profileOpen, setProfileOpen] = useState(false); const [unreadNotif, setUnreadNotif] = useState(0); const [unreadChat, setUnreadChat] = useState(0); const [msgToast, setMsgToast] = useState(null); const [planTier, setPlanTier] = useState(null); const profileRef = useRef(null); const headerRef = useRef(null); const toastTimer = useRef(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; const socket = io(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>getUnreadCount().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setPlanTier(null); return; } getMyDashboard().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ _jsx(Link, { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ _jsx("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ _jsxs("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ _jsx(Link, { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ _jsx(Link, { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ _jsxs("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ _jsx("span", { className: "truncate max-w-[100px]", children: formatShortName(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ _jsxs("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ _jsx("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ _jsxs("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ _jsx(LanguageSwitcher, {}) ] }), /*#__PURE__*/ _jsxs("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ _jsx(LanguageSwitcher, {}), /*#__PURE__*/ _jsx("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ _jsxs("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setMenuOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ _jsx("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ _jsx("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ _jsx("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ _jsx(Link, { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } PT60145undefined147175undefined177233undefined235283undefined285329undefined331381undefined383436undefined438489undefined491549undefined551588undefined606636"https://api.canhelp.gr"undefined6416630undefined666672undefined712720__WEBPACK_MODULE_REFERENCE__2_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined746756__WEBPACK_MODULE_REFERENCE__2_5b22757365506174686e616d65225d_call_directImport_asiSafe1__._undefined791800__WEBPACK_MODULE_REFERENCE__3_5b2275736553657373696f6e225d_call_directImport_asiSafe1__._undefined831839__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined880887__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined939946__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined9981005__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10511058__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11001107__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11521159__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11911196__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12271232__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12641269__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined13731381__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined19281936__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined20852093__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined21542155__WEBPACK_MODULE_REFERENCE__10_5b22696f225d_call_directImport_asiSafe1__._undefined28642872__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined29913004__WEBPACK_MODULE_REFERENCE__9_5b22676574556e72656164436f756e74225d_call_directImport_asiSafe1__._undefined32533261__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined33623375__WEBPACK_MODULE_REFERENCE__9_5b226765744d7944617368626f617264225d_call_directImport_asiSafe1__._undefined35273535__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined39953999__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined40014009__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined40604063__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined42714275__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined44294433__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined46544657__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined46594662__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined48514854__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51725176__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined53965400__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined54025410__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined55335536__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined55385541__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined59305933__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined59355938__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined63726376__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined63786386__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined65096512__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined65146517__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined69146917__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69196922__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined73997402__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined74047407__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined78367840__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined78427850__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined79737977__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined79797982__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined83248327__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined88668869__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined95499552__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1013010134__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1013610139__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1047210475__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1101211015__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1164211645__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1222312227__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1251612520__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1294112944__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1313913153__WEBPACK_MODULE_REFERENCE__5_5b22666f726d617453686f72744e616d65225d_call_directImport_asiSafe1__._undefined1338913392__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1385613859__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1437214375__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1492514928__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1557015574__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1591415918__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1592015928__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined1609916103__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1610516108__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1666816671__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1733317336__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1819018194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1819618199__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1876118764__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1942619429__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2053920543__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2054520553__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined2072420728__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2073020733__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2129721300__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2200522008__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2281322817__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2328223285__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2412824132__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2413424137__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2469224695__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2539825401__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2615426158__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2661326616__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2745927463__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2746527468__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2802828031__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2869328696__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2982129825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2982729830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3034630349__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3096330966__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3180831812__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3181431817__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3233632339__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3295332956__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3382133825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3382733830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3434634350__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3504635049__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3602936032__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3692336927__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3692936932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3745037453__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3806738070__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3890438908__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3891038913__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3943339436__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4005040053__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4094540948__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4120641210__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4163641642__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined4207442077__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4267742680__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4378743791__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4379343801__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4392443927__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4392943932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4431644319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4432144324__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4482344826__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4482844843__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4497044974__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4517145174__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4517645191__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4525345256__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4555445557__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4600346006__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4631646319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4688746891__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4710547109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4711147119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4722647230__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4723247235__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4760847611__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4807248075__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4867248676__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4867848681__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4905849061__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4952249525__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5025650260__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5026250270__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5037750381__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5038350386__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5076350766__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5122751230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5179651800__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5180251805__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5218452187__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5264852651__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5348253486__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5348853496__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5360353607__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5360953612__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5398453987__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5448954492__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5513455137__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5557655580__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5558255590__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5571355717__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5571955722__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5613956142__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5665156654__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5729257296__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5729857301__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5772057723__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5823258235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5910559109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5911159119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5924259246__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5924859251__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5967259675__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6022760230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6089160895__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6126461267__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6190561909__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6191161914__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6233162334__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6284362846__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6369663700__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6370263705__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6408264085__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6454664549__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6525465258__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6526065263__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6563965642__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6610366106__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6675566759__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6676166764__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6713767141__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6766067663__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6852368526__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6917769181__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6918369186__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6956169564__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7002570028__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7064670650__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7083970845__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined7127971282__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7172971732__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7240572409__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7241172419__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined7252672529__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7253172534__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7293272935__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7293772940__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7351473517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7364573649__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7386073863__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7405474058__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7421274215__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7446074463__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7475174755__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7493374936__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7531775320__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7532275325__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined_ fV[edCcq  _  [ vMFaOgi5Q7^`j>_fh2|~P!!!8""""L#$#%%%r%O'''')))2**_**H+,,/M/1?24445i6689;;>a>??sAABBCDE2F3H_}HJJoMMO[O]OOWPPPP"SlSVLVYYY=Zo\\O__c;d=dd7eee_ehPhk[knnpp2t~tttvBwzKz<}}O02و>_ٍݏ'ג!moØ sjl ߨ)?E?_͵ϵ$nԺ2.(ik5N$&_P_aHrzD|;Al_ Y_"9o %qs-y{_<|HIa .    G41{-/~_EG9G  #[#]##K%%''.+z+|++B--Y//d2222w4_466a9999q;;=>jAA?DDDDQFFhHHKhK%LwL)NsN2P|PSiSkS\S%ToTqTTLVVVV#YmYY9Z [V[\a\\E]:^^__``ibbbc(0,navigation.useRouter)(0,navigation.usePathname)(0,auth/* useSession */.wV)(0,esm_debug.io)(0,api/* getUnreadCount */.$M)(0,api/* getMyDashboard */.H)react_jsx_runtime.Fragment(link_default())(0,formatName/* formatShortName */.H)(0,auth/* signOut */.CI)LanguageSwitcherbuffersourcesizemapshashI // EXPORTS __webpack_require__.d(__webpack_exports__, { Header: () => (/* binding */ Header) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); // EXTERNAL MODULE: ../../node_modules/next/dist/api/navigation.js var navigation = __webpack_require__(71159); // EXTERNAL MODULE: ./src/lib/auth.ts var auth = __webpack_require__(13260); // EXTERNAL MODULE: ./src/context/locale.tsx var context_locale = __webpack_require__(96484); // EXTERNAL MODULE: ./src/lib/formatName.ts var formatName = __webpack_require__(48178); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ./src/lib/translations.ts var translations = __webpack_require__(12998); ;// ./src/components/LanguageSwitcher.tsx /* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ function LanguageSwitcher() { const { locale, setLocale } = (0,context_locale/* useLocale */.Y)(); const [open, setOpen] = (0,react.useState)(false); const ref = (0,react.useRef)(null); const current = translations/* LOCALES */.YZ.find((l)=>l.code === locale) ?? translations/* LOCALES */.YZ[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: translations/* LOCALES */.YZ.map((loc)=>/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } // EXTERNAL MODULE: ./src/lib/api.ts var api = __webpack_require__(91864); // EXTERNAL MODULE: ../../node_modules/socket.io-client/build/esm-debug/index.js + 30 modules var esm_debug = __webpack_require__(44826); ;// ./src/components/Header.tsx /* __next_internal_client_entry_do_not_use__ Header auto */ const API_URL = "https://api.canhelp.gr" || 0; function Header() { const router = (0,navigation.useRouter)(); const pathname = (0,navigation.usePathname)(); const { data: session } = (0,auth/* useSession */.wV)(); const { t, locale } = (0,context_locale/* useLocale */.Y)(); const [menuOpen, setMenuOpen] = (0,react.useState)(false); const [profileOpen, setProfileOpen] = (0,react.useState)(false); const [unreadNotif, setUnreadNotif] = (0,react.useState)(0); const [unreadChat, setUnreadChat] = (0,react.useState)(0); const [msgToast, setMsgToast] = (0,react.useState)(null); const [planTier, setPlanTier] = (0,react.useState)(null); const profileRef = (0,react.useRef)(null); const headerRef = (0,react.useRef)(null); const toastTimer = (0,react.useRef)(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) return; const socket = (0,esm_debug.io)(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>(0,api/* getUnreadCount */.$M)().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) { setPlanTier(null); return; } (0,api/* getMyDashboard */.H)().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "truncate max-w-[100px]", children: (0,formatName/* formatShortName */.H)(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); (0,auth/* signOut */.CI)().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)(LanguageSwitcher, {}) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)(LanguageSwitcher, {}), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>{ setMenuOpen(false); (0,auth/* signOut */.CI)().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } {"finalSource":true}mapbufferedMap ` ConcatSourceRawSourceN // EXPORTS __webpack_require__.d(__webpack_exports__, { Header: () => (/* binding */ Header) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); // EXTERNAL MODULE: ../../node_modules/next/dist/api/navigation.js var navigation = __webpack_require__(71159); // EXTERNAL MODULE: ./src/lib/auth.ts var auth = __webpack_require__(13260); // EXTERNAL MODULE: ./src/context/locale.tsx var context_locale = __webpack_require__(96484); // EXTERNAL MODULE: ./src/lib/formatName.ts var formatName = __webpack_require__(48178); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ./src/lib/translations.ts var translations = __webpack_require__(12998); ;// ./src/components/LanguageSwitcher.tsx  ReplaceSourceReplaceSourceRawSource]/* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useRef, useEffect } from 'react'; import { useLocale } from '@/context/locale'; import { LOCALES } from '@/lib/translations'; export function LanguageSwitcher() { const { locale, setLocale } = useLocale(); const [open, setOpen] = useState(false); const ref = useRef(null); const current = LOCALES.find((l)=>l.code === locale) ?? LOCALES[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ _jsxs("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ _jsx("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ _jsx("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ _jsx("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: LOCALES.map((loc)=>/*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ _jsx("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } r70132undefined134185undefined187231undefined233277undefined279285undefined350358__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined391398__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined424429__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined458464__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined498504__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_asiSafe1__._undefined595603__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined908912__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined10181022__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13801383__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined15141517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18611864__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined21472150__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined23182324__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined23512355__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined28092812__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined29732976__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32313234__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined138224(0,context_locale/* useLocale */.Y)undefined257341(0,react.useState)undefined367447(0,react.useRef)undefined476545translations/* LOCALES */.YZundefined579643translations/* LOCALES */.YZundefined734820(0,react.useEffect)undefined11251201(0,react_jsx_runtime.jsxs)undefined13071383(0,react_jsx_runtime.jsxs)undefined17411815(0,react_jsx_runtime.jsx)undefined19462020(0,react_jsx_runtime.jsx)undefined23642438(0,react_jsx_runtime.jsx)undefined27212795(0,react_jsx_runtime.jsx)undefined29633032translations/* LOCALES */.YZundefined30593135(0,react_jsx_runtime.jsxs)undefined35893663(0,react_jsx_runtime.jsx)undefined38243898(0,react_jsx_runtime.jsx)undefined41534227(0,react_jsx_runtime.jsx)undefinedRawSource // EXTERNAL MODULE: ./src/lib/api.ts var api = __webpack_require__(91864); // EXTERNAL MODULE: ../../node_modules/socket.io-client/build/esm-debug/index.js + 30 modules var esm_debug = __webpack_require__(44826); ;// ./src/components/Header.tsx "(/* __next_internal_client_entry_do_not_use__ Header auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import Link from 'next/link'; import { useRouter, usePathname } from 'next/navigation'; import { useSession, signOut } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { formatShortName } from '@/lib/formatName'; import { LanguageSwitcher } from './LanguageSwitcher'; import { useState, useRef, useEffect } from 'react'; import { getUnreadCount, getMyDashboard } from '@/lib/api'; import { io } from 'socket.io-client'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Header() { const router = useRouter(); const pathname = usePathname(); const { data: session } = useSession(); const { t, locale } = useLocale(); const [menuOpen, setMenuOpen] = useState(false); const [profileOpen, setProfileOpen] = useState(false); const [unreadNotif, setUnreadNotif] = useState(0); const [unreadChat, setUnreadChat] = useState(0); const [msgToast, setMsgToast] = useState(null); const [planTier, setPlanTier] = useState(null); const profileRef = useRef(null); const headerRef = useRef(null); const toastTimer = useRef(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; const socket = io(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>getUnreadCount().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setPlanTier(null); return; } getMyDashboard().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ _jsx(Link, { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ _jsx("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ _jsxs("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ _jsx(Link, { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ _jsx(Link, { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ _jsxs("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ _jsx("span", { className: "truncate max-w-[100px]", children: formatShortName(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ _jsxs("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ _jsx("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ _jsxs("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ _jsx(LanguageSwitcher, {}) ] }), /*#__PURE__*/ _jsxs("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ _jsx(LanguageSwitcher, {}), /*#__PURE__*/ _jsx("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ _jsxs("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setMenuOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ _jsx("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ _jsx("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ _jsx("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ _jsx(Link, { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } PT60145undefined147175undefined177233undefined235283undefined285329undefined331381undefined383436undefined438489undefined491549undefined551588undefined606636"https://api.canhelp.gr"undefined6416630undefined666672undefined712720__WEBPACK_MODULE_REFERENCE__2_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined746756__WEBPACK_MODULE_REFERENCE__2_5b22757365506174686e616d65225d_call_directImport_asiSafe1__._undefined791800__WEBPACK_MODULE_REFERENCE__3_5b2275736553657373696f6e225d_call_directImport_asiSafe1__._undefined831839__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined880887__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined939946__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined9981005__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10511058__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11001107__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11521159__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11911196__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12271232__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12641269__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined13731381__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined19281936__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined20852093__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined21542155__WEBPACK_MODULE_REFERENCE__10_5b22696f225d_call_directImport_asiSafe1__._undefined28642872__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined29913004__WEBPACK_MODULE_REFERENCE__9_5b22676574556e72656164436f756e74225d_call_directImport_asiSafe1__._undefined32533261__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined33623375__WEBPACK_MODULE_REFERENCE__9_5b226765744d7944617368626f617264225d_call_directImport_asiSafe1__._undefined35273535__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined39953999__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined40014009__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined40604063__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined42714275__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined44294433__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined46544657__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined46594662__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined48514854__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51725176__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined53965400__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined54025410__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined55335536__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined55385541__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined59305933__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined59355938__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined63726376__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined63786386__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined65096512__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined65146517__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined69146917__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69196922__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined73997402__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined74047407__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined78367840__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined78427850__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined79737977__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined79797982__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined83248327__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined88668869__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined95499552__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1013010134__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1013610139__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1047210475__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1101211015__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1164211645__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1222312227__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1251612520__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1294112944__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1313913153__WEBPACK_MODULE_REFERENCE__5_5b22666f726d617453686f72744e616d65225d_call_directImport_asiSafe1__._undefined1338913392__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1385613859__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1437214375__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1492514928__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1557015574__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1591415918__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1592015928__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined1609916103__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1610516108__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1666816671__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1733317336__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1819018194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1819618199__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1876118764__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1942619429__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2053920543__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2054520553__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined2072420728__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2073020733__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2129721300__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2200522008__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2281322817__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2328223285__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2412824132__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2413424137__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2469224695__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2539825401__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2615426158__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2661326616__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2745927463__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2746527468__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2802828031__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2869328696__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2982129825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2982729830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3034630349__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3096330966__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3180831812__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3181431817__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3233632339__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3295332956__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3382133825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3382733830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3434634350__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3504635049__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3602936032__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3692336927__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3692936932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3745037453__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3806738070__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3890438908__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3891038913__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3943339436__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4005040053__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4094540948__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4120641210__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4163641642__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined4207442077__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4267742680__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4378743791__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4379343801__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4392443927__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4392943932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4431644319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4432144324__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4482344826__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4482844843__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4497044974__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4517145174__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4517645191__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4525345256__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4555445557__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4600346006__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4631646319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4688746891__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4710547109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4711147119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4722647230__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4723247235__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4760847611__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4807248075__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4867248676__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4867848681__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4905849061__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4952249525__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5025650260__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5026250270__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5037750381__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5038350386__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5076350766__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5122751230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5179651800__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5180251805__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5218452187__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5264852651__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5348253486__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5348853496__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5360353607__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5360953612__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5398453987__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5448954492__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5513455137__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5557655580__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5558255590__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5571355717__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5571955722__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5613956142__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5665156654__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5729257296__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5729857301__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5772057723__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5823258235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5910559109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5911159119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5924259246__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5924859251__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5967259675__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6022760230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6089160895__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6126461267__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6190561909__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6191161914__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6233162334__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6284362846__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6369663700__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6370263705__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6408264085__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6454664549__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6525465258__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6526065263__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6563965642__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6610366106__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6675566759__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6676166764__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6713767141__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6766067663__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6852368526__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6917769181__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6918369186__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6956169564__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7002570028__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7064670650__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7083970845__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined7127971282__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7172971732__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7240572409__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7241172419__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined7252672529__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7253172534__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7293272935__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7293772940__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7351473517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7364573649__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7386073863__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7405474058__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7421274215__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7446074463__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7475174755__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7493374936__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7531775320__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7532275325__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined`$156242(0,navigation.useRouter)undefined268358(0,navigation.usePathname)undefined393481(0,auth/* useSession */.wV)undefined512598(0,context_locale/* useLocale */.Y)undefined639723(0,react.useState)undefined775859(0,react.useState)undefined911995(0,react.useState)undefined10411125(0,react.useState)undefined11671251(0,react.useState)undefined12961380(0,react.useState)undefined14121492(0,react.useRef)undefined15231603(0,react.useRef)undefined16351715(0,react.useRef)undefined18191905(0,react.useEffect)undefined24522538(0,react.useEffect)undefined26872773(0,react.useEffect)undefined28342907(0,esm_debug.io)undefined36163702(0,react.useEffect)undefined38213917(0,api/* getUnreadCount */.$M)undefined41664252(0,react.useEffect)undefined43534449(0,api/* getMyDashboard */.H)undefined46014687(0,react.useEffect)undefined51475223(0,react_jsx_runtime.jsxs)undefined52255304react_jsx_runtime.Fragmentundefined53555429(0,react_jsx_runtime.jsx)undefined56375713(0,react_jsx_runtime.jsxs)undefined58675943(0,react_jsx_runtime.jsxs)undefined61646238(0,react_jsx_runtime.jsx)undefined62406317(link_default())undefined65066580(0,react_jsx_runtime.jsx)undefined68986974(0,react_jsx_runtime.jsxs)undefined71947270(0,react_jsx_runtime.jsxs)undefined72727351react_jsx_runtime.Fragmentundefined74747548(0,react_jsx_runtime.jsx)undefined75507627(link_default())undefined80168090(0,react_jsx_runtime.jsx)undefined80928169(link_default())undefined86038679(0,react_jsx_runtime.jsxs)undefined86818760react_jsx_runtime.Fragmentundefined88838957(0,react_jsx_runtime.jsx)undefined89599036(link_default())undefined94339507(0,react_jsx_runtime.jsx)undefined95099586(link_default())undefined1006310137(0,react_jsx_runtime.jsx)undefined1013910216(link_default())undefined1064510721(0,react_jsx_runtime.jsxs)undefined1072310802react_jsx_runtime.Fragmentundefined1092511001(0,react_jsx_runtime.jsxs)undefined1100311080(link_default())undefined1142211496(0,react_jsx_runtime.jsx)undefined1203512109(0,react_jsx_runtime.jsx)undefined1278912863(0,react_jsx_runtime.jsx)undefined1344113517(0,react_jsx_runtime.jsxs)undefined1351913596(link_default())undefined1392914003(0,react_jsx_runtime.jsx)undefined1454014614(0,react_jsx_runtime.jsx)undefined1524115315(0,react_jsx_runtime.jsx)undefined1589315969(0,react_jsx_runtime.jsxs)undefined1625816334(0,react_jsx_runtime.jsxs)undefined1675516829(0,react_jsx_runtime.jsx)undefined1702417122(0,formatName/* formatShortName */.H)undefined1735817432(0,react_jsx_runtime.jsx)undefined1789617970(0,react_jsx_runtime.jsx)undefined1848318557(0,react_jsx_runtime.jsx)undefined1910719181(0,react_jsx_runtime.jsx)undefined1982319899(0,react_jsx_runtime.jsxs)undefined2023920315(0,react_jsx_runtime.jsxs)undefined2031720396react_jsx_runtime.Fragmentundefined2056720643(0,react_jsx_runtime.jsxs)undefined2064520722(link_default())undefined2128221356(0,react_jsx_runtime.jsx)undefined2201822092(0,react_jsx_runtime.jsx)undefined2294623022(0,react_jsx_runtime.jsxs)undefined2302423101(link_default())undefined2366323737(0,react_jsx_runtime.jsx)undefined2439924473(0,react_jsx_runtime.jsx)undefined2558325659(0,react_jsx_runtime.jsxs)undefined2566125740react_jsx_runtime.Fragmentundefined2591125987(0,react_jsx_runtime.jsxs)undefined2598926066(link_default())undefined2663026704(0,react_jsx_runtime.jsx)undefined2740927483(0,react_jsx_runtime.jsx)undefined2828828364(0,react_jsx_runtime.jsxs)undefined2882928903(0,react_jsx_runtime.jsx)undefined2974629822(0,react_jsx_runtime.jsxs)undefined2982429901(link_default())undefined3045630530(0,react_jsx_runtime.jsx)undefined3123331307(0,react_jsx_runtime.jsx)undefined3206032136(0,react_jsx_runtime.jsxs)undefined3259132665(0,react_jsx_runtime.jsx)undefined3350833584(0,react_jsx_runtime.jsxs)undefined3358633663(link_default())undefined3422334297(0,react_jsx_runtime.jsx)undefined3495935033(0,react_jsx_runtime.jsx)undefined3615836234(0,react_jsx_runtime.jsxs)undefined3623636313(link_default())undefined3682936903(0,react_jsx_runtime.jsx)undefined3751737591(0,react_jsx_runtime.jsx)undefined3843338509(0,react_jsx_runtime.jsxs)undefined3851138588(link_default())undefined3910739181(0,react_jsx_runtime.jsx)undefined3979539869(0,react_jsx_runtime.jsx)undefined4073440810(0,react_jsx_runtime.jsxs)undefined4081240889(link_default())undefined4140541481(0,react_jsx_runtime.jsxs)undefined4217742251(0,react_jsx_runtime.jsx)undefined4323143305(0,react_jsx_runtime.jsx)undefined4419644272(0,react_jsx_runtime.jsxs)undefined4427444351(link_default())undefined4486944943(0,react_jsx_runtime.jsx)undefined4555745631(0,react_jsx_runtime.jsx)undefined4646546541(0,react_jsx_runtime.jsxs)undefined4654346620(link_default())undefined4714047214(0,react_jsx_runtime.jsx)undefined4782847902(0,react_jsx_runtime.jsx)undefined4879448868(0,react_jsx_runtime.jsx)undefined4912649202(0,react_jsx_runtime.jsxs)undefined4962849710(0,auth/* signOut */.CI)undefined5014250216(0,react_jsx_runtime.jsx)undefined5081650890(0,react_jsx_runtime.jsx)undefined5199752073(0,react_jsx_runtime.jsxs)undefined5207552154react_jsx_runtime.Fragmentundefined5227752351(0,react_jsx_runtime.jsx)undefined5235352430(link_default())undefined5281452888(0,react_jsx_runtime.jsx)undefined5289052967(link_default())undefined5346653540(0,react_jsx_runtime.jsx)undefined5354253637LanguageSwitcherundefined5376453840(0,react_jsx_runtime.jsxs)undefined5403754111(0,react_jsx_runtime.jsx)undefined5411354208LanguageSwitcherundefined5427054344(0,react_jsx_runtime.jsx)undefined5464254716(0,react_jsx_runtime.jsx)undefined5516255236(0,react_jsx_runtime.jsx)undefined5554655620(0,react_jsx_runtime.jsx)undefined5618856264(0,react_jsx_runtime.jsxs)undefined5647856554(0,react_jsx_runtime.jsxs)undefined5655656635react_jsx_runtime.Fragmentundefined5674256818(0,react_jsx_runtime.jsxs)undefined5682056897(link_default())undefined5727057344(0,react_jsx_runtime.jsx)undefined5780557879(0,react_jsx_runtime.jsx)undefined5847658552(0,react_jsx_runtime.jsxs)undefined5855458631(link_default())undefined5900859082(0,react_jsx_runtime.jsx)undefined5954359617(0,react_jsx_runtime.jsx)undefined6034860424(0,react_jsx_runtime.jsxs)undefined6042660505react_jsx_runtime.Fragmentundefined6061260688(0,react_jsx_runtime.jsxs)undefined6069060767(link_default())undefined6114461218(0,react_jsx_runtime.jsx)undefined6167961753(0,react_jsx_runtime.jsx)undefined6231962395(0,react_jsx_runtime.jsxs)undefined6239762474(link_default())undefined6285362927(0,react_jsx_runtime.jsx)undefined6338863462(0,react_jsx_runtime.jsx)undefined6429364369(0,react_jsx_runtime.jsxs)undefined6437164450react_jsx_runtime.Fragmentundefined6455764633(0,react_jsx_runtime.jsxs)undefined6463564712(link_default())undefined6508465158(0,react_jsx_runtime.jsx)undefined6566065734(0,react_jsx_runtime.jsx)undefined6637666450(0,react_jsx_runtime.jsx)undefined6688966965(0,react_jsx_runtime.jsxs)undefined6696767046react_jsx_runtime.Fragmentundefined6716967245(0,react_jsx_runtime.jsxs)undefined6724767324(link_default())undefined6774167815(0,react_jsx_runtime.jsx)undefined6832468398(0,react_jsx_runtime.jsx)undefined6903669112(0,react_jsx_runtime.jsxs)undefined6911469191(link_default())undefined6961069684(0,react_jsx_runtime.jsx)undefined7019370267(0,react_jsx_runtime.jsx)undefined7113771213(0,react_jsx_runtime.jsxs)undefined7121571294react_jsx_runtime.Fragmentundefined7141771493(0,react_jsx_runtime.jsxs)undefined7149571572(link_default())undefined7199372067(0,react_jsx_runtime.jsx)undefined7261972693(0,react_jsx_runtime.jsx)undefined7335473430(0,react_jsx_runtime.jsxs)undefined7379973873(0,react_jsx_runtime.jsx)undefined7451174587(0,react_jsx_runtime.jsxs)undefined7458974666(link_default())undefined7508375157(0,react_jsx_runtime.jsx)undefined7566675740(0,react_jsx_runtime.jsx)undefined7659076666(0,react_jsx_runtime.jsxs)undefined7666876745(link_default())undefined7712277196(0,react_jsx_runtime.jsx)undefined7765777731(0,react_jsx_runtime.jsx)undefined7843678512(0,react_jsx_runtime.jsxs)undefined7851478591(link_default())undefined7896779041(0,react_jsx_runtime.jsx)undefined7950279576(0,react_jsx_runtime.jsx)undefined8022580301(0,react_jsx_runtime.jsxs)undefined8030380380(link_default())undefined8075380829(0,react_jsx_runtime.jsxs)undefined8134881422(0,react_jsx_runtime.jsx)undefined8228282356(0,react_jsx_runtime.jsx)undefined8300783083(0,react_jsx_runtime.jsxs)undefined8308583162(link_default())undefined8353783611(0,react_jsx_runtime.jsx)undefined8407284146(0,react_jsx_runtime.jsx)undefined8476484840(0,react_jsx_runtime.jsxs)undefined8502985111(0,auth/* signOut */.CI)undefined8554585619(0,react_jsx_runtime.jsx)undefined8606686140(0,react_jsx_runtime.jsx)undefined8681386889(0,react_jsx_runtime.jsxs)undefined8689186970react_jsx_runtime.Fragmentundefined8707787151(0,react_jsx_runtime.jsx)undefined8715387230(link_default())undefined8762887702(0,react_jsx_runtime.jsx)undefined8770487781(link_default())undefined8835588429(0,react_jsx_runtime.jsx)undefined8855788633(0,react_jsx_runtime.jsxs)undefined8884488918(0,react_jsx_runtime.jsx)undefined8910989185(0,react_jsx_runtime.jsxs)undefined8933989413(0,react_jsx_runtime.jsx)undefined8965889732(0,react_jsx_runtime.jsx)undefined9002090096(0,react_jsx_runtime.jsxs)undefined9027490348(0,react_jsx_runtime.jsx)undefined9072990803(0,react_jsx_runtime.jsx)undefined9080590882(link_default())undefined /***/ }) G@J/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // EXPORTS __webpack_require__.d(__webpack_exports__, { Header: () => (/* binding */ Header) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); // EXTERNAL MODULE: ../../node_modules/next/dist/api/navigation.js var navigation = __webpack_require__(71159); // EXTERNAL MODULE: ./src/lib/auth.ts var auth = __webpack_require__(13260); // EXTERNAL MODULE: ./src/context/locale.tsx var context_locale = __webpack_require__(96484); // EXTERNAL MODULE: ./src/lib/formatName.ts var formatName = __webpack_require__(48178); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ./src/lib/translations.ts var translations = __webpack_require__(12998); ;// ./src/components/LanguageSwitcher.tsx /* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ function LanguageSwitcher() { const { locale, setLocale } = (0,context_locale/* useLocale */.Y)(); const [open, setOpen] = (0,react.useState)(false); const ref = (0,react.useRef)(null); const current = translations/* LOCALES */.YZ.find((l)=>l.code === locale) ?? translations/* LOCALES */.YZ[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: translations/* LOCALES */.YZ.map((loc)=>/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } // EXTERNAL MODULE: ./src/lib/api.ts var api = __webpack_require__(91864); // EXTERNAL MODULE: ../../node_modules/socket.io-client/build/esm-debug/index.js + 30 modules var esm_debug = __webpack_require__(44826); ;// ./src/components/Header.tsx /* __next_internal_client_entry_do_not_use__ Header auto */ const API_URL = "https://api.canhelp.gr" || 0; function Header() { const router = (0,navigation.useRouter)(); const pathname = (0,navigation.usePathname)(); const { data: session } = (0,auth/* useSession */.wV)(); const { t, locale } = (0,context_locale/* useLocale */.Y)(); const [menuOpen, setMenuOpen] = (0,react.useState)(false); const [profileOpen, setProfileOpen] = (0,react.useState)(false); const [unreadNotif, setUnreadNotif] = (0,react.useState)(0); const [unreadChat, setUnreadChat] = (0,react.useState)(0); const [msgToast, setMsgToast] = (0,react.useState)(null); const [planTier, setPlanTier] = (0,react.useState)(null); const profileRef = (0,react.useRef)(null); const headerRef = (0,react.useRef)(null); const toastTimer = (0,react.useRef)(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) return; const socket = (0,esm_debug.io)(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>(0,api/* getUnreadCount */.$M)().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) { setPlanTier(null); return; } (0,api/* getMyDashboard */.H)().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "truncate max-w-[100px]", children: (0,formatName/* formatShortName */.H)(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); (0,auth/* signOut */.CI)().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)(LanguageSwitcher, {}) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)(LanguageSwitcher, {}), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>{ setMenuOpen(false); (0,auth/* signOut */.CI)().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } /***/ }) HK `LYLN // EXPORTS __webpack_require__.d(__webpack_exports__, { Header: () => (/* binding */ Header) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); // EXTERNAL MODULE: ../../node_modules/next/dist/api/navigation.js var navigation = __webpack_require__(71159); // EXTERNAL MODULE: ./src/lib/auth.ts var auth = __webpack_require__(13260); // EXTERNAL MODULE: ./src/context/locale.tsx var context_locale = __webpack_require__(96484); // EXTERNAL MODULE: ./src/lib/formatName.ts var formatName = __webpack_require__(48178); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ./src/lib/translations.ts var translations = __webpack_require__(12998); ;// ./src/components/LanguageSwitcher.tsx Z]/* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useRef, useEffect } from 'react'; import { useLocale } from '@/context/locale'; import { LOCALES } from '@/lib/translations'; export function LanguageSwitcher() { const { locale, setLocale } = useLocale(); const [open, setOpen] = useState(false); const ref = useRef(null); const current = LOCALES.find((l)=>l.code === locale) ?? LOCALES[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ _jsxs("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ _jsx("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ _jsx("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ _jsx("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: LOCALES.map((loc)=>/*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ _jsx("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } r70132undefined134185undefined187231undefined233277undefined279285undefined350358__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined391398__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined424429__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined458464__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined498504__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_asiSafe1__._undefined595603__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined908912__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined10181022__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13801383__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined15141517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18611864__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined21472150__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined23182324__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined23512355__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined28092812__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined29732976__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32313234__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined138224(0,context_locale/* useLocale */.Y)undefined257341(0,react.useState)undefined367447(0,react.useRef)undefined476545translations/* LOCALES */.YZundefined579643translations/* LOCALES */.YZundefined734820(0,react.useEffect)undefined11251201(0,react_jsx_runtime.jsxs)undefined13071383(0,react_jsx_runtime.jsxs)undefined17411815(0,react_jsx_runtime.jsx)undefined19462020(0,react_jsx_runtime.jsx)undefined23642438(0,react_jsx_runtime.jsx)undefined27212795(0,react_jsx_runtime.jsx)undefined29633032translations/* LOCALES */.YZundefined30593135(0,react_jsx_runtime.jsxs)undefined35893663(0,react_jsx_runtime.jsx)undefined38243898(0,react_jsx_runtime.jsx)undefined41534227(0,react_jsx_runtime.jsx)undefinedRawSource // EXTERNAL MODULE: ./src/lib/api.ts var api = __webpack_require__(91864); // EXTERNAL MODULE: ../../node_modules/socket.io-client/build/esm-debug/index.js + 30 modules var esm_debug = __webpack_require__(44826); ;// ./src/components/Header.tsx V"(/* __next_internal_client_entry_do_not_use__ Header auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import Link from 'next/link'; import { useRouter, usePathname } from 'next/navigation'; import { useSession, signOut } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { formatShortName } from '@/lib/formatName'; import { LanguageSwitcher } from './LanguageSwitcher'; import { useState, useRef, useEffect } from 'react'; import { getUnreadCount, getMyDashboard } from '@/lib/api'; import { io } from 'socket.io-client'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Header() { const router = useRouter(); const pathname = usePathname(); const { data: session } = useSession(); const { t, locale } = useLocale(); const [menuOpen, setMenuOpen] = useState(false); const [profileOpen, setProfileOpen] = useState(false); const [unreadNotif, setUnreadNotif] = useState(0); const [unreadChat, setUnreadChat] = useState(0); const [msgToast, setMsgToast] = useState(null); const [planTier, setPlanTier] = useState(null); const profileRef = useRef(null); const headerRef = useRef(null); const toastTimer = useRef(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; const socket = io(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>getUnreadCount().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setPlanTier(null); return; } getMyDashboard().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ _jsx(Link, { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ _jsx("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ _jsxs("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ _jsx(Link, { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ _jsx(Link, { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ _jsxs("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ _jsx("span", { className: "truncate max-w-[100px]", children: formatShortName(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ _jsxs("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ _jsx("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ _jsxs("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ _jsx(LanguageSwitcher, {}) ] }), /*#__PURE__*/ _jsxs("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ _jsx(LanguageSwitcher, {}), /*#__PURE__*/ _jsx("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ _jsxs("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setMenuOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ _jsx("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ _jsx("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ _jsx("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ _jsx(Link, { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } PT60145undefined147175undefined177233undefined235283undefined285329undefined331381undefined383436undefined438489undefined491549undefined551588undefined606636"https://api.canhelp.gr"undefined6416630undefined666672undefined712720__WEBPACK_MODULE_REFERENCE__2_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined746756__WEBPACK_MODULE_REFERENCE__2_5b22757365506174686e616d65225d_call_directImport_asiSafe1__._undefined791800__WEBPACK_MODULE_REFERENCE__3_5b2275736553657373696f6e225d_call_directImport_asiSafe1__._undefined831839__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined880887__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined939946__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined9981005__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10511058__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11001107__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11521159__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11911196__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12271232__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12641269__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined13731381__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined19281936__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined20852093__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined21542155__WEBPACK_MODULE_REFERENCE__10_5b22696f225d_call_directImport_asiSafe1__._undefined28642872__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined29913004__WEBPACK_MODULE_REFERENCE__9_5b22676574556e72656164436f756e74225d_call_directImport_asiSafe1__._undefined32533261__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined33623375__WEBPACK_MODULE_REFERENCE__9_5b226765744d7944617368626f617264225d_call_directImport_asiSafe1__._undefined35273535__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined39953999__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined40014009__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined40604063__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined42714275__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined44294433__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined46544657__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined46594662__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined48514854__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51725176__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined53965400__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined54025410__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined55335536__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined55385541__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined59305933__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined59355938__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined63726376__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined63786386__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined65096512__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined65146517__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined69146917__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69196922__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined73997402__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined74047407__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined78367840__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined78427850__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined79737977__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined79797982__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined83248327__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined88668869__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined95499552__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1013010134__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1013610139__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1047210475__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1101211015__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1164211645__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1222312227__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1251612520__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1294112944__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1313913153__WEBPACK_MODULE_REFERENCE__5_5b22666f726d617453686f72744e616d65225d_call_directImport_asiSafe1__._undefined1338913392__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1385613859__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1437214375__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1492514928__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1557015574__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1591415918__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1592015928__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined1609916103__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1610516108__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1666816671__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1733317336__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1819018194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1819618199__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1876118764__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1942619429__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2053920543__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2054520553__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined2072420728__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2073020733__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2129721300__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2200522008__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2281322817__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2328223285__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2412824132__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2413424137__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2469224695__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2539825401__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2615426158__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2661326616__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2745927463__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2746527468__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2802828031__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2869328696__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2982129825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2982729830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3034630349__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3096330966__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3180831812__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3181431817__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3233632339__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3295332956__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3382133825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3382733830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3434634350__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3504635049__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3602936032__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3692336927__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3692936932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3745037453__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3806738070__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3890438908__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3891038913__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3943339436__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4005040053__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4094540948__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4120641210__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4163641642__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined4207442077__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4267742680__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4378743791__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4379343801__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4392443927__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4392943932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4431644319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4432144324__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4482344826__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4482844843__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4497044974__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4517145174__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4517645191__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4525345256__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4555445557__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4600346006__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4631646319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4688746891__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4710547109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4711147119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4722647230__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4723247235__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4760847611__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4807248075__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4867248676__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4867848681__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4905849061__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4952249525__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5025650260__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5026250270__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5037750381__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5038350386__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5076350766__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5122751230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5179651800__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5180251805__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5218452187__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5264852651__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5348253486__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5348853496__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5360353607__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5360953612__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5398453987__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5448954492__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5513455137__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5557655580__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5558255590__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5571355717__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5571955722__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5613956142__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5665156654__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5729257296__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5729857301__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5772057723__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5823258235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5910559109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5911159119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5924259246__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5924859251__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5967259675__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6022760230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6089160895__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6126461267__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6190561909__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6191161914__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6233162334__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6284362846__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6369663700__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6370263705__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6408264085__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6454664549__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6525465258__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6526065263__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6563965642__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6610366106__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6675566759__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6676166764__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6713767141__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6766067663__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6852368526__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6917769181__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6918369186__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6956169564__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7002570028__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7064670650__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7083970845__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined7127971282__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7172971732__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7240572409__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7241172419__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined7252672529__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7253172534__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7293272935__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7293772940__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7351473517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7364573649__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7386073863__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7405474058__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7421274215__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7446074463__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7475174755__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7493374936__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7531775320__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7532275325__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined`$156242(0,navigation.useRouter)undefined268358(0,navigation.usePathname)undefined393481(0,auth/* useSession */.wV)undefined512598(0,context_locale/* useLocale */.Y)undefined639723(0,react.useState)undefined775859(0,react.useState)undefined911995(0,react.useState)undefined10411125(0,react.useState)undefined11671251(0,react.useState)undefined12961380(0,react.useState)undefined14121492(0,react.useRef)undefined15231603(0,react.useRef)undefined16351715(0,react.useRef)undefined18191905(0,react.useEffect)undefined24522538(0,react.useEffect)undefined26872773(0,react.useEffect)undefined28342907(0,esm_debug.io)undefined36163702(0,react.useEffect)undefined38213917(0,api/* getUnreadCount */.$M)undefined41664252(0,react.useEffect)undefined43534449(0,api/* getMyDashboard */.H)undefined46014687(0,react.useEffect)undefined51475223(0,react_jsx_runtime.jsxs)undefined52255304react_jsx_runtime.Fragmentundefined53555429(0,react_jsx_runtime.jsx)undefined56375713(0,react_jsx_runtime.jsxs)undefined58675943(0,react_jsx_runtime.jsxs)undefined61646238(0,react_jsx_runtime.jsx)undefined62406317(link_default())undefined65066580(0,react_jsx_runtime.jsx)undefined68986974(0,react_jsx_runtime.jsxs)undefined71947270(0,react_jsx_runtime.jsxs)undefined72727351react_jsx_runtime.Fragmentundefined74747548(0,react_jsx_runtime.jsx)undefined75507627(link_default())undefined80168090(0,react_jsx_runtime.jsx)undefined80928169(link_default())undefined86038679(0,react_jsx_runtime.jsxs)undefined86818760react_jsx_runtime.Fragmentundefined88838957(0,react_jsx_runtime.jsx)undefined89599036(link_default())undefined94339507(0,react_jsx_runtime.jsx)undefined95099586(link_default())undefined1006310137(0,react_jsx_runtime.jsx)undefined1013910216(link_default())undefined1064510721(0,react_jsx_runtime.jsxs)undefined1072310802react_jsx_runtime.Fragmentundefined1092511001(0,react_jsx_runtime.jsxs)undefined1100311080(link_default())undefined1142211496(0,react_jsx_runtime.jsx)undefined1203512109(0,react_jsx_runtime.jsx)undefined1278912863(0,react_jsx_runtime.jsx)undefined1344113517(0,react_jsx_runtime.jsxs)undefined1351913596(link_default())undefined1392914003(0,react_jsx_runtime.jsx)undefined1454014614(0,react_jsx_runtime.jsx)undefined1524115315(0,react_jsx_runtime.jsx)undefined1589315969(0,react_jsx_runtime.jsxs)undefined1625816334(0,react_jsx_runtime.jsxs)undefined1675516829(0,react_jsx_runtime.jsx)undefined1702417122(0,formatName/* formatShortName */.H)undefined1735817432(0,react_jsx_runtime.jsx)undefined1789617970(0,react_jsx_runtime.jsx)undefined1848318557(0,react_jsx_runtime.jsx)undefined1910719181(0,react_jsx_runtime.jsx)undefined1982319899(0,react_jsx_runtime.jsxs)undefined2023920315(0,react_jsx_runtime.jsxs)undefined2031720396react_jsx_runtime.Fragmentundefined2056720643(0,react_jsx_runtime.jsxs)undefined2064520722(link_default())undefined2128221356(0,react_jsx_runtime.jsx)undefined2201822092(0,react_jsx_runtime.jsx)undefined2294623022(0,react_jsx_runtime.jsxs)undefined2302423101(link_default())undefined2366323737(0,react_jsx_runtime.jsx)undefined2439924473(0,react_jsx_runtime.jsx)undefined2558325659(0,react_jsx_runtime.jsxs)undefined2566125740react_jsx_runtime.Fragmentundefined2591125987(0,react_jsx_runtime.jsxs)undefined2598926066(link_default())undefined2663026704(0,react_jsx_runtime.jsx)undefined2740927483(0,react_jsx_runtime.jsx)undefined2828828364(0,react_jsx_runtime.jsxs)undefined2882928903(0,react_jsx_runtime.jsx)undefined2974629822(0,react_jsx_runtime.jsxs)undefined2982429901(link_default())undefined3045630530(0,react_jsx_runtime.jsx)undefined3123331307(0,react_jsx_runtime.jsx)undefined3206032136(0,react_jsx_runtime.jsxs)undefined3259132665(0,react_jsx_runtime.jsx)undefined3350833584(0,react_jsx_runtime.jsxs)undefined3358633663(link_default())undefined3422334297(0,react_jsx_runtime.jsx)undefined3495935033(0,react_jsx_runtime.jsx)undefined3615836234(0,react_jsx_runtime.jsxs)undefined3623636313(link_default())undefined3682936903(0,react_jsx_runtime.jsx)undefined3751737591(0,react_jsx_runtime.jsx)undefined3843338509(0,react_jsx_runtime.jsxs)undefined3851138588(link_default())undefined3910739181(0,react_jsx_runtime.jsx)undefined3979539869(0,react_jsx_runtime.jsx)undefined4073440810(0,react_jsx_runtime.jsxs)undefined4081240889(link_default())undefined4140541481(0,react_jsx_runtime.jsxs)undefined4217742251(0,react_jsx_runtime.jsx)undefined4323143305(0,react_jsx_runtime.jsx)undefined4419644272(0,react_jsx_runtime.jsxs)undefined4427444351(link_default())undefined4486944943(0,react_jsx_runtime.jsx)undefined4555745631(0,react_jsx_runtime.jsx)undefined4646546541(0,react_jsx_runtime.jsxs)undefined4654346620(link_default())undefined4714047214(0,react_jsx_runtime.jsx)undefined4782847902(0,react_jsx_runtime.jsx)undefined4879448868(0,react_jsx_runtime.jsx)undefined4912649202(0,react_jsx_runtime.jsxs)undefined4962849710(0,auth/* signOut */.CI)undefined5014250216(0,react_jsx_runtime.jsx)undefined5081650890(0,react_jsx_runtime.jsx)undefined5199752073(0,react_jsx_runtime.jsxs)undefined5207552154react_jsx_runtime.Fragmentundefined5227752351(0,react_jsx_runtime.jsx)undefined5235352430(link_default())undefined5281452888(0,react_jsx_runtime.jsx)undefined5289052967(link_default())undefined5346653540(0,react_jsx_runtime.jsx)undefined5354253637LanguageSwitcherundefined5376453840(0,react_jsx_runtime.jsxs)undefined5403754111(0,react_jsx_runtime.jsx)undefined5411354208LanguageSwitcherundefined5427054344(0,react_jsx_runtime.jsx)undefined5464254716(0,react_jsx_runtime.jsx)undefined5516255236(0,react_jsx_runtime.jsx)undefined5554655620(0,react_jsx_runtime.jsx)undefined5618856264(0,react_jsx_runtime.jsxs)undefined5647856554(0,react_jsx_runtime.jsxs)undefined5655656635react_jsx_runtime.Fragmentundefined5674256818(0,react_jsx_runtime.jsxs)undefined5682056897(link_default())undefined5727057344(0,react_jsx_runtime.jsx)undefined5780557879(0,react_jsx_runtime.jsx)undefined5847658552(0,react_jsx_runtime.jsxs)undefined5855458631(link_default())undefined5900859082(0,react_jsx_runtime.jsx)undefined5954359617(0,react_jsx_runtime.jsx)undefined6034860424(0,react_jsx_runtime.jsxs)undefined6042660505react_jsx_runtime.Fragmentundefined6061260688(0,react_jsx_runtime.jsxs)undefined6069060767(link_default())undefined6114461218(0,react_jsx_runtime.jsx)undefined6167961753(0,react_jsx_runtime.jsx)undefined6231962395(0,react_jsx_runtime.jsxs)undefined6239762474(link_default())undefined6285362927(0,react_jsx_runtime.jsx)undefined6338863462(0,react_jsx_runtime.jsx)undefined6429364369(0,react_jsx_runtime.jsxs)undefined6437164450react_jsx_runtime.Fragmentundefined6455764633(0,react_jsx_runtime.jsxs)undefined6463564712(link_default())undefined6508465158(0,react_jsx_runtime.jsx)undefined6566065734(0,react_jsx_runtime.jsx)undefined6637666450(0,react_jsx_runtime.jsx)undefined6688966965(0,react_jsx_runtime.jsxs)undefined6696767046react_jsx_runtime.Fragmentundefined6716967245(0,react_jsx_runtime.jsxs)undefined6724767324(link_default())undefined6774167815(0,react_jsx_runtime.jsx)undefined6832468398(0,react_jsx_runtime.jsx)undefined6903669112(0,react_jsx_runtime.jsxs)undefined6911469191(link_default())undefined6961069684(0,react_jsx_runtime.jsx)undefined7019370267(0,react_jsx_runtime.jsx)undefined7113771213(0,react_jsx_runtime.jsxs)undefined7121571294react_jsx_runtime.Fragmentundefined7141771493(0,react_jsx_runtime.jsxs)undefined7149571572(link_default())undefined7199372067(0,react_jsx_runtime.jsx)undefined7261972693(0,react_jsx_runtime.jsx)undefined7335473430(0,react_jsx_runtime.jsxs)undefined7379973873(0,react_jsx_runtime.jsx)undefined7451174587(0,react_jsx_runtime.jsxs)undefined7458974666(link_default())undefined7508375157(0,react_jsx_runtime.jsx)undefined7566675740(0,react_jsx_runtime.jsx)undefined7659076666(0,react_jsx_runtime.jsxs)undefined7666876745(link_default())undefined7712277196(0,react_jsx_runtime.jsx)undefined7765777731(0,react_jsx_runtime.jsx)undefined7843678512(0,react_jsx_runtime.jsxs)undefined7851478591(link_default())undefined7896779041(0,react_jsx_runtime.jsx)undefined7950279576(0,react_jsx_runtime.jsx)undefined8022580301(0,react_jsx_runtime.jsxs)undefined8030380380(link_default())undefined8075380829(0,react_jsx_runtime.jsxs)undefined8134881422(0,react_jsx_runtime.jsx)undefined8228282356(0,react_jsx_runtime.jsx)undefined8300783083(0,react_jsx_runtime.jsxs)undefined8308583162(link_default())undefined8353783611(0,react_jsx_runtime.jsx)undefined8407284146(0,react_jsx_runtime.jsx)undefined8476484840(0,react_jsx_runtime.jsxs)undefined8502985111(0,auth/* signOut */.CI)undefined8554585619(0,react_jsx_runtime.jsx)undefined8606686140(0,react_jsx_runtime.jsx)undefined8681386889(0,react_jsx_runtime.jsxs)undefined8689186970react_jsx_runtime.Fragmentundefined8707787151(0,react_jsx_runtime.jsx)undefined8715387230(link_default())undefined8762887702(0,react_jsx_runtime.jsx)undefined8770487781(link_default())undefined8835588429(0,react_jsx_runtime.jsx)undefined8855788633(0,react_jsx_runtime.jsxs)undefined8884488918(0,react_jsx_runtime.jsx)undefined8910989185(0,react_jsx_runtime.jsxs)undefined8933989413(0,react_jsx_runtime.jsx)undefined8965889732(0,react_jsx_runtime.jsx)undefined9002090096(0,react_jsx_runtime.jsxs)undefined9027490348(0,react_jsx_runtime.jsx)undefined9072990803(0,react_jsx_runtime.jsx)undefined9080590882(link_default())undefinedFH, /***/ 64271:  vwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceV/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceimport(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/builtin/global-error.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-page.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-segment.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/http-access-fallback/error-boundary.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/layout-router.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/metadata/async-metadata.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/render-from-template-context.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/framework/boundary-components.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/metadata/generate/icon-mark.js");  aqvNNSBG9>Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 58671, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56542, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 88248, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 49743, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 96231, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 10959, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 72041, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 95094, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67487, 23))buffersourcesizemapshashPromise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 58671, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56542, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 88248, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 49743, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 96231, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 10959, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 72041, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 95094, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67487, 23)); {"finalSource":true}mapbufferedMap ReplaceSourceRawSourceimport(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/builtin/global-error.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-page.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-segment.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/http-access-fallback/error-boundary.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/layout-router.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/metadata/async-metadata.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/render-from-template-context.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/framework/boundary-components.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/metadata/generate/icon-mark.js"); 0113Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 58671, 23))undefined118222Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56542, 23))undefined227334Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 88248, 23))undefined339467Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 49743, 23))undefined472578Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 96231, 23))undefined583699Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 10959, 23))undefined704825Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 72041, 23))undefined830938Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 95094, 23))undefined9431049Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67487, 23))undefined /***/ }) 7/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 58671, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56542, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 88248, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 49743, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 96231, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 10959, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 72041, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 95094, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67487, 23)); /***/ }) 8; <Kimport(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/builtin/global-error.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-page.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-segment.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/http-access-fallback/error-boundary.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/layout-router.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/metadata/async-metadata.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/render-from-template-context.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/framework/boundary-components.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/metadata/generate/icon-mark.js"); 0113Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 58671, 23))undefined118222Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56542, 23))undefined227334Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 88248, 23))undefined339467Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 49743, 23))undefined472578Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 96231, 23))undefined583699Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 10959, 23))undefined704825Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 72041, 23))undefined830938Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 95094, 23))undefined9431049Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67487, 23))undefined<>, /***/ 67674:  (webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource *webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Header: () => (/* binding */ Header) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Header = registerClientReference( function() { throw new Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Header.tsx", "Header", ); `=D(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)buffersourcesizemapshash/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Header: () => (/* binding */ Header) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const Header = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Header.tsx", "Header", ); {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Header: () => (/* binding */ Header) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); ReplaceSourceRawSource// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Header = registerClientReference( function() { throw new Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Header.tsx", "Header", );61134undefined136142undefined158180(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined /***/ }) -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Header: () => (/* binding */ Header) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const Header = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Header.tsx", "Header", ); /***/ }) .1  2?2/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Header: () => (/* binding */ Header) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); @// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Header = registerClientReference( function() { throw new Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Header.tsx", "Header", );24, /***/ 72088:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/***/ (() => { /* (ignored) */  /***/ }) #$ %( )*+,+-, /***/ 72519:  dwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceV/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceimport(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/builtin/global-error.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-page.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-segment.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/http-access-fallback/error-boundary.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/layout-router.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/metadata/async-metadata.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/render-from-template-context.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/framework/boundary-components.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/metadata/generate/icon-mark.js");  aqvNNSBG9>Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 48365, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 64596, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56186, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67805, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 27561, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 47569, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 42747, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56676, 23))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 97225))buffersourcesizemapshashPromise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 48365, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 64596, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56186, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67805, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 27561, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 47569, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 42747, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56676, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 97225)); {"finalSource":true}mapbufferedMap ReplaceSourceRawSourceimport(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/builtin/global-error.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-page.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-segment.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/http-access-fallback/error-boundary.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/layout-router.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/metadata/async-metadata.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/render-from-template-context.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/framework/boundary-components.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/metadata/generate/icon-mark.js"); 0113Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 48365, 23))undefined118222Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 64596, 23))undefined227334Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56186, 23))undefined339467Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67805, 23))undefined472578Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 27561, 23))undefined583699Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 47569, 23))undefined704825Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 42747, 23))undefined830938Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56676, 23))undefined9431049Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 97225))undefined /***/ }) /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 48365, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 64596, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56186, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67805, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 27561, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 47569, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 42747, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56676, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 97225)); /***/ })   !00113Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 48365, 23))undefined118222Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 64596, 23))undefined227334Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56186, 23))undefined339467Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67805, 23))undefined472578Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 27561, 23))undefined583699Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 47569, 23))undefined704825Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 42747, 23))undefined830938Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56676, 23))undefined9431049Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 97225))undefined"$, /***/ 85105:  s webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceV/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcefimport(/* webpackMode: "eager", webpackExports: ["Footer"] */ "/opt/canhelp/apps/web/src/components/Footer.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["Header"] */ "/opt/canhelp/apps/web/src/components/Header.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["ScrollToTopButton"] */ "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocaleProvider"] */ "/opt/canhelp/apps/web/src/context/locale.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocationProvider"] */ "/opt/canhelp/apps/web/src/context/location.tsx"); aotFmrcPromise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 15043))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 58719))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 21046))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96484))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 56003))buffersourcesizemapshashPromise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 15043)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 58719)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 21046)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96484)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 56003)); {"finalSource":true}mapbufferedMap ReplaceSourceRawSourcefimport(/* webpackMode: "eager", webpackExports: ["Footer"] */ "/opt/canhelp/apps/web/src/components/Footer.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["Header"] */ "/opt/canhelp/apps/web/src/components/Header.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["ScrollToTopButton"] */ "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocaleProvider"] */ "/opt/canhelp/apps/web/src/context/locale.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocationProvider"] */ "/opt/canhelp/apps/web/src/context/location.tsx"); )0111Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 15043))undefined116227Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 58719))undefined232365Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 21046))undefined370486Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96484))undefined491611Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 56003))undefined /***/ }) R/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 15043)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 58719)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 21046)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96484)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 56003)); /***/ })  'fimport(/* webpackMode: "eager", webpackExports: ["Footer"] */ "/opt/canhelp/apps/web/src/components/Footer.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["Header"] */ "/opt/canhelp/apps/web/src/components/Header.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["ScrollToTopButton"] */ "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocaleProvider"] */ "/opt/canhelp/apps/web/src/context/locale.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocationProvider"] */ "/opt/canhelp/apps/web/src/context/location.tsx"); )0111Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 15043))undefined116227Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 58719))undefined232365Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 21046))undefined370486Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96484))undefined491611Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 56003))undefined, /***/ 85998:  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceV/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceimport(/* webpackMode: "eager", webpackExports: ["__esModule","default"] */ "/opt/canhelp/node_modules/next/dist/client/app-dir/link.js"); @Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 3498, 23))buffersourcesizemapshashgPromise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 3498, 23)); {"finalSource":true}mapbufferedMap ReplaceSourceRawSourceimport(/* webpackMode: "eager", webpackExports: ["__esModule","default"] */ "/opt/canhelp/node_modules/next/dist/client/app-dir/link.js"); r0136Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 3498, 23))undefined /***/ })  /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 3498, 23)); /***/ })    r0136Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 3498, 23))undefined, /***/ 91864:  \webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource uwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcefQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); _X[aX^ :@7_=L R E K  R X k q > D v | g_mkq06sy<B_e=Cdj &_>D5;PV CI<Bkq_  D!J!!"V"\"$$%%'$'j'p''(>(D(((W)])*_*I*O***R+X+,,B,H,,,-"---h.n./%///\0b081>111113_344:44444;5A555b6h666+717888889a9g9::P;V;;;<_<==T=Z===>>>>??@ @@@-A3AtAzABB^BdBCCdCjCCCJDHPDDD;EAE|EEOFUF true"https://api.canhelp.gr"00truebuffersourcesizemapshashwk/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); {"finalSource":true}mapbufferedMap ConcatSourceRawSource /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ ReplaceSourceRawSourcefQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); Q 164190 trueundefined226256"https://api.canhelp.gr"undefined2612830undefined2873440undefined347353undefined437463trueundefined11121118undefined12501256undefined14111417undefined15051511undefined15571563undefined17151721undefined17961802undefined18501856undefined19711977undefined21032109undefined22042210undefined23802386undefined24522458undefined25062512undefined26292635undefined27282734undefined28292835undefined28982904undefined30543060undefined31793185undefined32553261undefined33903396undefined34463452undefined35283534undefined36073613undefined36873693undefined39473953undefined40814087undefined41444150undefined42114217undefined43124318undefined44124418undefined45174523undefined47034709undefined48494855undefined49254931undefined50855091undefined52205226undefined53535359undefined54085414undefined55105516undefined56175623undefined56945700undefined58305836undefined61296135undefined61976203undefined63336339undefined64806486undefined66656671undefined67236729undefined69726978undefined70837089undefined71907196undefined73617367undefined74267432undefined75317537undefined76957701undefined78387844undefined79577963undefined82148220undefined83228328undefined84248430undefined85168522undefined86998705undefined87908796undefined92389244undefined96239629undefined1001410020undefined1009010096undefined1023610242undefined1030210308undefined1043710443undefined1058310589undefined1076710773undefined1082510831undefined1095210958undefined1109011096undefined1126611272undefined1133011336undefined1146811474undefined1154811554undefined1171311719undefined1188011886undefined1206312069undefined1216712173undefined1238012386undefined1260012606undefined1273212738undefined1279212798undefined1321913225undefined1336413370undefined1346813474undefined1355413560undefined1362713633undefined1376913775undefined1392213928undefined1403414040undefined1412314129undefined1435614362undefined1452214528undefined1458914595undefined1468914695undefined1502215028undefined1518415190undefined1535215358undefined1552415530undefined1564015646undefined1570015706undefined1576415770undefined1606216068undefined1612016126undefined1631716323undefined1638716393undefined1661016616undefined1668516691undefined1675616762undefined1691116917undefined1699016996undefined1717317179undefined1725217258undefined1737017376undefined1748217488undefined1764717653undefined1772317729undefined1778817794undefined1799918005undefined /***/ }) k/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); /***/ })    /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ fQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); Q 164190 trueundefined226256"https://api.canhelp.gr"undefined2612830undefined2873440undefined347353undefined437463trueundefined11121118undefined12501256undefined14111417undefined15051511undefined15571563undefined17151721undefined17961802undefined18501856undefined19711977undefined21032109undefined22042210undefined23802386undefined24522458undefined25062512undefined26292635undefined27282734undefined28292835undefined28982904undefined30543060undefined31793185undefined32553261undefined33903396undefined34463452undefined35283534undefined36073613undefined36873693undefined39473953undefined40814087undefined41444150undefined42114217undefined43124318undefined44124418undefined45174523undefined47034709undefined48494855undefined49254931undefined50855091undefined52205226undefined53535359undefined54085414undefined55105516undefined56175623undefined56945700undefined58305836undefined61296135undefined61976203undefined63336339undefined64806486undefined66656671undefined67236729undefined69726978undefined70837089undefined71907196undefined73617367undefined74267432undefined75317537undefined76957701undefined78387844undefined79577963undefined82148220undefined83228328undefined84248430undefined85168522undefined86998705undefined87908796undefined92389244undefined96239629undefined1001410020undefined1009010096undefined1023610242undefined1030210308undefined1043710443undefined1058310589undefined1076710773undefined1082510831undefined1095210958undefined1109011096undefined1126611272undefined1133011336undefined1146811474undefined1154811554undefined1171311719undefined1188011886undefined1206312069undefined1216712173undefined1238012386undefined1260012606undefined1273212738undefined1279212798undefined1321913225undefined1336413370undefined1346813474undefined1355413560undefined1362713633undefined1376913775undefined1392213928undefined1403414040undefined1412314129undefined1435614362undefined1452214528undefined1458914595undefined1468914695undefined1502215028undefined1518415190undefined1535215358undefined1552415530undefined1564015646undefined1570015706undefined1576415770undefined1606216068undefined1612016126undefined1631716323undefined1638716393undefined1661016616undefined1668516691undefined1675616762undefined1691116917undefined1699016996undefined1717317179undefined1725217258undefined1737017376undefined1748217488undefined1764717653undefined1772317729undefined1778817794undefined1799918005undefined, /***/ 91946:  Owebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource 8webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43560); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourceZ import { fillMetadataSegment } from 'next/dist/lib/metadata/get-metadata-route' export default async (props) => { const imageData = {"type":"image/svg+xml","sizes":"any"} const imageUrl = fillMetadataSegment(".", await props.params, "icon.svg") return [{ ...imageData, url: imageUrl + "?71a523b2dd824001", }] } dPUcUcBZ u@/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__.fillMetadataSegment));buffersourcesizemapshash__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43560); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (async (props) => { const imageData = {"type":"image/svg+xml","sizes":"any"} const imageUrl = (0,next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__.fillMetadataSegment)(".", await props.params, "icon.svg") return [{ ...imageData, url: imageUrl + "?71a523b2dd824001", }] }); {"finalSource":true}mapbufferedMap ConcatSourceRawSource __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43560); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__); ReplaceSourceRawSourceZ import { fillMetadataSegment } from 'next/dist/lib/metadata/get-metadata-route' export default async (props) => { const imageData = {"type":"image/svg+xml","sizes":"any"} const imageUrl = fillMetadataSegment(".", await props.params, "icon.svg") return [{ ...imageData, url: imageUrl + "?71a523b2dd824001", }] }280undefined8599/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined8599undefined201219(0,next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__.fillMetadataSegment)undefined346345.5);undefined /***/ }) /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43560); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (async (props) => { const imageData = {"type":"image/svg+xml","sizes":"any"} const imageUrl = (0,next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__.fillMetadataSegment)(".", await props.params, "icon.svg") return [{ ...imageData, url: imageUrl + "?71a523b2dd824001", }] }); /***/ })    __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43560); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__); Z import { fillMetadataSegment } from 'next/dist/lib/metadata/get-metadata-route' export default async (props) => { const imageData = {"type":"image/svg+xml","sizes":"any"} const imageUrl = fillMetadataSegment(".", await props.params, "icon.svg") return [{ ...imageData, url: imageUrl + "?71a523b2dd824001", }] }280undefined8599/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined8599undefined201219(0,next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__.fillMetadataSegment)undefined346345.5);undefined, /***/ 94833:  p webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceV/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource  webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourcefimport(/* webpackMode: "eager", webpackExports: ["Footer"] */ "/opt/canhelp/apps/web/src/components/Footer.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["Header"] */ "/opt/canhelp/apps/web/src/components/Header.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["ScrollToTopButton"] */ "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocaleProvider"] */ "/opt/canhelp/apps/web/src/context/locale.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocationProvider"] */ "/opt/canhelp/apps/web/src/context/location.tsx"); aotFmrcPromise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 39348))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 67674))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 32948))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 20138))Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1697))buffersourcesizemapshashPromise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 39348)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 67674)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 32948)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 20138)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1697)); {"finalSource":true}mapbufferedMap ReplaceSourceRawSourcefimport(/* webpackMode: "eager", webpackExports: ["Footer"] */ "/opt/canhelp/apps/web/src/components/Footer.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["Header"] */ "/opt/canhelp/apps/web/src/components/Header.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["ScrollToTopButton"] */ "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocaleProvider"] */ "/opt/canhelp/apps/web/src/context/locale.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocationProvider"] */ "/opt/canhelp/apps/web/src/context/location.tsx"); (0111Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 39348))undefined116227Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 67674))undefined232365Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 32948))undefined370486Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 20138))undefined491611Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1697))undefined /***/ }) Q/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 39348)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 67674)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 32948)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 20138)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1697)); /***/ })  (0111Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 39348))undefined116227Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 67674))undefined232365Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 32948))undefined370486Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 20138))undefined491611Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1697))undefined, /***/ 96484:  :5webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource_/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource +webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { getTranslations } from '@/lib/translations'; const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ createContext({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } export function LocaleProvider({ children, initialLocale }) { const router = useRouter(); const [locale, setLocaleState] = useState(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = useCallback((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = useCallback((key, fallback)=>getTranslations(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ _jsx(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } export function useLocale() { return useContext(LocaleContext); } cN}_5$ow2::?U  1 4 B (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)"https://api.canhelp.gr"0(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)0(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)buffersourcesizemapshash /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } function LocaleProvider({ children, initialLocale }) { const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const [locale, setLocaleState] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((key, fallback)=>(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } function useLocale() { return (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(LocaleContext); } {"finalSource":true}mapbufferedMap ConcatSourceRawSource/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); ReplaceSourceRawSource /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { getTranslations } from '@/lib/translations'; const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ createContext({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } export function LocaleProvider({ children, initialLocale }) { const router = useRouter(); const [locale, setLocaleState] = useState(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = useCallback((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = useCallback((key, fallback)=>getTranslations(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ _jsx(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } export function useLocale() { return useContext(LocaleContext); } G78125undefined127210undefined212255undefined257309undefined413425(0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)undefined798804undefined879887(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined929936(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10741082(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined13081338"https://api.canhelp.gr"undefined134313650undefined17121722(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined20012031"https://api.canhelp.gr"undefined203620580undefined24902500(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined25192533(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)undefined26092612(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined27622768undefined28032812(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)undefined /***/ }) u/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } function LocaleProvider({ children, initialLocale }) { const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const [locale, setLocaleState] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((key, fallback)=>(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } function useLocale() { return (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(LocaleContext); } /***/ })   /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998);  /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { getTranslations } from '@/lib/translations'; const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ createContext({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } export function LocaleProvider({ children, initialLocale }) { const router = useRouter(); const [locale, setLocaleState] = useState(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = useCallback((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = useCallback((key, fallback)=>getTranslations(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ _jsx(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } export function useLocale() { return useContext(LocaleContext); } G78125undefined127210undefined212255undefined257309undefined413425(0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)undefined798804undefined879887(0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)undefined929936(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10741082(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined13081338"https://api.canhelp.gr"undefined134313650undefined17121722(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined20012031"https://api.canhelp.gr"undefined203620580undefined24902500(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined25192533(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)undefined26092612(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined27622768undefined28032812(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)undefined }; ;  :exports.id = 892; exports.ids = [892]; exports.modules = { /***/ 1241: /***/ (() => { /* (ignored) */ /***/ }), /***/ 1697: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider) /* harmony export */ }); /* unused harmony export useLocation */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const LocationProvider = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "LocationProvider", );const useLocation = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "useLocation", ); /***/ }), /***/ 12998: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ getTranslations), /* harmony export */ YZ: () => (/* binding */ LOCALES) /* harmony export */ }); /* unused harmony export translations */ const LOCALES = [ { code: 'el', label: 'Ελληνικά', flag: '🇬🇷' }, { code: 'en', label: 'English', flag: '🇬🇧' }, { code: 'ru', label: 'Русский', flag: '🇷🇺' } ]; const translations = { el: { 'footer.slogan': 'Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.', 'footer.links': 'Σύνδεσμοι', 'footer.socials': 'Στα κοινωνικά δίκτυα', // Nav 'nav.home': 'Αρχική', 'nav.tasks': 'Εργασίες', 'nav.post': '+ Δημοσίευση', 'nav.dashboard': 'Πίνακας', 'nav.chat': 'Μηνύματα', 'nav.notifications': 'Ειδοποιήσεις', 'nav.profile': 'Προφίλ', 'nav.admin': 'Διαχείριση', 'nav.specialists': 'Ειδικοί', 'nav.new_task': 'Νέα εργασία', 'nav.login': 'Σύνδεση', 'nav.register': 'Εγγραφή', 'nav.logout': 'Έξοδος', // Hero 'hero.title': 'Βρες ειδικό για κάθε δουλειά', 'hero.subtitle': 'Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία', 'hero.cta.post': 'Δημοσίευσε εργασία', 'hero.cta.browse': 'Γίνε ειδικός', 'hero.search.placeholder': 'Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...', 'stats.specialists': 'ειδικοί', 'stats.tasks': 'εργασίες', 'stats.categories': 'κατηγορίες', 'stats.free': 'δωρεάν εγγραφή', // Sections 'section.categories': 'Δημιούργησε εργασία σε οποιαδήποτε κατηγορία', 'section.how': 'Πώς λειτουργεί', 'section.recent': 'Πρόσφατες εργασίες', 'section.all': 'Δες όλες →', 'section.more': 'ακόμα', 'section.cities': 'Πόλεις & Περιοχές', 'section.community': 'Ένα κοινοτικό έργο για όλους', 'community.subtitle': 'Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.', 'community.point1.title': 'Είσαι ειδικός σε κάτι;', 'community.point1.desc': 'Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.', 'community.point2.title': 'Χρειάζεσαι βοήθεια;', 'community.point2.desc': 'Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.', 'community.point3.title': 'Βοήθησε το έργο να αναπτυχθεί', 'community.point3.desc': 'Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.', 'community.share': 'Μοιράσου με φίλους', 'community.share.copied': 'Σύνδεσμος αντιγράφηκε!', // Referral section on home page 'section.referral': 'Πρόγραμμα παραπομπών', 'referral.home.subtitle': 'Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.', 'referral.home.step1.title': 'Εγγραφείσε και λάβε σύνδεσμο', 'referral.home.step1.desc': 'Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.', 'referral.home.step2.title': 'Μοιράσου με φίλους', 'referral.home.step2.desc': 'Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.', 'referral.home.step3.title': 'Κέρδισε ανταμοιβές', 'referral.home.step3.desc': 'Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.', 'referral.home.cta': 'Πάρε τον σύνδεσμό σου', 'referral.home.badge': 'Πρόγραμμα παραπομπών', // FAQ section 'section.faq': 'Συχνές Ερωτήσεις', 'faq.q1': 'Πώς λειτουργεί το CanHelp;', 'faq.a1': 'Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.', 'faq.q2': 'Πόσο κοστίζει η χρήση της πλατφόρμας;', 'faq.a2': 'Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.', 'faq.q3': 'Πώς μπορώ να γίνω ειδικός;', 'faq.a3': 'Κάνε εγγραφή, πήγαινε στο «Γίνε Ειδικός», συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.', 'faq.q4': 'Πώς επιλέγω τον κατάλληλο ειδικό;', 'faq.a4': 'Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q5': 'Τι γίνεται αν δεν είμαι ικανοποιημένος;', 'faq.a5': 'Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.', 'faq.q6': 'Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;', 'faq.a6': 'Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q7': 'Πόσος χρόνος χρειάζεται για να λάβω προσφορές;', 'faq.a7': 'Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.', 'faq.q8': 'Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;', 'faq.a8': 'Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.', 'faq.q9': 'Τι είδη εργασιών μπορώ να βρω στο CanHelp;', 'faq.a9': 'Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.', 'faq.q10': 'Υπάρχει εφαρμογή για κινητό;', 'faq.a10': 'Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.', // How it works 'how.step1.title': 'Δημοσίευσε εργασία', 'how.step1.desc': 'Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου', 'how.step2.title': 'Λάβε προσφορές', 'how.step2.desc': 'Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο', 'how.step3.title': 'Επίλεξε & ξεκίνα', 'how.step3.desc': 'Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία', // Tasks page 'tasks.title': 'εργασίες', 'tasks.filters': 'Φίλτρα', 'tasks.search': 'Αναζήτηση', 'tasks.search.placeholder': 'Τίτλος ή λέξη κλειδί...', 'tasks.search.btn': 'Αναζήτηση', 'tasks.publish': 'Δημοσίευση', 'tasks.category.all': 'Όλες', 'tasks.category.all_in': 'Όλα στην', 'tasks.category.label': 'Κατηγορία', 'tasks.location.label': 'Πόλη', 'tasks.location.placeholder': 'π.χ. Αθήνα', 'tasks.empty': 'Δεν βρέθηκαν εργασίες', 'tasks.empty.cta': 'Δημοσίευσε την πρώτη', // Task detail 'task.status.open': 'Ανοιχτή', 'task.status.in_progress': 'Σε εξέλιξη', 'task.status.completed': 'Ολοκληρωμένη', 'task.status.cancelled': 'Ακυρωμένη', 'task.status.draft': 'Πρόχειρο', 'task.budget': 'Προϋπολογισμός', 'task.location': 'Τοποθεσία', 'task.deadline': 'Ημερομηνία έναρξης', 'task.created_at': 'Δημιουργήθηκε', 'task.customer': 'Πελάτης', 'task.offer.btn': 'Υποβολή προσφοράς', 'task.invite.banner_title': 'Σας προσκαλούν σε αυτήν την εργασία', 'task.invite.banner_hint': 'Ο πελάτης σας πρόσκαλεσε προσωπικά', 'task.invite.accept': 'Αποστολή προσφοράς', 'task.invite.decline': 'Άρνηση', 'offer.accept': 'Αποδοχή', 'offer.decline': 'Απόρριψη', 'task.complete': 'Ολοκλήρωση εργασίας', 'task.complete.confirm': 'Να ολοκληρωθεί η εργασία;', 'task.edit': 'Επεξεργασία', 'task.status_label': 'Κατάσταση', 'task.yours': 'Η εργασία σου', 'task.offer.yours': 'Η προσφορά σου', 'review.leave': 'Άφησε αξιολόγηση', 'review.rating': 'Βαθμολογία', 'review.comment': 'Σχόλιο', 'review.comment.placeholder': 'Πες μας για την εμπειρία σου...', 'review.submit': 'Υποβολή αξιολόγησης', 'review.submitting': 'Αποστολή...', 'review.done': 'Η αξιολόγηση καταχωρήθηκε!', 'profile.reviews': 'Αξιολογήσεις', 'profile.no_reviews': 'Δεν υπάρχουν αξιολογήσεις ακόμα', 'profile.rating': 'Βαθμολογία', 'profile.skills.label': 'Δεξιότητες', 'profile.member_since': 'Μέλος από', 'task.offers': 'Προσφορές', 'task.offers.none': 'Δεν υπάρχουν ακόμα προσφορές', // Create task 'create.title': 'Δημοσίευση εργασίας', 'create.field.title': 'Τίτλος', 'create.field.description': 'Περιγραφή', 'create.field.category': 'Κατηγορία', 'create.field.category.select': 'Επιλέξτε...', 'create.field.location': 'Τοποθεσία', 'create.field.location.any': 'Οπουδήποτε', 'create.field.location.all': 'Ολόκληρη η πόλη', 'create.field.budget': 'Προϋπολογισμός (€)', 'create.field.deadline': 'Ημερομηνία έναρξης', 'create.field.budget_negotiable': 'Η τιμή είναι διαπραγματεύσιμη', 'create.field.time_slot': 'Χρόνος εκτέλεσης', 'create.field.time_slot.any': 'Οποιαδήποτε', 'create.field.time_slot.morning': 'Πρωινό (08:00–13:00)', 'create.field.time_slot.afternoon': 'Μεσημέρι (13:00–18:00)', 'create.field.time_slot.evening': 'Βράδυ (18:00–22:00)', 'create.field.time_slot.weekend': 'Σαββατοκύριακο', 'create.field.address': 'Διεύθυνση (προαιρετικά)', 'create.field.address.district': 'Συνοικία', 'create.field.address.street': 'Οδός', 'create.field.address.house': 'Αριθμός', 'create.field.confidential': 'Εμπιστευτική σημείωση', 'create.field.confidential.placeholder': 'Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...', 'create.field.confidential.hint': 'Δεν εμφανίζεται δημόσια', 'create.field.photos': 'Φωτογραφίες', 'create.field.photos.add': 'Προσθήκη φωτογραφίας', 'create.field.photos.uploading': 'Ανέβασμα...', 'task.budget_negotiable': 'Τιμή διαπραγματεύσιμη', 'task.time_slot': 'Χρόνος', 'task.confidential': 'Εμπιστευτική σημείωση', 'create.field.title.placeholder': 'π.χ. Καθαρισμός διαμερίσματος 80τμ', 'create.field.description.placeholder': 'Περίγραψε λεπτομερώς τι χρειάζεσαι...', 'create.field.location.placeholder': 'π.χ. Αθήνα, Κολωνάκι', 'create.field.budget.placeholder': 'π.χ. 100', 'create.submit': 'Δημοσίευση εργασίας', 'create.submitting': 'Δημοσίευση...', // Auth 'login.title': 'Καλωσόρισες', 'login.subtitle': 'Σύνδεση στο CanHelp', 'login.email': 'Email', 'login.password': 'Κωδικός', 'login.submit': 'Σύνδεση', 'login.submitting': 'Σύνδεση...', 'login.error': 'Λάθος email ή κωδικός', 'login.unverified.title': 'Επιβεβαιώστε το email σας', 'login.unverified.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.', 'login.unverified.resend': 'Αποστολή νέου email επαλήθευσης', 'login.unverified.sending': 'Αποστολή...', 'login.unverified.sent': '✓ Εστάλη — ελέγξτε τα εισερχόμενα', 'profile.email.verified': 'Email επαληθεύτηκε', 'profile.email.not_verified': 'Email δεν επαληθεύτηκε', 'login.no_account': 'Δεν έχεις λογαριασμό;', 'login.register_link': 'Εγγραφή', 'login.forgot_password': 'Ξέχασα τον κωδικό', 'login.or_continue_with': 'ή συνεχίστε με', 'login.continue_google': 'Σύνδεση με Google', 'forgot.title': 'Ξέχασα τον κωδικό', 'forgot.subtitle': 'Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης', 'forgot.email': 'Email', 'forgot.submit': 'Αποστολή', 'forgot.submitting': 'Αποστολή...', 'forgot.sent.title': 'Ελέγξτε τα εισερχόμενά σας', 'forgot.sent.desc': 'Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.', 'forgot.back_to_login': 'Επιστροφή στη σύνδεση', 'forgot.error': 'Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.', 'forgot.error.not_found': 'Δεν βρέθηκε λογαριασμός με αυτό το email.', 'forgot.error.send_failed': 'Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα', 'reset.title': 'Νέος κωδικός', 'reset.subtitle': 'Εισάγετε τον νέο σας κωδικό', 'reset.password': 'Νέος κωδικός', 'reset.confirm': 'Επιβεβαίωση κωδικού', 'reset.submit': 'Αλλαγή κωδικού', 'reset.submitting': 'Αποθήκευση...', 'reset.success': 'Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...', 'reset.back_to_login': 'Επιστροφή στη σύνδεση', 'reset.error.mismatch': 'Οι κωδικοί δεν ταιριάζουν', 'reset.error.invalid': 'Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.', 'register.title': 'Εγγραφή', 'register.subtitle': 'Δημιουργία λογαριασμού στο CanHelp', 'register.first_name': 'Όνομα', 'register.last_name': 'Επώνυμο', 'register.email': 'Email', 'register.password': 'Κωδικός (min 8 χαρακτήρες)', 'register.role': 'Ρόλος', 'register.role.customer': 'Χρήστης', 'register.role.customer.desc': 'Δημοσιεύω εργασίες', 'register.role.specialist': 'Ειδικός', 'register.role.specialist.desc': 'Αναλαμβάνω εργασίες', 'register.submit': 'Δημιουργία λογαριασμού', 'register.submitting': 'Εγγραφή...', 'register.has_account': 'Έχεις ήδη λογαριασμό;', 'register.login_link': 'Σύνδεση', 'register.continue_google': 'Εγγραφή με Google', 'register.check_email.title': 'Ελέγξτε το email σας', 'register.check_email.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.', 'register.check_email.login': 'Επιστροφή στη σύνδεση', // Dashboard 'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.new_task': '+ Νέα εργασία', 'dashboard.my_tasks': 'Οι εργασίες μου', 'dashboard.my_offers': 'Οι προσφορές μου', 'dashboard.invitations': 'Προσκλήσεις για εργασία', 'dashboard.offers_count': 'προσφορές', 'dashboard.declined_count': 'απορρίφθηκαν', 'dashboard.completed_tasks': 'Ολοκληρωμένες εργασίες', 'dashboard.completed_offers': 'Ολοκληρωμένες προσφορές', 'dashboard.review_pending': 'Η αξιολόγηση δεν έχει υποβληθεί ακόμα', 'tasks.new.top_specialists': 'Κορυφαίοι ειδικοί', 'tasks.new.select_category': 'Επιλέξτε κατηγορία για να δείτε ειδικούς', 'tasks.new.invite': 'Πρόσκληση', 'tasks.new.invited': 'Επιλέχθηκε ✓', 'reviews.count': 'αξιολογήσεις', 'filter.location': 'Τοποθεσία', 'filter.language': 'Γλώσσες', 'filter.language.any': 'Οποιαδήποτε γλώσσα', 'filter.category.all': 'Όλες οι κατηγορίες', 'user.categories': 'Κατηγορίες', 'user.work_area': 'Περιοχή εργασίας', 'dashboard.tasks.empty': 'Δεν έχεις δημοσιεύσει εργασίες', 'dashboard.tasks.empty.cta': 'Δημοσίευσε την πρώτη σου', 'dashboard.tasks.add_new': 'Πρόσθεσε νέα εργασία', 'dashboard.offers.empty': 'Δεν έχεις υποβάλλει προσφορές', 'dashboard.offers.empty.cta': 'Βρες εργασίες', 'dashboard.customer.specialists_title': 'Ψάχνεις εκτελεστή;', 'dashboard.customer.specialists_hint': 'Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου', 'dashboard.customer.specialists_cta': 'Βρες ειδικό', 'dashboard.customer.how_title': 'Πώς λειτουργεί', 'dashboard.customer.step1': 'Δημιούργησε εργασία με περιγραφή και προϋπολογισμό', 'dashboard.customer.step2': 'Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο', 'dashboard.customer.step3': 'Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία', // Notifications 'notif.title': 'Ειδοποιήσεις', 'notif.mark_all': 'Σήμανση όλων ως αναγνωσμένα', 'notif.empty': 'Δεν υπάρχουν ειδοποιήσεις', 'notif.type.new_offer': 'Νέα προσφορά', 'notif.type.offer_accepted': 'Η προσφορά σας έγινε δεκτή', 'notif.type.offer_declined': 'Η προσφορά σας απορρίφθηκε', 'notif.type.task_completed': 'Η εργασία ολοκληρώθηκε', 'notif.type.task_cancelled': 'Η εργασία ακυρώθηκε', 'notif.type.new_message': 'Νέο μήνυμα', 'notif.type.new_review': 'Νέα αξιολόγηση', 'notif.type.task_invite': 'Πρόσκληση σε εργασία', 'notif.body.new_offer': 'Νέα προσφορά για «{title}»', 'notif.body.offer_accepted': 'Η προσφορά σας για «{title}» έγινε δεκτή', 'notif.body.offer_declined': 'Η προσφορά σας για «{title}» απορρίφθηκε', 'notif.body.task_invite': 'Σας προσκαλούν για «{title}»', 'notif.body.new_review': 'Λάβατε αξιολόγηση {rating}★', // Offer status 'offer.status.pending': 'Εκκρεμεί', 'offer.status.accepted': 'Αποδεκτή', 'offer.status.declined': 'Απορρίφθηκε', 'offer.status.withdrawn': 'Αποσύρθηκε', 'offer.status.other_accepted': 'Επιλέχθηκε άλλος ειδικός', // Common 'common.loading': 'Φόρτωση...', 'common.error': 'Σφάλμα', 'common.save': 'Αποθήκευση', 'common.saving': 'Αποθήκευση...', 'common.cancel': 'Ακύρωση', 'common.add': 'Προσθήκη', 'common.close': 'Κλείσιμο', 'common.edit': 'Επεξεργασία', 'common.delete': 'Διαγραφή', 'common.from': 'από', 'common.currency': '€', 'common.greece': 'Ελλάδα', // Chat 'chat.connected': 'Συνδεδεμένος', 'chat.disconnected': 'Αποσυνδεδεμένος', 'chat.no_rooms': 'Δεν υπάρχουν συνομιλίες ακόμα', 'chat.task_fallback': 'Εργασία', 'chat.select': 'Επίλεξε συνομιλία', 'chat.no_messages': 'Δεν υπάρχουν μηνύματα', 'chat.placeholder': 'Γράψε μήνυμα... (Enter για αποστολή)', 'chat.conversation_fallback': 'Συνομιλία', 'chat.direct_chat': 'Απευθείας συνομιλία', 'chat.linked_task': 'Συνδεδεμένη εργασία', 'chat.write_btn': 'Μήνυμα', 'chat.just_now': 'μόλις τώρα', 'chat.min_ago': 'λ', 'chat.write_specialist': 'Γράψε στον ειδικό', 'chat.write_customer': 'Γράψε στον πελάτη', 'chat.notif_settings': 'Ρυθμίσεις ειδοποιήσεων', 'chat.notif_messages': 'Ειδοποιήσεις για νέα μηνύματα', 'chat.toast_title': 'Νέο μήνυμα', 'chat.toast_open': 'Άνοιγμα συνομιλίας', // Offer form 'offer.price': 'Τιμή', 'offer.price.placeholder': 'π.χ. 80', 'offer.customer_budget': 'Προϋπολογισμός πελάτη', 'offer.message': 'Μήνυμα', 'offer.optional': 'προαιρετικό', 'offer.message.placeholder': 'Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...', 'offer.submitting': 'Αποστολή...', // Profile 'profile.photo': 'Φωτογραφία προφίλ', 'profile.photo.change': 'Αλλαγή φωτογραφίας', 'profile.photo.hint': 'JPEG, PNG, WebP · έως 5MB', 'profile.basic_info': 'Βασικά στοιχεία', 'profile.phone': 'Τηλέφωνο', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Σύντομη περιγραφή', 'profile.bio.placeholder': 'Πες μας λίγα λόγια για εσένα...', 'profile.language': 'Γλώσσα', 'profile.language.hint': 'Γλώσσα διεπαφής και email ειδοποιήσεων', 'profile.languages': 'Γλώσσες επικοινωνίας', 'profile.languages.hint': 'Επιλέξτε όλες τις γλώσσες που μιλάτε', 'profile.skills': 'Δεξιότητες', 'profile.skills.subtitle': 'Προσθέσε τις υπηρεσίες που προσφέρεις', 'profile.skills.placeholder': 'π.χ. Καθαρισμός, IT, Μαθήματα...', 'profile.role': 'Ρόλος λογαριασμού', 'profile.role.specialist': '🔧 Ειδικός', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Χρήστης', 'profile.role.change': 'Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.', 'profile.become_specialist': 'Γίνε Ειδικός', 'profile.become_specialist.desc': 'Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.', 'become_specialist.hero.title': 'Κέρδισε χρήματα κάνοντας αυτό που ξέρεις', 'become_specialist.hero.subtitle': 'Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα', 'become_specialist.how.title': 'Πώς λειτουργεί', 'become_specialist.step1.title': 'Δημιούργησε κάρτα ειδικού', 'become_specialist.step1.desc': 'Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα', 'become_specialist.step2.title': 'Βρες εργασίες', 'become_specialist.step2.desc': 'Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα «Αναζήτηση εργασιών»', 'become_specialist.step3.title': 'Στείλε προσφορά & κέρδισε', 'become_specialist.step3.desc': 'Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες', 'become_specialist.benefits.title': 'Πλεονεκτήματα προφίλ ειδικού', 'become_specialist.benefit1': 'Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία', 'become_specialist.benefit2': 'Δημόσιο προφίλ με αξιολογήσεις πελατών', 'become_specialist.benefit3': 'Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες', 'become_specialist.benefit4': 'Προσθήκη σε αγαπημένα από πελάτες', 'become_specialist.cta': 'Περισσότερα', 'become_specialist.free_badge': 'Δωρεάν εγγραφή', 'profile.tab.notifications': 'Ειδοποιήσεις', 'profile.tab.reviews': 'Αξιολογήσεις', 'profile.tab.referral': 'Παραπομπές', 'profile.tab.auto_response': 'Αυτόματη απάντηση', 'profile.tab.site': 'Site', 'profile.site.title': 'Προσωπική σελίδα', 'profile.site.url_label': 'Προσωπικό site', 'profile.site.copy': 'Αντιγραφή', 'profile.site.copied': 'Αντιγράφηκε', 'profile.site.visible_title': 'Τι εμφανίζεται στη σελίδα σας', 'profile.site.visible.name': 'Όνομα και φωτογραφία', 'profile.site.visible.bio': 'Βιογραφικό', 'profile.site.visible.rating': 'Αξιολόγηση και κριτικές', 'profile.site.visible.portfolio': 'Χαρτοφυλάκιο / Κάρτες', 'profile.site.visible.contacts': 'Στοιχεία επικοινωνίας', 'profile.site.visible.full_last_name': 'Πλήρες επώνυμο', 'profile.site.visible.services': 'Κάρτες υπηρεσιών', 'profile.site.visible.reviews': 'Ενότητα κριτικών', 'profile.site.visible.status': 'Κατάσταση «Έτοιμος να βοηθήσω»', 'profile.site.theme': 'Θέμα εμφάνισης', 'profile.site.theme.dark': 'Σκοτεινό', 'profile.site.theme.light': 'Φωτεινό', 'profile.site.slug_taken': 'Αυτή η διεύθυνση είναι ήδη κατειλημμένη', 'profile.site.stats.title': 'Στατιστικά επισκεψιμότητας', 'profile.site.stats.days': 'τελευταίες 30 ημέρες', 'profile.site.stats.views': 'Προβολές', 'profile.site.stats.unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.messages': 'Μηνύματα', 'profile.site.stats.total_views': 'Συνολικές προβολές', 'profile.site.stats.total_unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.total_messages': 'Μηνύματα', 'profile.site.stats.empty': 'Δεν υπάρχουν δεδομένα ακόμη', 'profile.site.stats.loading': 'Φόρτωση στατιστικών...', 'profile.site.stats.no_slug': 'Ορίστε τη διεύθυνση του site για να δείτε στατιστικά', 'profile.site.edit_bio_hint': 'Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα «Βασικά».', 'status.can_help_now_hint': 'Η κάρτα σου εμφανίζεται ψηλότερα', 'status.need_help_hint': 'Οι ειδικοί μπορούν να σε βοηθήσουν', 'profile.referral.title': 'Πρόγραμμα παραπομπών', 'profile.referral.desc': 'Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.', 'profile.referral.link_label': 'Ο σύνδεσμος παραπομπής σου', 'profile.referral.copy': 'Αντιγραφή', 'profile.referral.copied': 'Αντιγράφηκε!', 'profile.referral.invited_count': 'επιτυχείς παραπομπές', 'profile.referral.no_code': 'Ο κωδικός παραπομπής δεν είναι διαθέσιμος.', 'notifications.title': 'Ρυθμίσεις ειδοποιήσεων', 'notifications.email.new_tasks': 'Email για νέες εργασίες', 'notifications.email.new_tasks.desc': 'Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου', 'notifications.messages.desc': 'Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα', 'notifications.saved': 'Ρυθμίσεις αποθηκεύτηκαν', 'notifications.plan_required': 'Συνδρομή απαιτείται για αυτή τη λειτουργία', 'profile.tab.info': 'Βασικά στοιχεία', 'profile.tab.finance': 'Οικονομικά', 'profile.tab.skills': 'Δεξιότητες', 'profile.tab.categories': 'Κατηγορίες', 'profile.tab.geography': 'Γεωγραφία', 'profile.specialist.categories': 'Κατηγορίες εργασιών', 'profile.specialist.categories.desc': 'Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι', 'profile.specialist.geography': 'Περιοχές κάλυψης', 'profile.specialist.geography.desc': 'Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι', 'profile.saving': 'Αποθήκευση...', 'profile.upload.error': 'Σφάλμα κατά την αναφόρτωση', 'profile.saved': 'Αποθηκεύτηκε', 'profile.tab.cards': 'Χαρτοφυλάκιο', 'profile.cards.count': 'Χαρτοφυλάκια', 'profile.cards.add': 'Νέο χαρτοφυλάκιο', 'profile.cards.new_title': 'Τίτλος νέου χαρτοφυλακίου', 'profile.cards.placeholder': 'π.χ. Υδραυλικά', 'profile.cards.create': 'Δημιουργία', 'profile.cards.cancel': 'Ακύρωση', 'profile.cards.empty': 'Δεν έχετε χαρτοφυλάκιο', 'profile.cards.create_first': 'Δημιουργήστε το πρώτο σας χαρτοφυλάκιο', 'profile.cards.delete_confirm': 'Διαγραφή χαρτοφυλακίου;', 'profile.card.tab.main': 'Γενικά', 'profile.card.tab.skills': 'Δεξιότητες', 'profile.card.tab.categories': 'Κατηγορίες', 'profile.card.tab.geography': 'Γεωγραφία', 'profile.card.tab.portfolio': 'Γκαλερί', 'profile.card.active': 'Ενεργή', 'profile.card.save': 'Αποθήκευση', 'profile.card.saved': 'Αποθηκεύτηκε', 'profile.card.delete': 'Διαγραφή', 'profile.card.skill.add': 'Προσθήκη δεξιότητας', 'profile.card.photo.add': 'Προσθήκη φωτογραφίας', 'profile.card.photo.uploading': 'Μεταφόρτωση...', 'profile.card.photo.empty': 'Δεν υπάρχουν φωτογραφίες', 'profile.card.item.title': 'Τίτλος', 'profile.card.item.desc': 'Περιγραφή', 'profile.card.item.save': 'Αποθήκευση', 'profile.card.item.cancel': 'Ακύρωση', 'profile.card.item.edit': 'Επεξεργασία', 'profile.upgrade.cards_limit': 'Όριο χαρτοφυλακίων εξαντλήθηκε', 'profile.upgrade.plan': 'Τρέχον πλάνο:', 'profile.upgrade.contact': 'Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου', 'profile.upgrade.ok': 'Εντάξει', 'profile.plan.title': 'Πλάνο συνδρομής', 'profile.balance': 'Υπόλοιπο', 'profile.balance.topup': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.amount': 'Ποσό (σε EUR)', 'profile.balance.topup.hint': 'Επιλέξτε ποσό ή εισαγάγετε μανούαλα', 'profile.balance.topup.submit': 'Πληρωμή', 'profile.balance.topup.loading': 'Ρεδιρεκτάρισμα...', 'profile.balance.topup.error': 'Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.', 'payment.success.title': 'Πληρωμή επιτυχής!', 'payment.success.desc': 'Το υπόλοιπό σας ενημερώθηκε.', 'payment.cancelled.title': 'Ακύρωση πληρωμής', 'payment.cancelled.desc': 'Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.', 'payment.pending.title': 'Σε εξέλιξη...', 'payment.pending.desc': 'Επεξεργαζόμαστε την πληρωμή σας.', 'payment.back_to_profile': 'Επιστροφή στο προφίλ', 'profile.plan.basic': 'Βασικό (δωρεάν)', 'profile.plan.contact_upgrade': 'Επικοινωνήστε με τον διαχειριστή για αναβάθμιση', 'profile.plan.cards_up_to': 'Χαρτοφυλάκια: έως', 'profile.plan.cards_unlimited': 'Χαρτοφυλάκια: απεριόριστα', 'profile.plan.tasks_up_to': 'Εργασίες: έως', 'profile.plan.offers_up_to': 'Προσφορές: έως', 'profile.plan.valid_until': 'Ισχύει έως', 'profile.plan.no_expiry': 'Δεν λήγει', // Create task 'create.error': 'Σφάλμα κατά τη δημοσίευση', // Tasks list extras 'tasks.category.general': 'Γενικά', 'tasks.budget.range': 'Εύρος:', 'tasks.budget.from': 'από', 'tasks.budget.to': 'έως', 'tasks.filter.reset': 'Εκκαθάριση φίλτρων', 'tasks.load_more': 'Φόρτωση ακόμα', 'tasks.showing': 'Αποτελέσματα:', 'tasks.field.budget': 'Προϋπολογισμός, €', // Admin 'admin.title': 'Πίνακας Διαχείρισης', 'admin.tab.stats': 'Στατιστικά', 'admin.tab.users': 'Χρήστες', 'admin.tab.tasks': 'Εργασίες', 'admin.tab.reports': 'Αναφορές', 'admin.stats.users': 'Χρήστες', 'admin.stats.tasks': 'Εργασίες', 'admin.stats.offers': 'Προσφορές', 'admin.stats.reviews': 'Αξιολογήσεις', 'admin.tasks.by_status': 'Εργασίες ανά κατάσταση', 'admin.col.user': 'Χρήστης', 'admin.col.email': 'Email', 'admin.col.role': 'Ρόλος', 'admin.col.registered': 'Εγγραφή', 'admin.col.status': 'Κατάσταση', 'admin.col.title': 'Τίτλος', 'admin.col.budget': 'Προϋπολογισμός', 'admin.col.created': 'Δημιουργία', 'admin.users.active': 'Ενεργός', 'admin.users.inactive': 'Ανενεργός', 'admin.users.deactivate': 'Απενεργοποίηση', 'admin.users.activate': 'Ενεργοποίηση', 'admin.tasks.cancel': 'Ακύρωση', 'admin.reports.none': 'Δεν υπάρχουν αναφορές', 'admin.reports.reviewed': 'Αναθεωρήθηκε', 'admin.reports.dismiss': 'Απόρριψη', 'admin.pagination.total': 'Σύνολο', 'admin.users.role.change': 'Αλλαγή ρόλου', 'admin.users.search.placeholder': 'Αναζήτηση ονόματος ή email...', 'admin.tasks.delete': 'Διαγραφή', 'admin.tasks.delete.confirm': 'Διαγραφή αυτής της εργασίας μόνιμα;', 'admin.tasks.search.placeholder': 'Αναζήτηση τίτλου...', 'admin.col.customer': 'Πελάτης', 'admin.col.reporter': 'Καταγγέλλων', 'admin.col.target': 'Στόχος', 'admin.filter.all_roles': 'Όλοι οι ρόλοι', 'admin.filter.all_statuses': 'Όλες οι καταστάσεις', 'admin.reports.target.task': 'Εργασία', 'admin.reports.target.user': 'Χρήστης', 'admin.tab.categories': 'Κατηγορίες', 'admin.tab.locations': 'Πόλεις & Περιοχές', 'admin.tab.logs': 'Αρχεία', 'admin.tab.plans': 'Πακέτα', 'admin.tab.settings': 'Ρυθμίσεις', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Δραστηριότητα', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Ειδοποιήσεις', 'admin.notif_logs.type': 'Τύπος', 'admin.notif_logs.title': 'Τίτλος', 'admin.notif_logs.read': 'Διαβασμένο', 'admin.notif_logs.empty': 'Δεν υπάρχουν αρχεία ειδοποιήσεων', 'admin.stats.notif_chart_title': 'Ειδοποιήσεις ανά ημέρα', 'admin.stats.notif_label': 'Ειδοποιήσεις', 'admin.stats.mail_chart_title': 'Emails ανά ημέρα', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Όλα', 'admin.stats.specialists': 'Ειδικοί', 'admin.col.plan': 'Πακέτο', 'admin.back_home': 'Αρχική', 'admin.plans.title': 'Πακέτα συνδρομής', 'admin.plans.add': '+ Νέο πακέτο', 'admin.plans.empty': 'Δεν υπάρχουν πακέτα', 'admin.plans.form.new': 'Νέο πακέτο', 'admin.plans.form.edit': 'Επεξεργασία πακέτου', 'admin.plans.form.name': 'Όνομα', 'admin.plans.form.price': 'Τιμή (EUR)', 'admin.plans.form.old_price': 'Παλιά τιμή (EUR, προαιρετικό)', 'admin.plans.form.max_offers': 'Μέγ. προσφορές (κενό = χωρίς όριο)', 'admin.plans.form.max_cards': 'Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)', 'admin.plans.form.duration_days': 'Διάρκεια (ημέρες, κενό = χωρίς λήξη)', 'admin.plans.form.description': 'Περιγραφή', 'admin.plans.form.features': 'Δυνατότητες (μία ανά γραμμή)', 'admin.plans.form.notify': 'Ειδοποιήσεις νέων εργασιών', 'admin.plans.form.default': 'Προεπιλογή', 'admin.plans.form.active': 'Ενεργό', 'admin.plans.form.order': 'Σειρά', 'admin.plans.form.role': 'Ρόλος', 'admin.plans.form.tier': 'Επίπεδο', 'admin.plans.form.role.customer': 'Πελάτης', 'admin.plans.form.role.specialist': 'Ειδικός', 'admin.plans.form.tier.free': 'Δωρεάν', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Όρια (κενό = χωρίς όριο)', 'admin.plans.form.max_messages_day': 'Μέγ. μηνύματα/ημέρα', 'admin.plans.form.max_orders_day': 'Μέγ. παραγγελίες/ημέρα', 'admin.plans.form.max_skills': 'Μέγ. δεξιότητες', 'admin.plans.form.max_profiles': 'Μέγ. προφίλ', 'admin.plans.form.max_portfolio': 'Μέγ. στοιχεία χαρτοφυλακίου', 'admin.plans.form.section.boost': 'Πολλαπλασιαστές & Ενίσχυση', 'admin.plans.form.search_boost': 'Ενίσχυση αναζήτησης', 'admin.plans.form.offers_multiplier': 'Πολλαπλασιαστής προσφορών', 'admin.plans.form.section.contact': 'Δικαιώματα επικοινωνίας', 'admin.plans.form.can_contact_free': 'Επικοινωνία με δωρεάν χρήστες', 'admin.plans.form.can_contact_pro': 'Επικοινωνία με Pro χρήστες', 'admin.plans.form.can_contact_all': 'Επικοινωνία με όλους', 'admin.plans.form.can_show_contact': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.plans.form.can_view_phone': 'Προβολή τηλεφώνου', 'admin.plans.form.section.features': 'Λειτουργίες', 'admin.plans.form.upload_video': 'Μεταφόρτωση βίντεο', 'admin.plans.form.favorites': 'Αγαπημένα', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Σήμα επαλήθευσης', 'admin.plans.form.highlighted_reviews': 'Προβεβλημένες κριτικές', 'admin.plans.form.personal_site': 'Προσωπική σελίδα', 'admin.plans.form.can_help_now': 'Κατάσταση «Μπορώ να βοηθήσω»', 'admin.plans.form.need_help': 'Κατάσταση «Χρειάζομαι βοήθεια»', 'admin.plans.form.auto_response': 'Αυτόματη απάντηση', 'admin.plans.form.auto_match': 'Αυτόματη αντιστοίχιση', 'admin.plans.form.instant_dispatch_free': 'Άμεση αποστολή (δωρεάν)', 'admin.plans.form.instant_dispatch_pro': 'Άμεση αποστολή (Pro)', 'admin.plans.badge.default': 'Προεπιλογή', 'admin.plans.badge.inactive': 'Ανενεργό', 'admin.plans.make_default': 'Ορισμός ως προεπιλογή', 'admin.plans.tasks': 'Εργασίες', 'admin.plans.offers': 'Προσφορές', 'admin.plans.cards': 'Χαρτοφυλάκιο', 'admin.plans.notify_tasks': 'Ειδοποιήσεις εργασιών', 'admin.plans.delete.confirm': 'Διαγραφή πακέτου', 'admin.activity.title': 'Αρχείο δραστηριότητας', 'admin.activity.event': 'Γεγονός', 'admin.activity.all_events': 'Όλα τα γεγονότα', 'admin.activity.from': 'Από', 'admin.activity.to': 'Έως', 'admin.activity.reset': 'Επαναφορά', 'admin.activity.total': 'Σύνολο', 'admin.activity.empty': 'Δεν υπάρχουν εγγραφές', 'admin.mail.event': 'Συμβάν email', 'admin.mail.all_events': 'Όλα τα email συμβάντα', 'admin.mail.from': 'Από', 'admin.mail.to': 'Έως', 'admin.mail.reset': 'Επαναφορά', 'admin.mail.total': 'Σύνολο', 'admin.mail.empty': 'Δεν υπάρχουν email logs', 'admin.mail.recipient': 'Παραλήπτης', 'admin.mail.provider': 'Πάροχος', 'admin.mail.details': 'Λεπτομέρειες', 'admin.mail.status': 'Κατάσταση', 'admin.mail.success': 'Επιτυχία', 'admin.mail.failed': 'Σφάλμα', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'Δεν υπάρχουν εγγραφές', 'admin.logs.date': 'Ημερομηνία', 'admin.logs.provider': 'Πάροχος', 'admin.logs.model': 'Μοντέλο', 'admin.logs.action': 'Ενέργεια', 'admin.logs.langs': 'Γλώσσες', 'admin.logs.in': 'Είσοδος', 'admin.logs.out': 'Έξοδος', 'admin.logs.total': 'Σύνολο', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Κατάσταση', 'admin.stats.activity_30d': 'Δραστηριότητα 30 ημερών', 'admin.stats.tasks_label': 'Εργασίες', 'admin.stats.users_label': 'Χρήστες', 'admin.stats.specialists_label': 'Ειδικοί', 'admin.stats.tokens_title': 'Χρήση tokens (ανά μήνα)', 'admin.stats.tokens_out': 'Εξερχόμενα', 'admin.stats.tokens_in': 'Εισερχόμενα', 'admin.stats.tokens_out_label': 'Εξερχόμενα tokens', 'admin.stats.tokens_in_label': 'Εισερχόμενα tokens', 'admin.stats.cost_label': 'Κόστος (USD)', 'admin.stats.tasks_by_status': 'Εργασίες ανά κατάσταση', 'admin.task_status.open': 'Ανοιχτές', 'admin.task_status.in_progress': 'Σε εξέλιξη', 'admin.task_status.completed': 'Ολοκληρωμένες', 'admin.task_status.cancelled': 'Ακυρωμένες', 'admin.task_status.draft': 'Προσχέδια', 'admin.settings.tab.general': 'Γενικά', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Ειδοποιήσεις', 'admin.settings.tab.payment': 'Πληρωμή', 'admin.settings.tab.referral': 'Παραπομπές', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Κοινωνικά δίκτυα', 'admin.settings.socials.title': 'Σύνδεσμοι κοινωνικών δικτύων', 'admin.settings.socials.hint': 'Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο', 'admin.settings.seo.maintenance_label': 'Λειτουργία συντήρησης', 'admin.settings.seo.maintenance_hint': 'Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες', 'admin.settings.seo.indexing_label': 'Ευρετηρίαση από μηχανές αναζήτησης', 'admin.settings.seo.indexing_hint': 'Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο', 'admin.settings.seo.head_scripts_label': 'Scripts στο (JS)', 'admin.settings.seo.head_scripts_hint': 'Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)', 'admin.settings.seo.site_title_label': 'Τίτλος ιστότοπου', 'admin.settings.seo.site_description_label': 'Περιγραφή ιστότοπου (meta description)', 'admin.settings.referral.title': 'Πρόγραμμα παραπομπών', 'admin.settings.referral.hint': 'Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.', 'admin.settings.referral.enabled_label': 'Ενεργό', 'admin.settings.referral.enabled_hint': 'Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών', 'admin.settings.referral.customer_section': 'Για πελάτες', 'admin.settings.referral.specialist_section': 'Για ειδικούς', 'admin.settings.referral.plan_label': 'Πλάνο ανταμοιβής', 'admin.settings.referral.no_plan': '— χωρίς πλάνο —', 'admin.settings.referral.plan_hint': 'Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.', 'admin.settings.referral.days_label': 'Ημέρες ανταμοιβής', 'admin.settings.referral.days_hint': 'Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.', 'admin.settings.general.title': 'Γενικές ρυθμίσεις', 'admin.settings.general.site_name': 'Όνομα ιστότοπου', 'admin.settings.general.site_url': 'URL ιστότοπου', 'admin.settings.general.contact_email': 'Email επικοινωνίας', 'admin.settings.general.support_phone': 'Τηλέφωνο υποστήριξης', 'admin.settings.smtp.title': 'Ρυθμίσεις SMTP', 'admin.settings.smtp.hint': 'Χρησιμοποιείται για αποστολή ειδοποιήσεων email.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Θύρα', 'admin.settings.smtp.encryption': 'Κρυπτογράφηση', 'admin.settings.smtp.enc.none': 'Χωρίς', 'admin.settings.smtp.enc.tls': 'STARTTLS (θύρα 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (θύρα 465)', 'admin.settings.smtp.username': 'Όνομα χρήστη', 'admin.settings.smtp.password': 'Κωδικός / App Password', 'admin.settings.smtp.from_name': 'Όνομα αποστολέα', 'admin.settings.smtp.from_email': 'Email αποστολέα', 'admin.settings.smtp.test': 'Αποστολή δοκιμαστικού email', 'admin.settings.smtp.sending': 'Αποστολή...', 'admin.settings.payment.hint': 'Τα στοιχεία για ePay Piraeus Bank.', 'admin.settings.env.test': 'Δοκιμαστικό (sandbox)', 'admin.settings.env.prod': 'Παραγωγή', 'admin.settings.env.label': 'Περιβάλλον', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Ενεργό', 'admin.settings.saving': 'Αποθήκευση...', 'admin.settings.saved': '✓ Αποθηκεύτηκε', 'admin.notif.vars_hint': 'Διαθέσιμες μεταβλητές στα πρότυπα', 'admin.notif.tmpl.not_set': 'Πρότυπο δεν έχει οριστεί', 'admin.notif.tmpl.subject_label': 'Θέμα email', 'admin.notif.tmpl.body_label': 'Κείμενο email (HTML)', 'admin.notif.tmpl.save': 'Αποθήκευση', 'admin.notif.tmpl.close': 'Κλείσιμο', 'admin.notif.tmpl.translate': 'Αυτόματη μετάφραση', 'admin.notif.tmpl.translating': 'Μετάφραση...', 'admin.notif.tmpl.saving': 'Αποθήκευση...', 'admin.notif.email_verification': 'Επαλήθευση email', 'admin.notif.registration_success': 'Επιτυχής εγγραφή', 'admin.notif.password_reset': 'Επαναφορά κωδικού', 'admin.notif.new_offer': 'Νέα προσφορά', 'admin.notif.new_task': 'Νέα εργασία', 'admin.notif.offer_accepted': 'Προσφορά αποδεκτή', 'admin.notif.new_message': 'Νέο μήνυμα', 'admin.notif.offer_declined': 'Απόρριψη προσφοράς', 'admin.notif.offer_other_accepted': 'Επιλέχθηκε άλλος ειδικός', 'admin.notif.task_updated': 'Ενημέρωση εργασίας', 'admin.notif.deadline_reminder': 'Υπενθύμιση προθεσμίας', 'admin.notif.task_archived': 'Αυτόματη απόσυρση εργασίας', 'admin.notif.referral_reward': 'Ανταμοιβή παραπομπής', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Τιμολόγιο — ενεργοποίηση πλάνου', 'admin.email_template.plan_upgraded': 'Τιμολόγιο — αναβάθμιση πλάνου', 'admin.email_template.plan_downgrade_scheduled': 'Τιμολόγιο — προγραμματισμένη υποβάθμιση', 'admin.email_template.plan_downgrade_applied': 'Τιμολόγιο — εφαρμογή υποβάθμισης', 'admin.email_template.plan_renewal_reminder': 'Τιμολόγιο — υπενθύμιση ανανέωσης', 'admin.email_template.plan_insufficient_funds': 'Τιμολόγιο — ανεπαρκές υπόλοιπο', // Pricing confirm modal 'pricing.confirm.title': 'Επιβεβαίωση επιλογής πλάνου', 'pricing.confirm.plan': 'Πλάνο', 'pricing.confirm.prorated': 'Αναλογική έκπτωση', 'pricing.confirm.effective_price': 'Προς πληρωμή', 'pricing.confirm.your_balance': 'Το υπόλοιπό σας', 'pricing.confirm.downgrade_info': 'Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.', 'pricing.confirm.insufficient': 'Ανεπαρκές υπόλοιπο.', 'pricing.confirm.top_up': 'Ανανέωση', 'pricing.confirm.schedule_downgrade': 'Προγραμματισμός μετάβασης', 'pricing.confirm.pay': 'Πληρωμή', 'admin.user_edit.title': 'Επεξεργασία χρήστη', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Διευθυνση email επαληθεύτηκε', 'admin.user_edit.email_not_verified': 'Email δεν έχει επαληθευτεί', 'admin.user_edit.verify_email_btn': 'Χειροκίνητη επαλήθευση', 'admin.user_edit.verify_email_done': 'Email επαληθεύτηκε!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Εγγραφή', 'admin.user_edit.last_seen': 'Τελευταία σύνδεση', 'admin.user_edit.lang': 'Γλώσσα', 'admin.user_edit.first_name': 'Όνομα', 'admin.user_edit.last_name': 'Επώνυμο', 'admin.user_edit.phone': 'Τηλέφωνο', 'admin.user_edit.bio': 'Βιογραφικό', 'admin.user_edit.role': 'Ρόλος', 'admin.user_edit.plan': 'Πακέτο', 'admin.user_edit.no_plan': '— Χωρίς πακέτο —', 'admin.user_edit.active': 'Ενεργός λογαριασμός', 'admin.user_edit.balance': 'Υπόλοιπο (EUR)', 'admin.user_edit.skills': 'Δεξιότητες', 'admin.user_edit.tab.profile': 'Προφίλ', 'admin.user_edit.tab.account': 'Λογαριασμός', 'admin.user_edit.tab.balance': 'Υπόλοιπο', 'admin.user_edit.tab.settings': 'Ρυθμίσεις', 'admin.user_edit.tab.specialist': 'Χαρτοφυλάκιο', 'admin.user_edit.tab.site': 'Ιστοσελίδα', 'admin.user_edit.plan_expires': 'Λήξη πλάνου', 'admin.user_edit.interface_lang': 'Γλώσσα διεπαφής', 'admin.user_edit.comm_languages': 'Γλώσσες επικοινωνίας', 'admin.user_edit.personal_site_slug': 'Προσωπική σελίδα', 'admin.user_edit.show_contact_info': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.user_edit.show_contact_info.hint': 'Ορατό στους πελάτες', 'admin.user_edit.notify_new_tasks': 'Ειδοποίηση για νέες εργασίες', 'admin.user_edit.notify_new_tasks.hint': 'Push και email ειδοποιήσεις', 'admin.user_edit.notif_messages': 'Ειδοποιήσεις μηνυμάτων', 'admin.user_edit.notif_messages.hint': 'Νέα μηνύματα στη συνομιλία', 'admin.user_edit.site_settings': 'Ρυθμίσεις προσωπικής σελίδας', 'admin.user_edit.categories': 'Κατηγορίες υπηρεσιών', 'admin.user_edit.locations': 'Περιοχές εξυπηρέτησης', 'admin.user_edit.skill_placeholder': 'Νέα δεξιότητα...', 'admin.user_edit.add_category': '— Επιλέξτε κατηγορία —', 'admin.user_edit.add_location': '— Επιλέξτε περιοχή —', 'admin.user_edit.specialist_cards': 'Χαρτοφυλάκιο ειδικού', 'admin.user_edit.no_cards': 'Δεν βρέθηκαν στοιχεία χαρτοφυλακίου', 'admin.user_edit.card_title': 'Τίτλος χαρτοφυλακίου', 'admin.user_edit.card_description': 'Περιγραφή', 'admin.balance.topup.btn': 'Αναπλήρωση', 'admin.balance.withdraw.btn': 'Αφαίρεση', 'admin.balance.modal_hint': 'Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό', 'admin.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'admin.balance.topup.amount': 'Ποσό', 'admin.balance.topup.description': 'Σχόλιο', 'admin.balance.topup.description.placeholder': 'Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση', 'admin.balance.topup.submit': 'Αναπλήρωση υπολοίπου', 'admin.balance.withdraw.title': 'Αφαίρεση υπολοίπου', 'admin.balance.withdraw.amount': 'Ποσό', 'admin.balance.withdraw.description': 'Σχόλιο', 'admin.balance.withdraw.description.placeholder': 'Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση', 'admin.balance.withdraw.submit': 'Αφαίρεση από το υπόλοιπο', 'admin.user_edit.role.customer': 'Πελάτης', 'admin.user_edit.role.specialist': 'Ειδικός', 'admin.user_edit.role.admin': 'Διαχειριστής', 'common.refresh': 'Ανανέωση', 'common.back_home': 'Αρχική', 'admin.loc.hint': 'Διαχείριση πόλεων και συνοικιών', 'admin.loc.add_city': 'Νέα πόλη', 'admin.loc.add_district': 'Προσθήκη συνοικίας', 'admin.loc.new': 'Νέα τοποθεσία', 'admin.loc.edit': 'Επεξεργασία τοποθεσίας', 'admin.loc.district': 'συνοικία', 'admin.loc.empty': 'Δεν υπάρχουν τοποθεσίες', 'admin.loc.delete.confirm': 'Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.', 'admin.cat.add_root': 'Νέα κατηγορία', 'admin.cat.add_sub': 'Υποκατηγορία', 'admin.cat.edit': 'Επεξεργασία', 'admin.cat.delete': 'Διαγραφή', 'admin.cat.delete.confirm': 'Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Εικονίδιο', 'admin.cat.name_el': 'Ελληνικά', 'admin.cat.name_en': 'Αγγλικά', 'admin.cat.name_ru': 'Ρωσικά', 'admin.cat.order': 'Σειρά', 'admin.cat.active': 'Ενεργή', 'admin.cat.parent': 'Γονική κατηγορία', 'admin.cat.no_parent': 'Κορυφαίο επίπεδο', 'admin.cat.save': 'Αποθήκευση', 'admin.cat.cancel': 'Ακύρωση', 'admin.cat.empty': 'Δεν υπάρχουν κατηγορίες', 'admin.cat.hint': 'Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία', 'admin.cat.new': 'Νέα κατηγορία', 'admin.cat.subcategory': 'υποκατηγορία', 'admin.cat.add_child': 'Προσθήκη υποκατηγορίας', 'admin.cat.inactive': 'Ανενεργή', 'admin.event.user_login': 'Σύνδεση', 'admin.event.user_register': 'Εγγραφή', 'admin.event.admin_user_deactivate': 'Αποκλεισμός χρήστη', 'admin.event.admin_user_activate': 'Ενεργοποίηση χρήστη', 'admin.event.admin_user_role_changed': 'Αλλαγή ρόλου', 'admin.event.admin_task_cancelled': 'Ακύρωση εργασίας', 'admin.event.admin_task_deleted': 'Διαγραφή εργασίας', 'admin.event.admin_report_reviewed': 'Αναφορά εξετάστηκε', 'admin.event.admin_report_dismissed': 'Αναφορά απορρίφθηκε', 'admin.event.task_created': 'Δημιουργία εργασίας', 'user.online': 'Σε σύνδεση', 'user.seen_minutes': 'ήταν εδώ πριν {n} λεπτά', 'user.seen_hours': 'ήταν εδώ πριν {n} ώρες', 'user.seen_yesterday': 'ήταν εδώ χθες', 'user.seen_days': 'ήταν εδώ πριν {n} μέρες', // Specialists 'specialists.title': 'Ειδικοί', 'specialists.search': 'Αναζήτηση ειδικού...', 'specialists.search.btn': 'Αναζήτηση', 'specialists.empty': 'Δεν βρέθηκαν ειδικοί', 'specialists.no_bio': 'Χωρίς περιγραφή', 'specialists.view': 'Προβολή προφίλ', 'specialists.reviews': 'αξιολογήσεις', 'specialist.favorite': 'Προσθήκη στα αγαπημένα', 'specialist.unfavorite': 'Αφαίρεση από αγαπημένα', 'specialist.site_link': 'Προσωπικό site', 'favorites.specialists.title': 'Αγαπημένοι ειδικοί', 'favorites.specialists.empty': 'Δεν έχετε αγαπημένους ειδικούς', 'nav.favorites': 'Αγαπημένα', 'nav.schedule': 'Πρόγραμμα', 'nav.find_tasks': 'Αναζήτηση εργασιών', 'schedule.title': 'Το πρόγραμμά μου', 'schedule.subtitle': 'Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας', 'schedule.available': 'Ελεύθερος', 'schedule.busy': 'Απασχολημένος', 'schedule.unset': 'Μη ορισμένο', 'schedule.click_hint': '← κλικ για εναλλαγή κατάστασης', 'schedule.range_mode': 'Επιλογή εύρους', 'schedule.range_from': 'Από {date} — επιλέξτε τελική ημερομηνία', 'schedule.click_to_set': 'Κλικ για ορισμό', 'schedule.free': 'ελεύθερα', 'schedule.busy_count': 'απασχολημένα', 'schedule.free_days': 'ελεύθερες ημέρες', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Σύνδεση με Google Calendar', 'schedule.disconnectGoogle': 'Αποσύνδεση', 'schedule.connectedAs': 'Συνδεδεμένο ως', 'schedule.importFromGoogle': 'Συγχρονισμός από Google', 'schedule.gcalConnected': '✓ Google Calendar συνδέθηκε', 'schedule.gcalError': 'Σφάλμα σύνδεσης Google Calendar', 'schedule.gcalImportDone': 'Εισήχθησαν {n} ημερ. από Google Calendar', 'schedule.gcalAutoSyncNote': 'Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar', 'schedule.gcalConnectDesc': 'Συνδέστε το Google Calendar για αυτόματο συγχρονισμό', 'schedule.gcalDisconnectConfirm': 'Αποσύνδεση Google Calendar;', 'find_tasks.title': 'Αναζήτηση εργασιών', 'find_tasks.for_me': 'Για μένα', 'find_tasks.all': 'Όλες οι εργασίες', 'find_tasks.by_category': 'Ανά κατηγορία', 'find_tasks.list': 'Λίστα', 'find_tasks.already_offered': 'Προσφορά υποβλήθηκε', 'find_tasks.offer_now': 'Υποβολή προσφοράς', 'find_tasks.empty_for_me': 'Δεν βρέθηκαν εργασίες στις κατηγορίες σας', 'find_tasks.banner_hint': 'Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας', 'find_tasks.no_cards': 'Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς', 'find_tasks.add_card': 'Δημιουργία χαρτοφυλακίου', 'find_tasks.search': 'Αναζήτηση εργασιών...', 'find_tasks.tasks_count': 'εργασίες', // Footer 'footer.tagline': 'Η πλατφόρμα εργασιών για την Ελλάδα', 'footer.rights': 'Όλα τα δικαιώματα διατηρούνται.', // App download section 'app.download_title': 'Κατεβάστε την εφαρμογή CanHelp', 'app.download_desc': 'Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.', // Nav 'nav.pricing': 'Τιμές', // Pricing page 'pricing.title': 'Τιμολόγηση', 'pricing.subtitle': 'Επιλέξτε το κατάλληλο πρόγραμμα', 'pricing.role.customer': 'Πελάτης', 'pricing.role.specialist': 'Ειδικός', 'pricing.free': 'Δωρεάν', 'pricing.per_month': 'μήνα', 'pricing.duration': 'Διάρκεια', 'pricing.days': 'ημ.', 'pricing.current_plan': 'Το πρόγραμμά σας', 'pricing.popular': 'Δημοφιλές', 'pricing.choose': 'Επιλογή', 'pricing.your_plan': 'Ενεργό πρόγραμμα', 'pricing.free_default': 'Προεπιλογή', 'pricing.compare': 'Σύγκριση λειτουργιών', 'pricing.feature': 'Λειτουργία', 'pricing.faq_note': 'Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.', 'pricing.feat.messages': 'Μηνύματα / ημέρα', 'pricing.feat.orders': 'Παραγγελίες / ημέρα', 'pricing.feat.contact_all': 'Επικοινωνία με όλους', 'pricing.feat.view_phone': 'Εμφάνιση τηλεφώνου', 'pricing.feat.show_contact': 'Εμφάνιση στοιχείων επαφής', 'pricing.feat.favorites': 'Αγαπημένα', 'pricing.feat.verified_badge': 'Επαληθευμένο badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Προσωπικό site', 'pricing.feat.auto_response': 'Αυτόματη απάντηση', 'pricing.feat.auto_match': 'Αυτόματη αντιστοίχιση', 'pricing.feat.highlighted_reviews': 'Επισημασμένες αξιολογήσεις', 'pricing.feat.portfolio': 'Στοιχεία χαρτοφυλακίου', 'pricing.feat.cards': 'Κάρτες ειδικού', 'pricing.feat.notify_tasks': 'Ειδοποιήσεις νέων εργασιών', 'pricing.feat.video': 'Βίντεο στο χαρτοφυλάκιο', // Upgrade prompt 'upgrade.available_in': 'Διαθέσιμο στο', 'upgrade.cta': 'Αναβάθμιση', // Dashboard plan block 'dashboard.plan.title': 'Το πρόγραμμά μου', 'dashboard.plan.expires': 'Λήγει σε {n} ημέρες', 'dashboard.plan.upgrade': 'Αναβάθμιση προγράμματος', 'dashboard.plan.no_plan': 'Δωρεάν πρόγραμμα', 'dashboard.plan.messages': 'Μηνύματα σήμερα', 'dashboard.plan.orders': 'Παραγγελίες σήμερα', 'dashboard.plan.limits': 'Ημερήσια όρια', 'dashboard.plan.features': 'Λειτουργίες', 'dashboard.plan.stats': 'Στατιστικά', 'dashboard.stats.cards': 'Χαρτοφυλάκια', 'dashboard.stats.maxCards': 'Μέγ. χαρτοφυλάκια', 'dashboard.stats.portfolioItems': 'Στοιχεία portfolio', 'dashboard.stats.maxPortfolioItems': 'Μέγ. στοιχεία', 'dashboard.stats.activeOffers': 'Ενεργές προσφορές', 'dashboard.stats.reviewsReceived': 'Αξιολογήσεις', 'dashboard.stats.activeTasks': 'Ενεργές εργασίες', 'dashboard.stats.completedTasks': 'Ολοκληρωμένες', 'status.can_help_now': 'Είμαι διαθέσιμος τώρα', 'status.need_help': 'Χρειάζομαι βοήθεια', 'status.active': 'Ενεργό', 'status.toggle_on': 'Ενεργοποίηση', 'status.toggle_off': 'Απενεργοποίηση', // FOMO 'fomo.missed_orders': 'Χάσατε {n} παραγγελίες', 'fomo.missed_value': 'Αξία €{v}', 'fomo.upgrade_hint': 'Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες', 'fomo.conversion': 'Μετατροπές εργασιών', 'fomo.active': 'Ενεργές', 'fomo.with_offers': 'Με προσφορές', 'fomo.completed': 'Ολοκληρωμένες', 'fomo.already_offered': '{n} ειδικοί έχουν ήδη απαντήσει', 'fomo.specialist_missed': 'Χάσατε {n} παραγγελίες', 'fomo.top_categories': 'Κατηγορίες', 'fomo.offers_received': 'προσφορές ελήφθησαν', 'fomo.avg_offers': 'Μέσο {n}/εργασία', 'fomo.completion_rate': 'ολοκληρωμένες', // Task auto-match 'task.auto_match': 'Αυτόματη αντιστοίχιση', 'task.auto_match_results': 'Κορυφαίοι ειδικοί', 'task.no_offer_yet': 'Δεν έχετε στείλει προσφορά ακόμα', 'task.make_offer': 'Αποστολή προσφοράς', 'auto_response.title': 'Αυτόματη Απάντηση', 'auto_response.enabled': 'Ενεργοποίηση αυτόματης απάντησης', 'auto_response.min_budget': 'Ελάχ. προϋπολογισμός', 'auto_response.max_budget': 'Μέγ. προϋπολογισμός', 'auto_response.default_price': 'Προεπιλεγμένη τιμή', 'auto_response.default_message': 'Προεπιλεγμένο μήνυμα', 'auto_response.max_per_day': 'Μέγ. αυτόματες προσφορές/ημέρα', 'auto_response.save': 'Αποθήκευση', 'auto_response.saved': 'Αποθηκεύτηκε', 'auto_response.categories': 'Κατηγορίες', 'auto_response.locations': 'Τοποθεσίες', // Personal site 'profile.personal_site': 'Προσωπικό Site', 'profile.site_slug': 'Slug URL', 'profile.site_slug_hint': 'Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _', 'profile.site_open': 'Άνοιγμα site', 'profile.site_preview': 'Το site σας', 'profile.show_contact': 'Εμφάνιση στοιχείων επαφής', 'profile.show_contact_hint': 'Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας', // Google Calendar plan gate 'gcal.upgrade_required': 'Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα', // Chat limits 'chat.limit_warning': 'Απομένουν {n} μηνύματα σήμερα', 'chat.limit_reached': 'Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας', 'chat.upgrade': 'Αναβάθμιση', // Site page 'site.member_since': 'Μαζί μας από', 'site.rating': 'Βαθμολογία', 'site.completed_tasks': 'Ολοκληρώθηκαν', 'site.languages': 'Γλώσσες', 'site.photos': 'φωτ.', 'site.contact_form': 'Επικοινωνία', 'site.contact_sent': 'Το μήνυμα στάλθηκε!', 'site.contact_sent_desc': 'Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα', 'site.contact_name': 'Όνομα', 'site.contact_name_ph': 'Το όνομά σας', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Μήνυμα', 'site.contact_message_ph': 'Περιγράψτε την εργασία σας...', 'site.contact_send': 'Αποστολή', 'site.share': 'Κοινοποίηση', 'site.speaks_languages': 'Μιλάει', 'site.message_sent': 'Το μήνυμα εστάλη!', 'site.message_sent_desc': 'Ο ειδικός θα το λάβει στη συνομιλία', 'site.message_placeholder': 'Γράψτε το μήνυμά σας...', 'site.write_to_chat': 'Γράψτε στο chat', 'site.auth_required_title': 'Απαιτείται σύνδεση', 'site.auth_required_desc': 'Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.', 'site.auth_login_btn': 'Σύνδεση', 'site.auth_contact_form_btn': 'Επικοινωνία μέσω φόρμας', 'specialist.services': 'Υπηρεσίες', 'portfolio.title': 'Χαρτοφυλάκιο', 'common.not_found': 'Η σελίδα δεν βρέθηκε', 'common.anonymous': 'Ανώνυμα', 'specialist_setup.page_title': 'Ρύθμιση προφίλ ειδικού', 'specialist_setup.step_of': 'Βήμα {current} από {total}', 'specialist_setup.next': 'Επόμενο', 'specialist_setup.back': 'Πίσω', 'specialist_setup.skip': 'Παράλειψη', 'specialist_setup.finish': 'Ολοκλήρωση', 'specialist_setup.go_to_profile': 'Μεταβείτε στο προφίλ', 'specialist_setup.browse_tasks': 'Εξερεύνηση εργασιών', 'specialist_setup.step1.title': 'Καλωσήλθατε!', 'specialist_setup.step1.subtitle': 'Ας ρυθμίσουμε το προφίλ σας', 'specialist_setup.step1.desc': 'Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.', 'specialist_setup.step1.what_next': 'Τι θα κάνουμε:', 'specialist_setup.step1.item1': 'Συμπλήρωση βασικών πληροφοριών', 'specialist_setup.step1.item2': 'Δημιουργία κάρτας υπηρεσίας', 'specialist_setup.step1.item3': 'Προσθήκη δεξιοτήτων και κατηγοριών', 'specialist_setup.step1.item4': 'Επιλογή γεωγραφικής περιοχής', 'specialist_setup.step1.item5': 'Μεταφόρτωση φωτογραφιών χαρτοφυλακίου', 'specialist_setup.step2.title': 'Βασικό προφίλ', 'specialist_setup.step2.subtitle': 'Πείτε μας για σας', 'specialist_setup.step2.bio_label': 'Σχετικά με εμένα', 'specialist_setup.step2.bio_placeholder': 'Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...', 'specialist_setup.step2.phone_label': 'Τηλέφωνο', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Φωτογραφία προφίλ', 'specialist_setup.step2.photo_btn': 'Μεταφόρτωση φωτογραφίας', 'specialist_setup.step2.photo_uploading': 'Μεταφόρτωση...', 'specialist_setup.step2.photo_hint': 'Εμφανίζεται στο προφίλ σας', 'specialist_setup.step3.title': 'Κάρτα υπηρεσίας', 'specialist_setup.step3.subtitle': 'Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας', 'specialist_setup.step3.title_label': 'Τίτλος κάρτας', 'specialist_setup.step3.title_placeholder': 'Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...', 'specialist_setup.step3.desc_label': 'Περιγραφή', 'specialist_setup.step3.desc_placeholder': 'Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...', 'specialist_setup.step3.title_required': 'Απαιτείται τίτλος', 'specialist_setup.step4.title': 'Δεξιότητες & Κατηγορίες', 'specialist_setup.step4.subtitle': 'Προσθέστε δεξιότητες και επιλέξτε κατηγορίες', 'specialist_setup.step4.skills_label': 'Δεξιότητες', 'specialist_setup.step4.skills_placeholder': 'Π.χ. Εγκατάσταση σωληνώσεων...', 'specialist_setup.step4.skills_add': 'Προσθήκη', 'specialist_setup.step4.categories_label': 'Κατηγορίες', 'specialist_setup.step5.title': 'Γεωγραφική περιοχή', 'specialist_setup.step5.subtitle': 'Πού παρέχετε υπηρεσίες;', 'specialist_setup.step5.hint': 'Επιλέξτε πόλεις ή συγκεκριμένες περιοχές', 'specialist_setup.done.title': 'Το προφίλ σας είναι έτοιμο!', 'specialist_setup.done.subtitle': 'Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί', 'specialist_setup.done.desc': 'Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας.' }, en: { 'footer.slogan': 'Your task — our care! We solve any issue quickly and easily.', 'footer.links': 'Links', 'footer.socials': 'Socials', 'nav.home': 'Home', 'nav.tasks': 'Tasks', 'nav.post': '+ Post task', 'nav.dashboard': 'Dashboard', 'nav.chat': 'Messages', 'nav.notifications': 'Notifications', 'nav.profile': 'Profile', 'nav.admin': 'Admin Panel', 'nav.specialists': 'Specialists', 'nav.new_task': 'New task', 'nav.login': 'Login', 'nav.register': 'Register', 'nav.logout': 'Logout', 'hero.title': 'Find a specialist for any job', 'hero.subtitle': 'Post a task, receive offers and choose the best professional', 'hero.cta.post': 'Post a task', 'hero.cta.browse': 'Become a specialist', 'hero.search.placeholder': 'What do you need? e.g. electrician, cleaning...', 'stats.specialists': 'specialists', 'stats.tasks': 'tasks', 'stats.categories': 'categories', 'stats.free': 'free sign-up', 'section.categories': 'Create a task in any category', 'section.how': 'How it works', 'section.recent': 'Recent tasks', 'section.all': 'See all →', 'section.more': 'more', 'section.cities': 'Cities & Districts', 'section.community': 'A community project for everyone', 'community.subtitle': 'CanHelp is not just a marketplace — it\'s a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.', 'community.point1.title': 'Are you good at something?', 'community.point1.desc': 'Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.', 'community.point2.title': 'Need help with something?', 'community.point2.desc': 'Post a task in under a minute and receive offers from verified specialists in your city.', 'community.point3.title': 'Help the project grow', 'community.point3.desc': 'CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.', 'community.share': 'Share with friends', 'community.share.copied': 'Link copied!', // Referral section on home page 'section.referral': 'Referral Program', 'referral.home.subtitle': 'Share your link — every new user who signs up through it earns you a reward.', 'referral.home.step1.title': 'Sign up and get your link', 'referral.home.step1.desc': 'Create an account and find your unique referral link in your profile.', 'referral.home.step2.title': 'Share with friends', 'referral.home.step2.desc': 'Send the link to friends, acquaintances, or post it on social media.', 'referral.home.step3.title': 'Earn rewards', 'referral.home.step3.desc': 'Once your friend verifies their email, you automatically receive your reward.', 'referral.home.cta': 'Get your link', 'referral.home.badge': 'Referral Program', // FAQ section 'section.faq': 'Frequently Asked Questions', 'faq.q1': 'How does CanHelp work?', 'faq.a1': 'Post a task, receive offers from specialists, choose the best one and start working together. It\'s fast, simple and free for customers.', 'faq.q2': 'How much does it cost to use the platform?', 'faq.a2': 'Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.', 'faq.q3': 'How can I become a specialist?', 'faq.a3': 'Register, go to «Become a Specialist», fill in your profile with skills and categories, and start receiving tasks.', 'faq.q4': 'How do I choose the right specialist?', 'faq.a4': 'Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.', 'faq.q5': 'What if I am not satisfied?', 'faq.a5': 'You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.', 'faq.q6': 'Can I contact a specialist before accepting their offer?', 'faq.a6': 'Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.', 'faq.q7': 'How long does it take to receive offers?', 'faq.a7': 'Usually within a few hours. Specialists get notified about new tasks and can respond quickly.', 'faq.q8': 'Can I post a task in any city in Greece?', 'faq.a8': 'Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.', 'faq.q9': 'What types of tasks can I find on CanHelp?', 'faq.a9': 'Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.', 'faq.q10': 'Is there a mobile app?', 'faq.a10': 'Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.', 'how.step1.title': 'Post a task', 'how.step1.desc': 'Describe what you need and set your budget', 'how.step2.title': 'Receive offers', 'how.step2.desc': 'Specialists will send you offers with price and timeline', 'how.step3.title': 'Choose & start', 'how.step3.desc': 'Pick the best professional and start the collaboration', 'tasks.title': 'tasks', 'tasks.filters': 'Filters', 'tasks.search': 'Search', 'tasks.search.placeholder': 'Title or keyword...', 'tasks.search.btn': 'Search', 'tasks.publish': 'Post', 'tasks.category.all': 'All', 'tasks.category.all_in': 'All in', 'tasks.category.label': 'Category', 'tasks.location.label': 'City', 'tasks.location.placeholder': 'e.g. Athens', 'tasks.empty': 'No tasks found', 'tasks.empty.cta': 'Post the first one', 'task.status.open': 'Open', 'task.status.in_progress': 'In progress', 'task.status.completed': 'Completed', 'task.status.cancelled': 'Cancelled', 'task.status.draft': 'Draft', 'task.budget': 'Budget', 'task.location': 'Location', 'task.deadline': 'Start date', 'task.created_at': 'Created', 'task.customer': 'Customer', 'task.offer.btn': 'Submit offer', 'task.invite.banner_title': "You've been invited to this task", 'task.invite.banner_hint': 'The customer personally invited you', 'task.invite.accept': 'Send offer', 'task.invite.decline': 'Decline', 'offer.accept': 'Accept', 'offer.decline': 'Decline', 'task.complete': 'Complete task', 'task.complete.confirm': 'Mark this task as complete?', 'task.edit': 'Edit', 'task.status_label': 'Status', 'task.yours': 'Your task', 'task.offer.yours': 'Your offer', 'review.leave': 'Leave a review', 'review.rating': 'Rating', 'review.comment': 'Comment', 'review.comment.placeholder': 'Tell us about your experience...', 'review.submit': 'Submit review', 'review.submitting': 'Submitting...', 'review.done': 'Review submitted!', 'profile.reviews': 'Reviews', 'profile.no_reviews': 'No reviews yet', 'profile.rating': 'Rating', 'profile.skills.label': 'Skills', 'profile.member_since': 'Member since', 'task.offers': 'Offers', 'task.offers.none': 'No offers yet', 'create.title': 'Post a task', 'create.field.title': 'Title', 'create.field.description': 'Description', 'create.field.category': 'Category', 'create.field.category.select': 'Select...', 'create.field.location': 'Location', 'create.field.location.any': 'Anywhere', 'create.field.location.all': 'Entire city', 'create.field.budget': 'Budget (€)', 'create.field.deadline': 'Start date', 'create.field.budget_negotiable': 'Price is negotiable', 'create.field.time_slot': 'Time slot', 'create.field.time_slot.any': 'Anytime', 'create.field.time_slot.morning': 'Morning (08:00–13:00)', 'create.field.time_slot.afternoon': 'Afternoon (13:00–18:00)', 'create.field.time_slot.evening': 'Evening (18:00–22:00)', 'create.field.time_slot.weekend': 'Weekend', 'create.field.address': 'Address (optional)', 'create.field.address.district': 'District', 'create.field.address.street': 'Street', 'create.field.address.house': 'Number', 'create.field.confidential': 'Confidential note', 'create.field.confidential.placeholder': 'Details visible only to the assigned specialist...', 'create.field.confidential.hint': 'Not shown publicly', 'create.field.photos': 'Photos', 'create.field.photos.add': 'Add photo', 'create.field.photos.uploading': 'Uploading...', 'task.budget_negotiable': 'Price negotiable', 'task.time_slot': 'Time slot', 'task.confidential': 'Confidential note', 'create.field.title.placeholder': 'e.g. Clean 80sqm apartment', 'create.field.description.placeholder': 'Describe in detail what you need...', 'create.field.location.placeholder': 'e.g. Athens, Kolonaki', 'create.field.budget.placeholder': 'e.g. 100', 'create.submit': 'Post task', 'create.submitting': 'Posting...', 'login.title': 'Welcome back', 'login.subtitle': 'Sign in to CanHelp', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.submitting': 'Signing in...', 'login.error': 'Invalid email or password', 'login.unverified.title': 'Verify your email address', 'login.unverified.desc': 'We sent a verification link to your email. Check your inbox (or spam) and click the link.', 'login.unverified.resend': 'Resend verification email', 'login.unverified.sending': 'Sending...', 'login.unverified.sent': '✓ Sent — check your inbox', 'profile.email.verified': 'Email verified', 'profile.email.not_verified': 'Email not verified', 'login.no_account': "Don't have an account?", 'login.register_link': 'Register', 'login.forgot_password': 'Forgot password?', 'login.or_continue_with': 'or continue with', 'login.continue_google': 'Continue with Google', 'forgot.title': 'Forgot password', 'forgot.subtitle': 'Enter your email to receive a reset link', 'forgot.email': 'Email', 'forgot.submit': 'Send reset link', 'forgot.submitting': 'Sending...', 'forgot.sent.title': 'Check your inbox', 'forgot.sent.desc': 'If an account exists with that email, we\'ll send you a password reset link.', 'forgot.back_to_login': 'Back to sign in', 'forgot.error': 'Could not send reset link. Check the email address and try again.', 'forgot.error.not_found': 'No account found with this email address.', 'forgot.error.send_failed': 'Failed to send email. Please try again later.', 'reset.title': 'New password', 'reset.subtitle': 'Enter your new password', 'reset.password': 'New password', 'reset.confirm': 'Confirm password', 'reset.submit': 'Change password', 'reset.submitting': 'Saving...', 'reset.success': 'Password changed successfully. Redirecting to sign in...', 'reset.back_to_login': 'Back to sign in', 'reset.error.mismatch': 'Passwords do not match', 'reset.error.invalid': 'Invalid or expired link. Please request a new one.', 'register.title': 'Register', 'register.subtitle': 'Create a CanHelp account', 'register.first_name': 'First name', 'register.last_name': 'Last name', 'register.email': 'Email', 'register.password': 'Password (min 8 characters)', 'register.role': 'Role', 'register.role.customer': 'User', 'register.role.customer.desc': 'I post tasks', 'register.role.specialist': 'Specialist', 'register.role.specialist.desc': 'I take on tasks', 'register.submit': 'Create account', 'register.submitting': 'Registering...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Sign in', 'register.continue_google': 'Continue with Google', 'register.check_email.title': 'Check your email', 'register.check_email.desc': 'We sent a verification link to your email address. Check your inbox (or spam) and click the link.', 'register.check_email.login': 'Back to sign in', 'dashboard.title': 'Dashboard', 'dashboard.new_task': '+ New task', 'dashboard.my_tasks': 'My tasks', 'dashboard.my_offers': 'My offers', 'dashboard.invitations': 'Job invitations', 'dashboard.offers_count': 'offers', 'dashboard.declined_count': 'declined', 'dashboard.completed_tasks': 'Completed tasks', 'dashboard.completed_offers': 'Completed offers', 'dashboard.review_pending': 'Review not yet submitted', 'tasks.new.top_specialists': 'Top specialists', 'tasks.new.select_category': 'Select a category to see matching specialists', 'tasks.new.invite': 'Offer work', 'tasks.new.invited': 'Selected ✓', 'reviews.count': 'reviews', 'filter.location': 'Location', 'filter.language': 'Languages', 'filter.language.any': 'Any language', 'filter.category.all': 'All categories', 'user.categories': 'Categories', 'user.work_area': 'Work area', 'dashboard.tasks.empty': "You haven't posted any tasks", 'dashboard.tasks.empty.cta': 'Post your first one', 'dashboard.tasks.add_new': 'Add a new task', 'dashboard.offers.empty': "You haven't submitted any offers", 'dashboard.offers.empty.cta': 'Find tasks', 'dashboard.customer.specialists_title': 'Looking for a specialist?', 'dashboard.customer.specialists_hint': 'Browse specialist profiles, read reviews and invite them to your tasks', 'dashboard.customer.specialists_cta': 'Find a specialist', 'dashboard.customer.how_title': 'How it works', 'dashboard.customer.step1': 'Create a task with a description and budget', 'dashboard.customer.step2': 'Specialists will send offers with price and timeline', 'dashboard.customer.step3': 'Choose the right one and start working', 'notif.title': 'Notifications', 'notif.mark_all': 'Mark all as read', 'notif.empty': 'No notifications', 'notif.type.new_offer': 'New offer', 'notif.type.offer_accepted': 'Your offer was accepted', 'notif.type.offer_declined': 'Your offer was declined', 'notif.type.task_completed': 'Task completed', 'notif.type.task_cancelled': 'Task cancelled', 'notif.type.new_message': 'New message', 'notif.type.new_review': 'New review', 'notif.type.task_invite': 'Job invitation', 'notif.body.new_offer': 'New offer for «{title}»', 'notif.body.offer_accepted': 'Your offer for «{title}» was accepted', 'notif.body.offer_declined': 'Your offer for «{title}» was declined', 'notif.body.task_invite': 'You\'ve been invited for «{title}»', 'notif.body.new_review': 'You received a {rating}★ review', 'offer.status.pending': 'Pending', 'offer.status.accepted': 'Accepted', 'offer.status.declined': 'Declined', 'offer.status.withdrawn': 'Withdrawn', 'offer.status.other_accepted': 'Another specialist was chosen', 'common.loading': 'Loading...', 'common.error': 'Error', 'common.save': 'Save', 'common.saving': 'Saving...', 'common.cancel': 'Cancel', 'common.add': 'Add', 'common.close': 'Close', 'common.edit': 'Edit', 'common.delete': 'Delete', 'common.from': 'by', 'common.currency': '€', 'common.greece': 'Greece', // Chat 'chat.connected': 'Connected', 'chat.disconnected': 'Disconnected', 'chat.no_rooms': 'No conversations yet', 'chat.task_fallback': 'Task', 'chat.select': 'Select a conversation', 'chat.no_messages': 'No messages yet', 'chat.placeholder': 'Write a message... (Enter to send)', 'chat.conversation_fallback': 'Conversation', 'chat.direct_chat': 'Direct chat', 'chat.linked_task': 'Linked task', 'chat.write_btn': 'Message', 'chat.just_now': 'just now', 'chat.min_ago': 'm', 'chat.write_specialist': 'Write to specialist', 'chat.write_customer': 'Write to customer', 'chat.notif_settings': 'Notification settings', 'chat.notif_messages': 'Notifications for new messages', 'chat.toast_title': 'New message', 'chat.toast_open': 'Open chat', // Offer form 'offer.price': 'Price', 'offer.price.placeholder': 'e.g. 80', 'offer.customer_budget': 'Client budget', 'offer.message': 'Message', 'offer.optional': 'optional', 'offer.message.placeholder': 'Introduce yourself, your experience and why you are the best choice...', 'offer.submitting': 'Sending...', // Profile 'profile.photo': 'Profile photo', 'profile.photo.change': 'Change photo', 'profile.photo.hint': 'JPEG, PNG, WebP · up to 5MB', 'profile.basic_info': 'Basic info', 'profile.phone': 'Phone', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Short bio', 'profile.bio.placeholder': 'Tell us a bit about yourself...', 'profile.language': 'Language', 'profile.language.hint': 'App interface and email notification language', 'profile.languages': 'Languages spoken', 'profile.languages.hint': 'Select all languages you speak', 'profile.skills': 'Skills', 'profile.skills.subtitle': 'Add the services you offer', 'profile.skills.placeholder': 'e.g. Cleaning, IT, Tutoring...', 'profile.role': 'Account role', 'profile.role.specialist': '🔧 Specialist', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 User', 'profile.role.change': 'To change your role please contact support.', 'profile.become_specialist': 'Become a Specialist', 'profile.become_specialist.desc': 'Upgrade to Specialist to take on tasks and build your profile.', 'become_specialist.hero.title': 'Earn money doing what you do best', 'become_specialist.hero.subtitle': 'Create a specialist profile and receive orders from clients across Greece', 'become_specialist.how.title': 'How it works', 'become_specialist.step1.title': 'Create a specialist portfolio', 'become_specialist.step1.desc': 'Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks', 'become_specialist.step2.title': 'Find tasks', 'become_specialist.step2.desc': 'Discover tasks in your categories in the "Find Orders" section', 'become_specialist.step3.title': 'Send an offer & earn', 'become_specialist.step3.desc': 'Submit offers with price and timeline, chat with clients and complete tasks', 'become_specialist.benefits.title': 'Specialist profile advantages', 'become_specialist.benefit1': 'Task search filtered by your categories and location', 'become_specialist.benefit2': 'Public profile with client reviews', 'become_specialist.benefit3': 'Availability schedule visible to clients', 'become_specialist.benefit4': 'Saved to favourites by clients', 'become_specialist.cta': 'Learn more', 'become_specialist.free_badge': 'Free registration', 'profile.tab.notifications': 'Notifications', 'profile.tab.reviews': 'Reviews', 'profile.tab.referral': 'Referrals', 'profile.tab.auto_response': 'Auto-response', 'profile.tab.site': 'Site', 'profile.site.title': 'Personal page', 'profile.site.url_label': 'Personal site', 'profile.site.copy': 'Copy', 'profile.site.copied': 'Copied', 'profile.site.visible_title': "What's on your page", 'profile.site.visible.name': 'Name and photo', 'profile.site.visible.bio': 'Bio', 'profile.site.visible.rating': 'Rating and reviews', 'profile.site.visible.portfolio': 'Portfolio / Cards', 'profile.site.visible.contacts': 'Contact info', 'profile.site.visible.full_last_name': 'Full last name', 'profile.site.visible.services': 'Service cards', 'profile.site.visible.reviews': 'Reviews section', 'profile.site.visible.status': '"Ready to help" status', 'profile.site.theme': 'Appearance theme', 'profile.site.theme.dark': 'Dark', 'profile.site.theme.light': 'Light', 'profile.site.slug_taken': 'This address is already taken', 'profile.site.stats.title': 'Site analytics', 'profile.site.stats.days': 'last 30 days', 'profile.site.stats.views': 'Views', 'profile.site.stats.unique': 'Unique visitors', 'profile.site.stats.messages': 'Messages', 'profile.site.stats.total_views': 'Total views', 'profile.site.stats.total_unique': 'Unique visitors', 'profile.site.stats.total_messages': 'Messages', 'profile.site.stats.empty': 'No data yet', 'profile.site.stats.loading': 'Loading analytics...', 'profile.site.stats.no_slug': 'Set your site URL to see analytics', 'profile.site.edit_bio_hint': 'Bio and photo are edited in the "Basic info" tab.', 'status.title': 'Status', 'status.can_help_now_hint': 'Your card is shown higher in search', 'status.need_help_hint': 'Specialists can offer you help', 'profile.referral.title': 'Referral program', 'profile.referral.desc': 'Share your link and earn rewards for every new user you invite.', 'profile.referral.link_label': 'Your referral link', 'profile.referral.copy': 'Copy', 'profile.referral.copied': 'Copied!', 'profile.referral.invited_count': 'successful referrals', 'profile.referral.no_code': 'Referral code is not available.', 'notifications.title': 'Notification settings', 'notifications.email.new_tasks': 'Email for new tasks', 'notifications.email.new_tasks.desc': 'Receive an email when a new task is posted in your categories', 'notifications.messages.desc': 'Receive a notification when a new message arrives', 'notifications.saved': 'Settings saved', 'notifications.plan_required': 'Not available in your plan', 'profile.tab.info': 'Basic info', 'profile.tab.finance': 'Finance', 'profile.tab.skills': 'Skills', 'profile.tab.categories': 'Categories', 'profile.tab.geography': 'Geography', 'profile.specialist.categories': 'Work categories', 'profile.specialist.categories.desc': 'Select the categories you work in', 'profile.specialist.geography': 'Coverage areas', 'profile.specialist.geography.desc': 'Select the cities / districts where you are active', 'profile.saving': 'Saving...', 'profile.upload.error': 'Error uploading photo', 'profile.saved': 'Saved', 'profile.tab.cards': 'Portfolio', 'profile.cards.count': 'Portfolio', 'profile.cards.add': 'Add portfolio', 'profile.cards.new_title': 'New portfolio title', 'profile.cards.placeholder': 'e.g. Plumbing', 'profile.cards.create': 'Create', 'profile.cards.cancel': 'Cancel', 'profile.cards.empty': 'No portfolio yet', 'profile.cards.create_first': 'Create your first portfolio', 'profile.cards.delete_confirm': 'Delete portfolio?', 'profile.card.tab.main': 'General', 'profile.card.tab.skills': 'Skills', 'profile.card.tab.categories': 'Categories', 'profile.card.tab.geography': 'Geography', 'profile.card.tab.portfolio': 'Portfolio', 'profile.card.active': 'Active', 'profile.card.save': 'Save', 'profile.card.saved': 'Saved', 'profile.card.delete': 'Delete', 'profile.card.skill.add': 'Add skill', 'profile.card.photo.add': 'Add photo', 'profile.card.photo.uploading': 'Uploading...', 'profile.card.photo.empty': 'No photos yet', 'profile.card.item.title': 'Title', 'profile.card.item.desc': 'Description', 'profile.card.item.save': 'Save', 'profile.card.item.cancel': 'Cancel', 'profile.card.item.edit': 'Edit', 'profile.upgrade.cards_limit': 'Portfolio limit reached', 'profile.upgrade.plan': 'Current plan:', 'profile.upgrade.contact': 'Contact the administrator to change your plan', 'profile.upgrade.ok': 'Got it', 'profile.plan.title': 'Subscription plan', 'profile.balance': 'Balance', 'profile.balance.topup': 'Top Up Balance', 'profile.balance.topup.title': 'Top Up Balance', 'profile.balance.topup.amount': 'Amount (EUR)', 'profile.balance.topup.hint': 'Choose a preset or enter a custom amount', 'profile.balance.topup.submit': 'Proceed to Payment', 'profile.balance.topup.loading': 'Redirecting...', 'profile.balance.topup.error': 'Payment initiation failed. Please try again.', 'payment.success.title': 'Payment Successful!', 'payment.success.desc': 'Your balance has been updated.', 'payment.cancelled.title': 'Payment Cancelled', 'payment.cancelled.desc': 'Payment was cancelled. No charges were made.', 'payment.pending.title': 'Processing...', 'payment.pending.desc': 'Your payment is being processed.', 'payment.back_to_profile': 'Back to Profile', 'profile.plan.basic': 'Basic (free)', 'profile.plan.contact_upgrade': 'Contact admin to upgrade your plan', 'profile.plan.cards_up_to': 'Portfolio: up to', 'profile.plan.cards_unlimited': 'Portfolio: unlimited', 'profile.plan.tasks_up_to': 'Tasks: up to', 'profile.plan.offers_up_to': 'Offers: up to', 'profile.plan.valid_until': 'Valid until', 'profile.plan.no_expiry': 'No expiry', // Create task 'create.error': 'Error posting task', // Tasks list extras 'tasks.category.general': 'General', 'tasks.budget.range': 'Range:', 'tasks.budget.from': 'from', 'tasks.budget.to': 'to', 'tasks.filter.reset': 'Reset filters', 'tasks.load_more': 'Load more', 'tasks.showing': 'Results:', 'tasks.field.budget': 'Budget, €', // Admin 'admin.title': 'Admin Panel', 'admin.tab.stats': 'Statistics', 'admin.tab.users': 'Users', 'admin.tab.tasks': 'Tasks', 'admin.tab.reports': 'Reports', 'admin.stats.users': 'Users', 'admin.stats.tasks': 'Tasks', 'admin.stats.offers': 'Offers', 'admin.stats.reviews': 'Reviews', 'admin.tasks.by_status': 'Tasks by status', 'admin.col.user': 'User', 'admin.col.email': 'Email', 'admin.col.role': 'Role', 'admin.col.registered': 'Registered', 'admin.col.status': 'Status', 'admin.col.title': 'Title', 'admin.col.budget': 'Budget', 'admin.col.created': 'Created', 'admin.users.active': 'Active', 'admin.users.inactive': 'Inactive', 'admin.users.deactivate': 'Deactivate', 'admin.users.activate': 'Activate', 'admin.tasks.cancel': 'Cancel', 'admin.reports.none': 'No reports', 'admin.reports.reviewed': 'Reviewed', 'admin.reports.dismiss': 'Dismiss', 'admin.pagination.total': 'Total', 'admin.users.role.change': 'Change role', 'admin.users.search.placeholder': 'Search name or email...', 'admin.tasks.delete': 'Delete', 'admin.tasks.delete.confirm': 'Permanently delete this task?', 'admin.tasks.search.placeholder': 'Search title...', 'admin.col.customer': 'Customer', 'admin.col.reporter': 'Reporter', 'admin.col.target': 'Target', 'admin.filter.all_roles': 'All roles', 'admin.filter.all_statuses': 'All statuses', 'admin.reports.target.task': 'Task', 'admin.reports.target.user': 'User', 'admin.tab.categories': 'Categories', 'admin.tab.locations': 'Cities & Districts', 'admin.tab.logs': 'Logs', 'admin.tab.plans': 'Plans', 'admin.tab.settings': 'Settings', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Activity', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Notifications', 'admin.notif_logs.type': 'Type', 'admin.notif_logs.title': 'Title', 'admin.notif_logs.read': 'Read', 'admin.notif_logs.empty': 'No notification logs', 'admin.stats.notif_chart_title': 'Notifications per day', 'admin.stats.notif_label': 'Notifications', 'admin.stats.mail_chart_title': 'Emails per day', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'All', 'admin.stats.specialists': 'Specialists', 'admin.col.plan': 'Plan', 'admin.back_home': 'Home', 'admin.plans.title': 'Subscription plans', 'admin.plans.add': '+ New plan', 'admin.plans.empty': 'No plans created', 'admin.plans.form.new': 'New plan', 'admin.plans.form.edit': 'Edit plan', 'admin.plans.form.name': 'Name', 'admin.plans.form.price': 'Price (EUR)', 'admin.plans.form.old_price': 'Old price (EUR, optional)', 'admin.plans.form.max_offers': 'Max offers (empty = no limit)', 'admin.plans.form.max_cards': 'Max portfolio (empty = no limit)', 'admin.plans.form.duration_days': 'Duration (days, empty = no expiry)', 'admin.plans.form.description': 'Description', 'admin.plans.form.features': 'Features (one per line)', 'admin.plans.form.notify': 'Notify about new tasks', 'admin.plans.form.default': 'Default', 'admin.plans.form.active': 'Active', 'admin.plans.form.order': 'Order', 'admin.plans.form.role': 'Role', 'admin.plans.form.tier': 'Tier', 'admin.plans.form.role.customer': 'Customer', 'admin.plans.form.role.specialist': 'Specialist', 'admin.plans.form.tier.free': 'Free', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Limits (empty = unlimited)', 'admin.plans.form.max_messages_day': 'Max Messages/Day', 'admin.plans.form.max_orders_day': 'Max Orders/Day', 'admin.plans.form.max_skills': 'Max Skills', 'admin.plans.form.max_profiles': 'Max Profiles', 'admin.plans.form.max_portfolio': 'Max Portfolio Items', 'admin.plans.form.section.boost': 'Multipliers & Boost', 'admin.plans.form.search_boost': 'Search Boost', 'admin.plans.form.offers_multiplier': 'Offers Multiplier', 'admin.plans.form.section.contact': 'Contact Permissions', 'admin.plans.form.can_contact_free': 'Contact Free Plan users', 'admin.plans.form.can_contact_pro': 'Contact Pro Plan users', 'admin.plans.form.can_contact_all': 'Contact All users', 'admin.plans.form.can_show_contact': 'Show Contact Info', 'admin.plans.form.can_view_phone': 'View Phone', 'admin.plans.form.section.features': 'Feature Flags', 'admin.plans.form.upload_video': 'Upload Video', 'admin.plans.form.favorites': 'Favorites', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Verified Badge', 'admin.plans.form.highlighted_reviews': 'Highlighted Reviews', 'admin.plans.form.personal_site': 'Personal Site', 'admin.plans.form.can_help_now': 'Can Help Now Status', 'admin.plans.form.need_help': 'Need Help Status', 'admin.plans.form.auto_response': 'Auto Response', 'admin.plans.form.auto_match': 'Auto Match', 'admin.plans.form.instant_dispatch_free': 'Instant Dispatch (Free)', 'admin.plans.form.instant_dispatch_pro': 'Instant Dispatch (Pro)', 'admin.plans.badge.default': 'Default', 'admin.plans.badge.inactive': 'Inactive', 'admin.plans.make_default': 'Set as default', 'admin.plans.tasks': 'Tasks', 'admin.plans.offers': 'Offers', 'admin.plans.cards': 'Portfolio', 'admin.plans.notify_tasks': 'Task notifications', 'admin.plans.delete.confirm': 'Delete plan', 'admin.activity.title': 'Activity log', 'admin.activity.event': 'Event', 'admin.activity.all_events': 'All events', 'admin.activity.from': 'From', 'admin.activity.to': 'To', 'admin.activity.reset': 'Reset', 'admin.activity.total': 'Total', 'admin.activity.empty': 'No records', 'admin.mail.event': 'Email event', 'admin.mail.all_events': 'All email events', 'admin.mail.from': 'From', 'admin.mail.to': 'To', 'admin.mail.reset': 'Reset', 'admin.mail.total': 'Total', 'admin.mail.empty': 'No email logs', 'admin.mail.recipient': 'Recipient', 'admin.mail.provider': 'Provider', 'admin.mail.details': 'Details', 'admin.mail.status': 'Status', 'admin.mail.success': 'Success', 'admin.mail.failed': 'Failed', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'No records', 'admin.logs.date': 'Date', 'admin.logs.provider': 'Provider', 'admin.logs.model': 'Model', 'admin.logs.action': 'Action', 'admin.logs.langs': 'Languages', 'admin.logs.in': 'In', 'admin.logs.out': 'Out', 'admin.logs.total': 'Total', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Status', 'admin.stats.activity_30d': 'Activity over 30 days', 'admin.stats.tasks_label': 'Tasks', 'admin.stats.users_label': 'Users', 'admin.stats.specialists_label': 'Specialists', 'admin.stats.tokens_title': 'Token usage (by month)', 'admin.stats.tokens_out': 'Output', 'admin.stats.tokens_in': 'Input', 'admin.stats.tokens_out_label': 'Output tokens', 'admin.stats.tokens_in_label': 'Input tokens', 'admin.stats.cost_label': 'Cost (USD)', 'admin.stats.tasks_by_status': 'Tasks by status', 'admin.task_status.open': 'Open', 'admin.task_status.in_progress': 'In progress', 'admin.task_status.completed': 'Completed', 'admin.task_status.cancelled': 'Cancelled', 'admin.task_status.draft': 'Drafts', 'admin.settings.tab.general': 'General', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Notifications', 'admin.settings.tab.payment': 'Payment', 'admin.settings.tab.referral': 'Referrals', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Socials', 'admin.settings.socials.title': 'Social Network Links', 'admin.settings.socials.hint': 'Filled links are displayed in the site footer', 'admin.settings.seo.maintenance_label': 'Maintenance Mode', 'admin.settings.seo.maintenance_hint': 'Show a maintenance page to all visitors', 'admin.settings.seo.indexing_label': 'Search Engine Indexing', 'admin.settings.seo.indexing_hint': 'Allow search engines to index the site', 'admin.settings.seo.head_scripts_label': ' Scripts (JS)', 'admin.settings.seo.head_scripts_hint': 'Runs on every page (Google Tag Manager, analytics, etc.)', 'admin.settings.seo.site_title_label': 'Site Title', 'admin.settings.seo.site_description_label': 'Site Description (meta description)', 'admin.settings.referral.title': 'Referral program', 'admin.settings.referral.hint': 'Reward users who bring new registrations.', 'admin.settings.referral.enabled_label': 'Enabled', 'admin.settings.referral.enabled_hint': 'Enable / disable reward application', 'admin.settings.referral.customer_section': 'For customers', 'admin.settings.referral.specialist_section': 'For specialists', 'admin.settings.referral.plan_label': 'Reward plan', 'admin.settings.referral.no_plan': '— no plan —', 'admin.settings.referral.plan_hint': 'This plan will be assigned to the referrer. If their current plan is higher, only days will be added.', 'admin.settings.referral.days_label': 'Reward days', 'admin.settings.referral.days_hint': 'Number of days added to the plan expiry.', 'admin.settings.general.title': 'General settings', 'admin.settings.general.site_name': 'Site name', 'admin.settings.general.site_url': 'Site URL', 'admin.settings.general.contact_email': 'Contact email', 'admin.settings.general.support_phone': 'Support phone', 'admin.settings.smtp.title': 'SMTP settings', 'admin.settings.smtp.hint': 'Used to send email notifications.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Port', 'admin.settings.smtp.encryption': 'Encryption', 'admin.settings.smtp.enc.none': 'None', 'admin.settings.smtp.enc.tls': 'STARTTLS (port 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (port 465)', 'admin.settings.smtp.username': 'Username', 'admin.settings.smtp.password': 'Password / App Password', 'admin.settings.smtp.from_name': 'Sender name', 'admin.settings.smtp.from_email': 'Sender email', 'admin.settings.smtp.test': 'Send test email', 'admin.settings.smtp.sending': 'Sending...', 'admin.settings.payment.hint': 'ePay Piraeus Bank credentials.', 'admin.settings.env.test': 'Test (sandbox)', 'admin.settings.env.prod': 'Production', 'admin.settings.env.label': 'Environment', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Active', 'admin.settings.saving': 'Saving...', 'admin.settings.saved': 'Saved', 'admin.notif.vars_hint': 'Available variables in templates', 'admin.notif.tmpl.not_set': 'Template not configured', 'admin.notif.tmpl.subject_label': 'Email subject', 'admin.notif.tmpl.body_label': 'Email body (HTML)', 'admin.notif.tmpl.save': 'Save', 'admin.notif.tmpl.close': 'Close', 'admin.notif.tmpl.translate': 'Auto-translate to other languages', 'admin.notif.tmpl.translating': 'Translating...', 'admin.notif.tmpl.saving': 'Saving...', 'admin.notif.email_verification': 'Email verification', 'admin.notif.registration_success': 'Successful registration', 'admin.notif.password_reset': 'Password reset', 'admin.notif.new_offer': 'New offer', 'admin.notif.new_task': 'New task', 'admin.notif.offer_accepted': 'Offer accepted', 'admin.notif.new_message': 'New message', 'admin.notif.offer_declined': 'Offer declined', 'admin.notif.offer_other_accepted': 'Another specialist chosen', 'admin.notif.task_updated': 'Task updated', 'admin.notif.deadline_reminder': 'Deadline reminder', 'admin.notif.task_archived': 'Task unpublished automatically', 'admin.notif.referral_reward': 'Referral reward', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Plan activated', 'admin.email_template.plan_upgraded': 'Plan upgraded', 'admin.email_template.plan_downgrade_scheduled': 'Downgrade scheduled', 'admin.email_template.plan_downgrade_applied': 'Downgrade applied', 'admin.email_template.plan_renewal_reminder': 'Renewal reminder', 'admin.email_template.plan_insufficient_funds': 'Insufficient funds warning', // Pricing confirm modal 'pricing.confirm.title': 'Confirm plan selection', 'pricing.confirm.plan': 'Plan', 'pricing.confirm.prorated': 'Prorated credit', 'pricing.confirm.effective_price': 'Amount due', 'pricing.confirm.your_balance': 'Your balance', 'pricing.confirm.downgrade_info': 'The switch to the new plan will happen automatically after the current period ends.', 'pricing.confirm.insufficient': 'Insufficient balance.', 'pricing.confirm.top_up': 'Top up', 'pricing.confirm.schedule_downgrade': 'Schedule downgrade', 'pricing.confirm.pay': 'Pay', 'admin.user_edit.title': 'Edit user', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email verified', 'admin.user_edit.email_not_verified': 'Email not verified', 'admin.user_edit.verify_email_btn': 'Verify manually', 'admin.user_edit.verify_email_done': 'Email verified!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Registered', 'admin.user_edit.last_seen': 'Last seen', 'admin.user_edit.lang': 'Language', 'admin.user_edit.first_name': 'First name', 'admin.user_edit.last_name': 'Last name', 'admin.user_edit.phone': 'Phone', 'admin.user_edit.bio': 'Bio', 'admin.user_edit.role': 'Role', 'admin.user_edit.plan': 'Plan', 'admin.user_edit.no_plan': '— No plan —', 'admin.user_edit.active': 'Active account', 'admin.user_edit.balance': 'Balance (EUR)', 'admin.user_edit.skills': 'Skills', 'admin.user_edit.tab.profile': 'Profile', 'admin.user_edit.tab.account': 'Account', 'admin.user_edit.tab.balance': 'Balance', 'admin.user_edit.tab.settings': 'Settings', 'admin.user_edit.tab.specialist': 'Portfolio', 'admin.user_edit.tab.site': 'Website', 'admin.user_edit.plan_expires': 'Plan expires', 'admin.user_edit.interface_lang': 'Interface language', 'admin.user_edit.comm_languages': 'Communication languages', 'admin.user_edit.personal_site_slug': 'Personal page', 'admin.user_edit.show_contact_info': 'Show contact info', 'admin.user_edit.show_contact_info.hint': 'Visible to customers', 'admin.user_edit.notify_new_tasks': 'Notify about new tasks', 'admin.user_edit.notify_new_tasks.hint': 'Push and email notifications', 'admin.user_edit.notif_messages': 'Message notifications', 'admin.user_edit.notif_messages.hint': 'New messages in chat', 'admin.user_edit.site_settings': 'Personal page settings', 'admin.user_edit.categories': 'Service categories', 'admin.user_edit.locations': 'Service areas', 'admin.user_edit.skill_placeholder': 'New skill...', 'admin.user_edit.add_category': '— Select category —', 'admin.user_edit.add_location': '— Select location —', 'admin.user_edit.specialist_cards': 'Portfolio', 'admin.user_edit.no_cards': 'No portfolio found', 'admin.user_edit.card_title': 'Portfolio title', 'admin.user_edit.card_description': 'Description', 'admin.balance.topup.btn': 'Top up', 'admin.balance.withdraw.btn': 'Withdraw', 'admin.balance.modal_hint': 'Changes take effect immediately and are recorded in history', 'admin.balance.topup.title': 'Top up balance', 'admin.balance.topup.amount': 'Amount', 'admin.balance.topup.description': 'Comment', 'admin.balance.topup.description.placeholder': 'For example: bonus or manual top-up', 'admin.balance.topup.submit': 'Top up balance', 'admin.balance.withdraw.title': 'Withdraw balance', 'admin.balance.withdraw.amount': 'Amount', 'admin.balance.withdraw.description': 'Comment', 'admin.balance.withdraw.description.placeholder': 'For example: refund or manual debit', 'admin.balance.withdraw.submit': 'Withdraw from balance', 'admin.user_edit.role.customer': 'Customer', 'admin.user_edit.role.specialist': 'Specialist', 'admin.user_edit.role.admin': 'Administrator', 'common.refresh': 'Refresh', 'common.back_home': 'Home', 'admin.loc.hint': 'Manage cities and districts', 'admin.loc.add_city': 'New city', 'admin.loc.add_district': 'Add district', 'admin.loc.new': 'New location', 'admin.loc.edit': 'Edit location', 'admin.loc.district': 'district', 'admin.loc.empty': 'No locations', 'admin.loc.delete.confirm': 'Delete location? All districts will also be deleted.', 'admin.cat.add_root': 'New category', 'admin.cat.add_sub': 'Subcategory', 'admin.cat.edit': 'Edit', 'admin.cat.delete': 'Delete', 'admin.cat.delete.confirm': 'Delete category? All subcategories will also be deleted.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Icon', 'admin.cat.name_el': 'Greek', 'admin.cat.name_en': 'English', 'admin.cat.name_ru': 'Russian', 'admin.cat.order': 'Order', 'admin.cat.active': 'Active', 'admin.cat.parent': 'Parent category', 'admin.cat.no_parent': 'Top level', 'admin.cat.save': 'Save', 'admin.cat.cancel': 'Cancel', 'admin.cat.empty': 'No categories', 'admin.cat.hint': 'Manage categories with multi-level hierarchy', 'admin.cat.new': 'New category', 'admin.cat.subcategory': 'subcategory', 'admin.cat.add_child': 'Add subcategory', 'admin.cat.inactive': 'Inactive', 'admin.event.user_login': 'Login', 'admin.event.user_register': 'Registration', 'admin.event.admin_user_deactivate': 'User blocked', 'admin.event.admin_user_activate': 'User activated', 'admin.event.admin_user_role_changed': 'Role changed', 'admin.event.admin_task_cancelled': 'Task cancelled', 'admin.event.admin_task_deleted': 'Task deleted', 'admin.event.admin_report_reviewed': 'Report reviewed', 'admin.event.admin_report_dismissed': 'Report dismissed', 'admin.event.task_created': 'Task created', // User status 'user.online': 'Online', 'user.seen_minutes': 'was here {n} min ago', 'user.seen_hours': 'was here {n} hr ago', 'user.seen_yesterday': 'was here yesterday', 'user.seen_days': 'was here {n} days ago', // Specialists 'specialists.title': 'Specialists', 'specialists.search': 'Search specialist...', 'specialists.search.btn': 'Search', 'specialists.empty': 'No specialists found', 'specialists.no_bio': 'No description', 'specialists.view': 'View profile', 'specialists.reviews': 'reviews', 'specialist.favorite': 'Add to favorites', 'specialist.unfavorite': 'Remove from favorites', 'specialist.site_link': 'Personal site', 'favorites.specialists.title': 'Favourite specialists', 'favorites.specialists.empty': 'No favourite specialists yet', 'nav.favorites': 'Favourites', 'nav.schedule': 'Schedule', 'nav.find_tasks': 'Find Orders', 'schedule.title': 'My Schedule', 'schedule.subtitle': 'Mark the days when you are free or busy — clients will see your availability', 'schedule.available': 'Available', 'schedule.busy': 'Busy', 'schedule.unset': 'Not set', 'schedule.click_hint': '← click to cycle status', 'schedule.range_mode': 'Select range', 'schedule.range_from': 'From {date} — select end date', 'schedule.click_to_set': 'Click to set', 'schedule.free': 'free', 'schedule.busy_count': 'busy', 'schedule.free_days': 'free days', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Connect Google Calendar', 'schedule.disconnectGoogle': 'Disconnect', 'schedule.connectedAs': 'Connected as', 'schedule.importFromGoogle': 'Sync from Google', 'schedule.gcalConnected': '\u2713 Google Calendar connected', 'schedule.gcalError': 'Google Calendar connection error', 'schedule.gcalImportDone': 'Imported {n} days from Google Calendar', 'schedule.gcalAutoSyncNote': 'Availability changes are automatically synced to Google Calendar', 'schedule.gcalConnectDesc': 'Connect Google Calendar to automatically sync your availability', 'schedule.gcalDisconnectConfirm': 'Disconnect Google Calendar?', 'find_tasks.title': 'Find Orders', 'find_tasks.for_me': 'For me', 'find_tasks.all': 'All orders', 'find_tasks.by_category': 'By category', 'find_tasks.list': 'List', 'find_tasks.already_offered': 'Offer sent', 'find_tasks.offer_now': 'Make an offer', 'find_tasks.empty_for_me': 'No tasks found in your categories', 'find_tasks.banner_hint': 'Find tasks matching your portfolio categories', 'find_tasks.no_cards': 'Create a specialist portfolio to see tasks matched to you', 'find_tasks.add_card': 'Create portfolio', 'find_tasks.search': 'Search tasks...', 'find_tasks.tasks_count': 'tasks', 'footer.tagline': 'The task platform for Greece', 'footer.rights': 'All rights reserved.', // App download section 'app.download_title': 'Download the CanHelp mobile app', 'app.download_desc': 'All of CanHelp — always at your fingertips. Available for Android and iOS.', // Nav 'nav.pricing': 'Pricing', // Pricing page 'pricing.title': 'Pricing', 'pricing.subtitle': 'Choose the right plan for you', 'pricing.role.customer': 'Customer', 'pricing.role.specialist': 'Specialist', 'pricing.free': 'Free', 'pricing.per_month': 'mo', 'pricing.duration': 'Duration', 'pricing.days': 'days', 'pricing.current_plan': 'Your plan', 'pricing.popular': 'Popular', 'pricing.choose': 'Choose', 'pricing.your_plan': 'Active plan', 'pricing.free_default': 'Default', 'pricing.compare': 'Compare features', 'pricing.feature': 'Feature', 'pricing.faq_note': 'Payment is deducted from your CanHelp balance. Top up available in Payments.', 'pricing.feat.messages': 'Messages / day', 'pricing.feat.orders': 'Orders / day', 'pricing.feat.contact_all': 'Contact everyone', 'pricing.feat.view_phone': 'View phone number', 'pricing.feat.show_contact': 'Show contact info', 'pricing.feat.favorites': 'Favorites', 'pricing.feat.verified_badge': 'Verified badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Personal site', 'pricing.feat.auto_response': 'Auto-response', 'pricing.feat.auto_match': 'Auto-match', 'pricing.feat.highlighted_reviews': 'Highlighted reviews', 'pricing.feat.portfolio': 'Portfolio items', 'pricing.feat.cards': 'Specialist cards', 'pricing.feat.notify_tasks': 'New task notifications', 'pricing.feat.video': 'Video in portfolio', // Upgrade prompt 'upgrade.available_in': 'Available in', 'upgrade.cta': 'Upgrade', // Dashboard plan block 'dashboard.plan.title': 'My Plan', 'dashboard.plan.expires': 'Expires in {n} days', 'dashboard.plan.upgrade': 'Upgrade plan', 'dashboard.plan.no_plan': 'Free plan', 'dashboard.plan.messages': 'Messages today', 'dashboard.plan.orders': 'Orders today', 'dashboard.plan.limits': 'Daily limits', 'dashboard.plan.features': 'Features', 'dashboard.plan.stats': 'Stats', 'dashboard.stats.cards': 'Portfolios', 'dashboard.stats.maxCards': 'Max portfolios', 'dashboard.stats.portfolioItems': 'Portfolio items', 'dashboard.stats.maxPortfolioItems': 'Max items', 'dashboard.stats.activeOffers': 'Active offers', 'dashboard.stats.reviewsReceived': 'Reviews', 'dashboard.stats.activeTasks': 'Active tasks', 'dashboard.stats.completedTasks': 'Completed', 'status.need_help': 'I need help', 'status.active': 'Active', 'status.toggle_on': 'Enable', 'status.toggle_off': 'Disable', // FOMO 'fomo.missed_orders': 'Missed {n} orders', 'fomo.missed_value': 'Worth €{v}', 'fomo.upgrade_hint': 'Upgrade to receive more orders', 'fomo.conversion': 'Task conversion', 'fomo.active': 'Active', 'fomo.with_offers': 'With offers', 'fomo.completed': 'Completed', 'fomo.already_offered': '{n} specialists have already responded', 'fomo.specialist_missed': 'You missed {n} orders', 'fomo.top_categories': 'Categories', 'fomo.offers_received': 'offers received', 'fomo.avg_offers': 'Avg {n}/task', 'fomo.completion_rate': 'completed', // Task auto-match 'task.auto_match': 'Auto-match', 'task.auto_match_results': 'Top specialists', 'task.no_offer_yet': 'You haven\'t sent an offer yet', 'task.make_offer': 'Send offer', 'auto_response.title': 'Auto-Response', 'auto_response.enabled': 'Enable auto-response', 'auto_response.min_budget': 'Min budget', 'auto_response.max_budget': 'Max budget', 'auto_response.default_price': 'Default price', 'auto_response.default_message': 'Default message', 'auto_response.max_per_day': 'Max auto-offers per day', 'auto_response.save': 'Save', 'auto_response.saved': 'Saved', 'auto_response.categories': 'Categories', 'auto_response.locations': 'Locations', // Personal site 'profile.personal_site': 'Personal Site', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Only latin letters, numbers, - and _', 'profile.site_open': 'Open site', 'profile.site_preview': 'Your site', 'profile.show_contact': 'Show contact info', 'profile.show_contact_hint': 'Customers with Pro/Ultimate plans will see your phone number', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Calendar requires a Pro or Ultimate plan', // Chat limits 'chat.limit_warning': '{n} messages left today', 'chat.limit_reached': 'Message limit reached. Upgrade your plan', 'chat.upgrade': 'Upgrade', // Site page 'site.member_since': 'Member since', 'site.rating': 'Rating', 'site.completed_tasks': 'Completed', 'site.languages': 'Languages', 'site.photos': 'photos', 'site.contact_form': 'Get in touch', 'site.contact_sent': 'Message sent!', 'site.contact_sent_desc': 'The specialist will contact you soon', 'site.contact_name': 'Name', 'site.contact_name_ph': 'Your name', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Message', 'site.contact_message_ph': 'Describe your task...', 'site.contact_send': 'Send', 'site.share': 'Share', 'site.speaks_languages': 'Speaks', 'site.message_sent': 'Message sent!', 'site.message_sent_desc': 'The specialist will receive it in the chat', 'site.message_placeholder': 'Write your message...', 'site.write_to_chat': 'Write to chat', 'site.auth_required_title': 'Sign in required', 'site.auth_required_desc': 'To write in the chat, you need to sign in to your CanHelp account.', 'site.auth_login_btn': 'Sign in', 'site.auth_contact_form_btn': 'Contact via feedback form', 'specialist.services': 'Services', 'portfolio.title': 'Portfolio', 'status.can_help_now': 'Available now', 'common.not_found': 'Page not found', 'common.anonymous': 'Anonymous', 'specialist_setup.page_title': 'Specialist profile setup', 'specialist_setup.step_of': 'Step {current} of {total}', 'specialist_setup.next': 'Next', 'specialist_setup.back': 'Back', 'specialist_setup.skip': 'Skip', 'specialist_setup.finish': 'Finish', 'specialist_setup.go_to_profile': 'Go to profile', 'specialist_setup.browse_tasks': 'Browse tasks', 'specialist_setup.step1.title': 'Welcome!', 'specialist_setup.step1.subtitle': "Let's set up your profile", 'specialist_setup.step1.desc': 'A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.', 'specialist_setup.step1.what_next': 'What we will do:', 'specialist_setup.step1.item1': 'Fill in basic information', 'specialist_setup.step1.item2': 'Create a service card', 'specialist_setup.step1.item3': 'Add skills and categories', 'specialist_setup.step1.item4': 'Select service area', 'specialist_setup.step1.item5': 'Upload portfolio photos', 'specialist_setup.step2.title': 'Basic profile', 'specialist_setup.step2.subtitle': 'Tell us about yourself', 'specialist_setup.step2.bio_label': 'About me', 'specialist_setup.step2.bio_placeholder': 'Describe your experience, services you offer...', 'specialist_setup.step2.phone_label': 'Phone', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Profile photo', 'specialist_setup.step2.photo_btn': 'Upload photo', 'specialist_setup.step2.photo_uploading': 'Uploading...', 'specialist_setup.step2.photo_hint': 'Shown on your profile', 'specialist_setup.step3.title': 'Service card', 'specialist_setup.step3.subtitle': 'Create your first service card', 'specialist_setup.step3.title_label': 'Card title', 'specialist_setup.step3.title_placeholder': 'E.g. Plumber, Electrician, Cleaning...', 'specialist_setup.step3.desc_label': 'Description', 'specialist_setup.step3.desc_placeholder': 'Describe in detail what you offer, your experience, advantages...', 'specialist_setup.step3.title_required': 'Title is required', 'specialist_setup.step4.title': 'Skills & Categories', 'specialist_setup.step4.subtitle': 'Add skills and select categories', 'specialist_setup.step4.skills_label': 'Skills', 'specialist_setup.step4.skills_placeholder': 'E.g. Pipe installation...', 'specialist_setup.step4.skills_add': 'Add', 'specialist_setup.step4.categories_label': 'Categories', 'specialist_setup.step5.title': 'Service area', 'specialist_setup.step5.subtitle': 'Where do you provide services?', 'specialist_setup.step5.hint': 'Select cities or specific areas', 'specialist_setup.done.title': 'Your profile is ready!', 'specialist_setup.done.subtitle': 'Congratulations! Your profile has been set up', 'specialist_setup.done.desc': 'You can now receive orders from clients. Browse tasks that match your skills.' }, ru: { 'footer.slogan': 'Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.', 'footer.links': 'Ссылки', 'footer.socials': 'Мы в соцсетях', 'nav.home': 'Главная', 'nav.tasks': 'Задачи', 'nav.post': '+ Опубликовать', 'nav.dashboard': 'Панель управления', 'nav.chat': 'Сообщения', 'nav.notifications': 'Уведомления', 'nav.profile': 'Профиль', 'nav.admin': 'Админка', 'nav.specialists': 'Специалисты', 'nav.new_task': 'Новая задача', 'nav.login': 'Войти', 'nav.register': 'Регистрация', 'nav.logout': 'Выйти', 'hero.title': 'Найди специалиста для любой работы', 'hero.subtitle': 'Опубликуй задачу, получи предложения и выбери лучшего профессионала', 'hero.cta.post': 'Опубликовать задачу', 'hero.cta.browse': 'Стать специалистом', 'hero.search.placeholder': 'Что нужно? напр. электрик, уборка...', 'stats.specialists': 'специалистов', 'stats.tasks': 'задач', 'stats.categories': 'категорий', 'stats.free': 'бесплатная регистрация', 'section.categories': 'Создай задачу в любой категории', 'section.how': 'Как это работает', 'section.recent': 'Последние задачи', 'section.all': 'Смотреть все →', 'section.more': 'ещё', 'section.cities': 'Города и районы', 'section.community': 'Общественный проект для всех', 'community.subtitle': 'CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.', 'community.point1.title': 'Умеете что-то делать?', 'community.point1.desc': 'Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.', 'community.point2.title': 'Нужна помощь?', 'community.point2.desc': 'Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.', 'community.point3.title': 'Помогите проекту расти', 'community.point3.desc': 'CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.', 'community.share': 'Поделиться с друзьями', 'community.share.copied': 'Ссылка скопирована!', // Referral section on home page 'section.referral': 'Реферальная программа', 'referral.home.subtitle': 'Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.', 'referral.home.step1.title': 'Зарегистрируйтесь и получите ссылку', 'referral.home.step1.desc': 'Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.', 'referral.home.step2.title': 'Поделитесь с друзьями', 'referral.home.step2.desc': 'Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.', 'referral.home.step3.title': 'Получайте награды', 'referral.home.step3.desc': 'Как только друг подтвердит email, вы автоматически получите свою награду.', 'referral.home.cta': 'Получить ссылку', 'referral.home.badge': 'Реферальная программа', // FAQ section 'section.faq': 'Частые вопросы', 'faq.q1': 'Как работает CanHelp?', 'faq.a1': 'Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.', 'faq.q2': 'Сколько стоит использование платформы?', 'faq.a2': 'Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.', 'faq.q3': 'Как стать специалистом?', 'faq.a3': 'Зарегистрируйтесь, перейдите в «Стать специалистом», заполните профиль навыками и категориями и начните получать задачи.', 'faq.q4': 'Как выбрать подходящего специалиста?', 'faq.a4': 'Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.', 'faq.q5': 'Что если я не доволен результатом?', 'faq.a5': 'Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.', 'faq.q6': 'Можно ли связаться со специалистом до принятия предложения?', 'faq.a6': 'Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.', 'faq.q7': 'Сколько времени ждать предложений?', 'faq.a7': 'Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.', 'faq.q8': 'Можно ли разместить задачу в любом городе Греции?', 'faq.a8': 'Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.', 'faq.q9': 'Какие виды задач есть на CanHelp?', 'faq.a9': 'Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.', 'faq.q10': 'Есть ли мобильное приложение?', 'faq.a10': 'Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.', 'how.step1.title': 'Опубликуй задачу', 'how.step1.desc': 'Опиши что нужно и установи бюджет', 'how.step2.title': 'Получи предложения', 'how.step2.desc': 'Специалисты пришлют предложения с ценой и сроками', 'how.step3.title': 'Выбери и начни', 'how.step3.desc': 'Выбери лучшего профессионала и начни сотрудничество', 'tasks.title': 'задач', 'tasks.filters': 'Фильтры', 'tasks.search': 'Поиск', 'tasks.search.placeholder': 'Название или ключевое слово...', 'tasks.search.btn': 'Поиск', 'tasks.publish': 'Опубликовать', 'tasks.category.all': 'Все', 'tasks.category.all_in': 'Все в', 'tasks.category.label': 'Категория', 'tasks.location.label': 'Город', 'tasks.location.placeholder': 'напр. Афины', 'tasks.empty': 'Задачи не найдены', 'tasks.empty.cta': 'Опубликуй первую', 'task.status.open': 'Открыта', 'task.status.in_progress': 'В работе', 'task.status.completed': 'Завершена', 'task.status.cancelled': 'Отменена', 'task.status.draft': 'Черновик', 'task.budget': 'Бюджет', 'task.location': 'Местоположение', 'task.deadline': 'Дата начала', 'task.created_at': 'Создано', 'task.customer': 'Заказчик', 'task.offer.btn': 'Отправить предложение', 'task.invite.banner_title': 'Вас пригласили на это задание', 'task.invite.banner_hint': 'Заказчик лично пригласил вас', 'task.invite.accept': 'Отправить предложение', 'task.invite.decline': 'Отказаться', 'offer.accept': 'Принять', 'offer.decline': 'Отклонить', 'task.complete': 'Завершить задачу', 'task.complete.confirm': 'Отметить задачу как выполненную?', 'task.edit': 'Редактировать', 'task.status_label': 'Статус', 'task.yours': 'Ваша задача', 'task.offer.yours': 'Ваше предложение', 'review.leave': 'Оставить отзыв', 'review.rating': 'Оценка', 'review.comment': 'Комментарий', 'review.comment.placeholder': 'Расскажите о своём опыте...', 'review.submit': 'Отправить отзыв', 'review.submitting': 'Отправка...', 'review.done': 'Отзыв отправлен!', 'profile.reviews': 'Отзывы', 'profile.no_reviews': 'Отзывов пока нет', 'profile.rating': 'Рейтинг', 'profile.skills.label': 'Навыки', 'profile.member_since': 'Участник с', 'task.offers': 'Предложения', 'task.offers.none': 'Предложений пока нет', 'create.title': 'Опубликовать задачу', 'create.field.title': 'Название', 'create.field.description': 'Описание', 'create.field.category': 'Категория', 'create.field.category.select': 'Выберите...', 'create.field.location': 'Местоположение', 'create.field.location.any': 'Где угодно', 'create.field.location.all': 'Весь город', 'create.field.budget': 'Бюджет (€)', 'create.field.deadline': 'Дата начала', 'create.field.budget_negotiable': 'Цена обсуждается', 'create.field.time_slot': 'Время выполнения', 'create.field.time_slot.any': 'В любое время', 'create.field.time_slot.morning': 'Утром (08:00–13:00)', 'create.field.time_slot.afternoon': 'Днём (13:00–18:00)', 'create.field.time_slot.evening': 'Вечером (18:00–22:00)', 'create.field.time_slot.weekend': 'Выходной', 'create.field.address': 'Адрес (необязательно)', 'create.field.address.district': 'Квартал', 'create.field.address.street': 'Улица', 'create.field.address.house': 'Дом', 'create.field.confidential': 'Конфиденциальная заметка', 'create.field.confidential.placeholder': 'Детали, видные только назначенному специалисту...', 'create.field.confidential.hint': 'Не отображается публично', 'create.field.photos': 'Фотографии', 'create.field.photos.add': 'Добавить фото', 'create.field.photos.uploading': 'Загрузка...', 'task.budget_negotiable': 'Цена обсуждается', 'task.time_slot': 'Время', 'task.confidential': 'Конфид. заметка', 'create.field.title.placeholder': 'напр. Уборка квартиры 80кв', 'create.field.description.placeholder': 'Подробно опишите что нужно...', 'create.field.location.placeholder': 'напр. Афины, Колонаки', 'create.field.budget.placeholder': 'напр. 100', 'create.submit': 'Опубликовать задачу', 'create.submitting': 'Публикация...', 'login.title': 'Добро пожаловать', 'login.subtitle': 'Вход в CanHelp', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.submitting': 'Вход...', 'login.error': 'Неверный email или пароль', 'login.unverified.title': 'Подтвердите ваш email', 'login.unverified.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'login.unverified.resend': 'Отправить письмо повторно', 'login.unverified.sending': 'Отправка...', 'login.unverified.sent': '✓ Отправлено — проверьте входящие', 'profile.email.verified': 'Email подтверждён', 'profile.email.not_verified': 'Email не подтверждён', 'login.no_account': 'Нет аккаунта?', 'login.register_link': 'Зарегистрироваться', 'login.forgot_password': 'Забыл пароль?', 'login.or_continue_with': 'или продолжите через', 'login.continue_google': 'Войти через Google', 'forgot.title': 'Забыл пароль', 'forgot.subtitle': 'Введите email для получения ссылки восстановления', 'forgot.email': 'Email', 'forgot.submit': 'Отправить ссылку', 'forgot.submitting': 'Отправка...', 'forgot.sent.title': 'Проверьте входящие', 'forgot.sent.desc': 'Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.', 'forgot.back_to_login': 'Вернуться ко входу', 'forgot.error': 'Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.', 'forgot.error.not_found': 'Аккаунт с таким email не найден.', 'forgot.error.send_failed': 'Ошибка отправки письма. Попробуйте позже.', 'reset.title': 'Новый пароль', 'reset.subtitle': 'Введите новый пароль', 'reset.password': 'Новый пароль', 'reset.confirm': 'Подтвердите пароль', 'reset.submit': 'Изменить пароль', 'reset.submitting': 'Сохранение...', 'reset.success': 'Пароль успешно изменён. Перенаправление ко входу...', 'reset.back_to_login': 'Вернуться ко входу', 'reset.error.mismatch': 'Пароли не совпадают', 'reset.error.invalid': 'Недействительная или устаревшая ссылка. Запросите новую.', 'register.title': 'Регистрация', 'register.subtitle': 'Создать аккаунт в CanHelp', 'register.first_name': 'Имя', 'register.last_name': 'Фамилия', 'register.email': 'Email', 'register.password': 'Пароль (мин. 8 символов)', 'register.role': 'Роль', 'register.role.customer': 'Пользователь', 'register.role.customer.desc': 'Публикую задачи', 'register.role.specialist': 'Специалист', 'register.role.specialist.desc': 'Беру задачи', 'register.submit': 'Создать аккаунт', 'register.submitting': 'Регистрация...', 'register.has_account': 'Уже есть аккаунт?', 'register.login_link': 'Войти', 'register.continue_google': 'Зарегистрироваться через Google', 'register.check_email.title': 'Проверьте почту', 'register.check_email.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'register.check_email.login': 'Вернуться к входу', 'dashboard.title': 'Панель управления', 'dashboard.new_task': '+ Новая задача', 'dashboard.my_tasks': 'Мои задачи', 'dashboard.my_offers': 'Мои предложения', 'dashboard.invitations': 'Приглашения на задания', 'dashboard.offers_count': 'предл.', 'dashboard.declined_count': 'откл.', 'dashboard.completed_tasks': 'Завершённые задачи', 'dashboard.completed_offers': 'Завершённые предложения', 'dashboard.review_pending': 'Оценка ещё не оставлена', 'tasks.new.top_specialists': 'Топ специалисты', 'tasks.new.select_category': 'Выберите категорию, чтобы увидеть специалистов', 'tasks.new.invite': 'Предложить работу', 'tasks.new.invited': 'Выбран ✓', 'reviews.count': 'отзывов', 'filter.location': 'Локация', 'filter.language': 'Языки', 'filter.language.any': 'Любой язык', 'filter.category.all': 'Все категории', 'user.categories': 'Категории', 'user.work_area': 'Район работы', 'dashboard.tasks.empty': 'Вы не публиковали задачи', 'dashboard.tasks.empty.cta': 'Опубликуйте первую', 'dashboard.tasks.add_new': 'Добавить новую задачу', 'dashboard.offers.empty': 'Вы не отправляли предложений', 'dashboard.offers.empty.cta': 'Найти задачи', 'dashboard.customer.specialists_title': 'Ищете исполнителя?', 'dashboard.customer.specialists_hint': 'Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи', 'dashboard.customer.specialists_cta': 'Найти исполнителя', 'dashboard.customer.how_title': 'Как это работает', 'dashboard.customer.step1': 'Создайте задачу с описанием и бюджетом', 'dashboard.customer.step2': 'Специалисты пришлют предложения с ценой и сроками', 'dashboard.customer.step3': 'Выберите подходящего и начните работу', 'notif.title': 'Уведомления', 'notif.mark_all': 'Отметить все как прочитанные', 'notif.empty': 'Нет уведомлений', 'notif.type.new_offer': 'Новое предложение', 'notif.type.offer_accepted': 'Ваше предложение принято', 'notif.type.offer_declined': 'Ваше предложение отклонено', 'notif.type.task_completed': 'Задание выполнено', 'notif.type.task_cancelled': 'Задание отменено', 'notif.type.new_message': 'Новое сообщение', 'notif.type.new_review': 'Новый отзыв', 'notif.type.task_invite': 'Приглашение на задание', 'notif.body.new_offer': 'Новое предложение на «{title}»', 'notif.body.offer_accepted': 'Ваше предложение на «{title}» принято', 'notif.body.offer_declined': 'Ваше предложение на «{title}» отклонено', 'notif.body.task_invite': 'Вас приглашают на «{title}»', 'notif.body.new_review': 'Вы получили оценку {rating}★', 'offer.status.pending': 'Ожидает', 'offer.status.accepted': 'Принято', 'offer.status.declined': 'Отклонено', 'offer.status.withdrawn': 'Отозвано', 'offer.status.other_accepted': 'Выбран другой исполнитель', 'common.loading': 'Загрузка...', 'common.error': 'Ошибка', 'common.save': 'Сохранить', 'common.saving': 'Сохранение...', 'common.cancel': 'Отмена', 'common.add': 'Добавить', 'common.close': 'Закрыть', 'common.edit': 'Редактировать', 'common.delete': 'Удалить', 'common.from': 'от', 'common.currency': '€', 'common.greece': 'Греция', // Chat 'chat.connected': 'Подключено', 'chat.disconnected': 'Отключено', 'chat.no_rooms': 'Переписок пока нет', 'chat.task_fallback': 'Задача', 'chat.select': 'Выберите переписку', 'chat.no_messages': 'Сообщений пока нет', 'chat.placeholder': 'Напишите сообщение... (Enter для отправки)', 'chat.conversation_fallback': 'Переписка', 'chat.direct_chat': 'Личный чат', 'chat.linked_task': 'Прикреплённый заказ', 'chat.write_btn': 'Написать', 'chat.just_now': 'только что', 'chat.min_ago': 'м', 'chat.write_specialist': 'Написать специалисту', 'chat.write_customer': 'Написать заказчику', 'chat.notif_settings': 'Настройки уведомлений', 'chat.notif_messages': 'Уведомления о новых сообщениях', 'chat.toast_title': 'Новое сообщение', 'chat.toast_open': 'Открыть чат', // Offer form 'offer.price': 'Цена', 'offer.price.placeholder': 'напр. 80', 'offer.customer_budget': 'Бюджет заказчика', 'offer.message': 'Сообщение', 'offer.optional': 'необязательно', 'offer.message.placeholder': 'Представьтесь, расскажите об опыте и почему вы лучший выбор...', 'offer.submitting': 'Отправка...', // Profile 'profile.photo': 'Фото профиля', 'profile.photo.change': 'Изменить фото', 'profile.photo.hint': 'JPEG, PNG, WebP · до 5MB', 'profile.basic_info': 'Основная информация', 'profile.phone': 'Телефон', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Краткое описание', 'profile.bio.placeholder': 'Расскажите немного о себе...', 'profile.language': 'Язык', 'profile.language.hint': 'Язык интерфейса и email-уведомлений', 'profile.languages': 'Языки общения', 'profile.languages.hint': 'Выберите все языки, на которых вы общаетесь', 'profile.skills': 'Навыки', 'profile.skills.subtitle': 'Добавьте услуги, которые вы предлагаете', 'profile.skills.placeholder': 'напр. Уборка, IT, Репетиторство...', 'profile.role': 'Роль аккаунта', 'profile.role.specialist': '🔧 Специалист', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Пользователь', 'profile.role.change': 'Для смены роли обратитесь в службу поддержки.', 'profile.become_specialist': 'Стать специалистом', 'profile.become_specialist.desc': 'Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.', 'become_specialist.hero.title': 'Зарабатывай, делая то, что умеешь', 'become_specialist.hero.subtitle': 'Создай профиль специалиста и получай заказы от клиентов по всей Греции', 'become_specialist.how.title': 'Как это работает', 'become_specialist.step1.title': 'Создай портфолио специалиста', 'become_specialist.step1.desc': 'Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы', 'become_specialist.step2.title': 'Ищи заказы', 'become_specialist.step2.desc': 'Просматривай задачи по своим категориям в разделе «Поиск заказов»', 'become_specialist.step3.title': 'Откликайся и зарабатывай', 'become_specialist.step3.desc': 'Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы', 'become_specialist.benefits.title': 'Преимущества профиля специалиста', 'become_specialist.benefit1': 'Поиск заказов по вашим категориям и локации', 'become_specialist.benefit2': 'Публичный профиль с отзывами клиентов', 'become_specialist.benefit3': 'Расписание доступности, видимое клиентам', 'become_specialist.benefit4': 'Добавление в избранное клиентами', 'become_specialist.cta': 'Подробнее', 'become_specialist.free_badge': 'Бесплатная регистрация', 'profile.tab.notifications': 'Уведомления', 'profile.tab.reviews': 'Отзывы', 'profile.tab.referral': 'Рефералы', 'profile.tab.auto_response': 'Авто-ответ', 'profile.tab.site': 'Сайт', 'profile.site.title': 'Персональная страница', 'profile.site.url_label': 'Личный сайт', 'profile.site.copy': 'Копировать', 'profile.site.copied': 'Скопировано', 'profile.site.visible_title': 'Что отображается на вашей странице', 'profile.site.visible.name': 'Имя и фото', 'profile.site.visible.bio': 'Биография', 'profile.site.visible.rating': 'Рейтинг и отзывы', 'profile.site.visible.portfolio': 'Портфолио / Карточки', 'profile.site.visible.contacts': 'Контактные данные', 'profile.site.visible.full_last_name': 'Фамилия полностью', 'profile.site.visible.services': 'Карточки услуг', 'profile.site.visible.reviews': 'Раздел с отзывами', 'profile.site.visible.status': 'Статус «Готов помочь»', 'profile.site.theme': 'Тема оформления', 'profile.site.theme.dark': 'Тёмная', 'profile.site.theme.light': 'Светлая', 'profile.site.slug_taken': 'Этот адрес уже занят', 'profile.site.stats.title': 'Аналитика сайта', 'profile.site.stats.days': 'последние 30 дней', 'profile.site.stats.views': 'Просмотры', 'profile.site.stats.unique': 'Уникальные посетители', 'profile.site.stats.messages': 'Сообщения', 'profile.site.stats.total_views': 'Просмотры', 'profile.site.stats.total_unique': 'Уник. посетители', 'profile.site.stats.total_messages': 'Сообщения', 'profile.site.stats.empty': 'Данных пока нет', 'profile.site.stats.loading': 'Загрузка аналитики...', 'profile.site.stats.no_slug': 'Укажите адрес сайта, чтобы видеть статистику', 'profile.site.edit_bio_hint': 'Биография и фото настраиваются во вкладке «Основное».', 'status.title': 'Статус', 'status.can_help_now_hint': 'Ваша карточка показывается выше в поиске', 'status.need_help_hint': 'Специалисты могут предложить вам помощь', 'profile.referral.title': 'Партнёрская программа', 'profile.referral.desc': 'Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.', 'profile.referral.link_label': 'Ваша реферальная ссылка', 'profile.referral.copy': 'Копировать', 'profile.referral.copied': 'Скопировано!', 'profile.referral.invited_count': 'успешных приглашений', 'profile.referral.no_code': 'Реферальный код недоступен.', 'notifications.title': 'Настройки уведомлений', 'notifications.email.new_tasks': 'Email о новых заказах', 'notifications.email.new_tasks.desc': 'Получать email, когда в ваших категориях публикуется новый заказ', 'notifications.messages.desc': 'Получать уведомление при новом входящем сообщении', 'notifications.saved': 'Настройки сохранены', 'notifications.plan_required': 'Недоступно в вашем тарифе', 'profile.tab.info': 'Основное', 'profile.tab.finance': 'Финансы', 'profile.tab.skills': 'Навыки', 'profile.tab.categories': 'Категории', 'profile.tab.geography': 'География', 'profile.specialist.categories': 'Категории работ', 'profile.specialist.categories.desc': 'Выберите категории, в которых вы работаете', 'profile.specialist.geography': 'Города покрытия', 'profile.specialist.geography.desc': 'Выберите города / районы, где вы работаете', 'profile.saving': 'Сохранение...', 'profile.upload.error': 'Ошибка загрузки фото', 'profile.saved': 'Сохранено', 'profile.tab.cards': 'Портфолио', 'profile.cards.count': 'Портфолио', 'profile.cards.add': 'Добавить портфолио', 'profile.cards.new_title': 'Название нового портфолио', 'profile.cards.placeholder': 'Например: Сантехника', 'profile.cards.create': 'Создать', 'profile.cards.cancel': 'Отмена', 'profile.cards.empty': 'У вас нет портфолио', 'profile.cards.create_first': 'Создать первое портфолио', 'profile.cards.delete_confirm': 'Удалить портфолио?', 'profile.card.tab.main': 'Основное', 'profile.card.tab.skills': 'Навыки', 'profile.card.tab.categories': 'Категории', 'profile.card.tab.geography': 'География', 'profile.card.tab.portfolio': 'Галерея', 'profile.card.active': 'Активна', 'profile.card.save': 'Сохранить', 'profile.card.saved': 'Сохранено', 'profile.card.delete': 'Удалить', 'profile.card.skill.add': 'Добавить навык', 'profile.card.photo.add': 'Добавить фото', 'profile.card.photo.uploading': 'Загрузка...', 'profile.card.photo.empty': 'Нет фотографий', 'profile.card.item.title': 'Заголовок', 'profile.card.item.desc': 'Описание', 'profile.card.item.save': 'Сохранить', 'profile.card.item.cancel': 'Отмена', 'profile.card.item.edit': 'Описание работы', 'profile.upgrade.cards_limit': 'Лимит портфолио исчерпан', 'profile.upgrade.plan': 'Текущий тариф:', 'profile.upgrade.contact': 'Обратитесь к администратору для смены тарифа', 'profile.upgrade.ok': 'Понятно', 'profile.plan.title': 'Тарифный план', 'profile.balance': 'Баланс', 'profile.balance.topup': 'Пополнить баланс', 'profile.balance.topup.title': 'Пополнить баланс', 'profile.balance.topup.amount': 'Сумма (в EUR)', 'profile.balance.topup.hint': 'Выберите сумму или введите вручную', 'profile.balance.topup.submit': 'Перейти к оплате', 'profile.balance.topup.loading': 'Перенаправление...', 'profile.balance.topup.error': 'Ошибка инициализации платежа. Попробуйте снова.', 'payment.success.title': 'Оплата прошла успешно!', 'payment.success.desc': 'Ваш баланс обновлён.', 'payment.cancelled.title': 'Оплата отменена', 'payment.cancelled.desc': 'Оплата была отменена. Средства не списаны.', 'payment.pending.title': 'Обрабатывается...', 'payment.pending.desc': 'Ваш платёж в обработке.', 'payment.back_to_profile': 'Вернуться в профиль', 'profile.plan.basic': 'Базовый (бесплатный)', 'profile.plan.contact_upgrade': 'Обратитесь к администратору для подключения тарифа', 'profile.plan.cards_up_to': 'Портфолио: до', 'profile.plan.cards_unlimited': 'Портфолио: безлимитно', 'profile.plan.tasks_up_to': 'Задач: до', 'profile.plan.offers_up_to': 'Откликов: до', 'profile.plan.valid_until': 'Действителен до', 'profile.plan.no_expiry': 'Бессрочно', // Create task 'create.error': 'Ошибка при публикации', // Tasks list extras 'tasks.category.general': 'Общее', 'tasks.budget.range': 'Диапазон:', 'tasks.budget.from': 'от', 'tasks.budget.to': 'до', 'tasks.filter.reset': 'Сбросить фильтры', 'tasks.load_more': 'Загрузить ещё', 'tasks.showing': 'Результатов:', 'tasks.field.budget': 'Бюджет, €', // Admin 'admin.title': 'Панель администратора', 'admin.tab.stats': 'Статистика', 'admin.tab.users': 'Пользователи', 'admin.tab.tasks': 'Задачи', 'admin.tab.reports': 'Жалобы', 'admin.stats.users': 'Пользователи', 'admin.stats.tasks': 'Задачи', 'admin.stats.offers': 'Предложения', 'admin.stats.reviews': 'Отзывы', 'admin.tasks.by_status': 'Задачи по статусу', 'admin.col.user': 'Пользователь', 'admin.col.email': 'Email', 'admin.col.role': 'Роль', 'admin.col.registered': 'Регистрация', 'admin.col.status': 'Статус', 'admin.col.title': 'Название', 'admin.col.budget': 'Бюджет', 'admin.col.created': 'Создано', 'admin.users.active': 'Активен', 'admin.users.inactive': 'Неактивен', 'admin.users.deactivate': 'Деактивировать', 'admin.users.activate': 'Активировать', 'admin.tasks.cancel': 'Отменить', 'admin.reports.none': 'Жалоб нет', 'admin.reports.reviewed': 'Рассмотрено', 'admin.reports.dismiss': 'Отклонить', 'admin.pagination.total': 'Всего', 'admin.users.role.change': 'Изменить роль', 'admin.users.search.placeholder': 'Поиск по имени или email...', 'admin.tasks.delete': 'Удалить', 'admin.tasks.delete.confirm': 'Удалить эту задачу навсегда?', 'admin.tasks.search.placeholder': 'Поиск по названию...', 'admin.col.customer': 'Заказчик', 'admin.col.reporter': 'Жалобщик', 'admin.col.target': 'Цель', 'admin.filter.all_roles': 'Все роли', 'admin.filter.all_statuses': 'Все статусы', 'admin.reports.target.task': 'Задача', 'admin.reports.target.user': 'Пользователь', 'admin.tab.categories': 'Категории', 'admin.tab.locations': 'Города и районы', 'admin.tab.logs': 'Логи', 'admin.tab.plans': 'Тарифы', 'admin.tab.settings': 'Настройки', 'admin.logs.subtab.ai': 'AI логи', 'admin.logs.subtab.activity': 'Активность', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Уведомления', 'admin.notif_logs.type': 'Тип', 'admin.notif_logs.title': 'Заголовок', 'admin.notif_logs.read': 'Прочитано', 'admin.notif_logs.empty': 'Логи уведомлений пусты', 'admin.stats.notif_chart_title': 'Уведомления по дням', 'admin.stats.notif_label': 'Уведомления', 'admin.stats.mail_chart_title': 'Email по дням', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Все', 'admin.stats.specialists': 'Исполнители', 'admin.col.plan': 'Тариф', 'admin.back_home': 'На главную', 'admin.plans.title': 'Тарифные пакеты', 'admin.plans.add': '+ Добавить тариф', 'admin.plans.empty': 'Тарифы не созданы', 'admin.plans.form.new': 'Новый тариф', 'admin.plans.form.edit': 'Редактировать тариф', 'admin.plans.form.name': 'Название', 'admin.plans.form.price': 'Цена (EUR)', 'admin.plans.form.old_price': 'Старая цена (EUR, необязательно)', 'admin.plans.form.max_offers': 'Макс. откликов (пусто = без лимита)', 'admin.plans.form.max_cards': 'Макс. портфолио (пусто = без лимита)', 'admin.plans.form.duration_days': 'Срок (дней, пусто = без истечения)', 'admin.plans.form.description': 'Описание', 'admin.plans.form.features': 'Возможности (по одной на строку)', 'admin.plans.form.notify': 'Уведомления о новых заказах', 'admin.plans.form.default': 'По умолчанию', 'admin.plans.form.active': 'Активен', 'admin.plans.form.order': 'Порядок', 'admin.plans.form.role': 'Роль', 'admin.plans.form.tier': 'Уровень', 'admin.plans.form.role.customer': 'Заказчик', 'admin.plans.form.role.specialist': 'Специалист', 'admin.plans.form.tier.free': 'Бесплатный', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Лимиты (пусто = без ограничений)', 'admin.plans.form.max_messages_day': 'Макс. сообщений/день', 'admin.plans.form.max_orders_day': 'Макс. заказов/день', 'admin.plans.form.max_skills': 'Макс. навыков', 'admin.plans.form.max_profiles': 'Макс. профилей', 'admin.plans.form.max_portfolio': 'Макс. элементов портфолио', 'admin.plans.form.section.boost': 'Множители & Буст', 'admin.plans.form.search_boost': 'Буст в поиске', 'admin.plans.form.offers_multiplier': 'Множитель откликов', 'admin.plans.form.section.contact': 'Права контактов', 'admin.plans.form.can_contact_free': 'Контакт с бесплатными пользователями', 'admin.plans.form.can_contact_pro': 'Контакт с Pro пользователями', 'admin.plans.form.can_contact_all': 'Контакт со всеми', 'admin.plans.form.can_show_contact': 'Показывать контакты', 'admin.plans.form.can_view_phone': 'Просмотр телефона', 'admin.plans.form.section.features': 'Возможности', 'admin.plans.form.upload_video': 'Загрузка видео', 'admin.plans.form.favorites': 'Избранное', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Знак верификации', 'admin.plans.form.highlighted_reviews': 'Выделенные отзывы', 'admin.plans.form.personal_site': 'Личный сайт', 'admin.plans.form.can_help_now': 'Статус «Могу помочь»', 'admin.plans.form.need_help': 'Статус «Нужна помощь»', 'admin.plans.form.auto_response': 'Автоответ', 'admin.plans.form.auto_match': 'Автоподбор', 'admin.plans.form.instant_dispatch_free': 'Мгновенная рассылка (бесплатно)', 'admin.plans.form.instant_dispatch_pro': 'Мгновенная рассылка (Pro)', 'admin.plans.badge.default': 'По умолчанию', 'admin.plans.badge.inactive': 'Неактивен', 'admin.plans.make_default': 'Сделать по умолчанию', 'admin.plans.tasks': 'Задач', 'admin.plans.offers': 'Откликов', 'admin.plans.cards': 'Портфолио', 'admin.plans.notify_tasks': 'Уведомления о заказах', 'admin.plans.delete.confirm': 'Удалить тариф', 'admin.activity.title': 'Журнал активности', 'admin.activity.event': 'Событие', 'admin.activity.all_events': 'Все события', 'admin.activity.from': 'От', 'admin.activity.to': 'До', 'admin.activity.reset': 'Сбросить', 'admin.activity.total': 'Всего', 'admin.activity.empty': 'Нет записей', 'admin.mail.event': 'Email событие', 'admin.mail.all_events': 'Все email события', 'admin.mail.from': 'От', 'admin.mail.to': 'До', 'admin.mail.reset': 'Сбросить', 'admin.mail.total': 'Всего', 'admin.mail.empty': 'Нет email логов', 'admin.mail.recipient': 'Получатель', 'admin.mail.provider': 'Провайдер', 'admin.mail.details': 'Детали', 'admin.mail.status': 'Статус', 'admin.mail.success': 'Успешно', 'admin.mail.failed': 'Ошибка', 'admin.event.email_sent': 'Email отправлен', 'admin.event.email_failed': 'Email не отправлен', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Тестовый email отправлен', 'admin.event.admin_email_test_failed': 'Тестовый email не отправлен', 'admin.logs.empty': 'Нет записей', 'admin.logs.date': 'Дата', 'admin.logs.provider': 'Провайдер', 'admin.logs.model': 'Модель', 'admin.logs.action': 'Действие', 'admin.logs.langs': 'Языки', 'admin.logs.in': 'Вход', 'admin.logs.out': 'Выход', 'admin.logs.total': 'Итого', 'admin.logs.ms': 'мс', 'admin.logs.status': 'Статус', 'admin.stats.activity_30d': 'Активность за 30 дней', 'admin.stats.tasks_label': 'Заявки', 'admin.stats.users_label': 'Пользователи', 'admin.stats.specialists_label': 'Исполнители', 'admin.stats.tokens_title': 'Расход токенов (по месяцам)', 'admin.stats.tokens_out': 'Исходящие', 'admin.stats.tokens_in': 'Входящие', 'admin.stats.tokens_out_label': 'Исходящие токены', 'admin.stats.tokens_in_label': 'Входящие токены', 'admin.stats.cost_label': 'Стоимость (USD)', 'admin.stats.tasks_by_status': 'Заявки по статусам', 'admin.task_status.open': 'Открытые', 'admin.task_status.in_progress': 'В работе', 'admin.task_status.completed': 'Завершённые', 'admin.task_status.cancelled': 'Отменённые', 'admin.task_status.draft': 'Черновики', 'admin.settings.tab.general': 'Общие', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Уведомления', 'admin.settings.tab.payment': 'Оплата', 'admin.settings.tab.referral': 'Реферальная', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Соцсети', 'admin.settings.socials.title': 'Ссылки на социальные сети', 'admin.settings.socials.hint': 'Заполненные ссылки отображаются в подвале сайта', 'admin.settings.seo.maintenance_label': 'Режим обслуживания', 'admin.settings.seo.maintenance_hint': 'Показывать страницу обслуживания всем посетителям', 'admin.settings.seo.indexing_label': 'Индексация поисковыми системами', 'admin.settings.seo.indexing_hint': 'Разрешить поисковым системам индексировать сайт', 'admin.settings.seo.head_scripts_label': 'Скрипты в (JS)', 'admin.settings.seo.head_scripts_hint': 'Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)', 'admin.settings.seo.site_title_label': 'Заголовок сайта', 'admin.settings.seo.site_description_label': 'Описание сайта (meta description)', 'admin.settings.referral.title': 'Партнёрская программа', 'admin.settings.referral.hint': 'Награждайте пользователей, приводящих новых участников.', 'admin.settings.referral.enabled_label': 'Включено', 'admin.settings.referral.enabled_hint': 'Включить / отключить выдачу наград', 'admin.settings.referral.customer_section': 'Для клиентов', 'admin.settings.referral.specialist_section': 'Для специалистов', 'admin.settings.referral.plan_label': 'Тарифный план за реферала', 'admin.settings.referral.no_plan': '— без плана —', 'admin.settings.referral.plan_hint': 'Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.', 'admin.settings.referral.days_label': 'Дней награды', 'admin.settings.referral.days_hint': 'Количество дней, добавляемых к сроку действия плана.', 'admin.settings.general.title': 'Общие настройки', 'admin.settings.general.site_name': 'Название сайта', 'admin.settings.general.site_url': 'URL сайта', 'admin.settings.general.contact_email': 'Email для связи', 'admin.settings.general.support_phone': 'Телефон поддержки', 'admin.settings.smtp.title': 'Настройки SMTP сервера', 'admin.settings.smtp.hint': 'Используется для отправки email-уведомлений.', 'admin.settings.smtp.host': 'SMTP Хост', 'admin.settings.smtp.port': 'Порт', 'admin.settings.smtp.encryption': 'Шифрование', 'admin.settings.smtp.enc.none': 'Нет', 'admin.settings.smtp.enc.tls': 'STARTTLS (порт 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (порт 465)', 'admin.settings.smtp.username': 'Имя пользователя', 'admin.settings.smtp.password': 'Пароль / App Password', 'admin.settings.smtp.from_name': 'Имя отправителя', 'admin.settings.smtp.from_email': 'Email отправителя', 'admin.settings.smtp.test': 'Отправить тестовый email', 'admin.settings.smtp.sending': 'Отправка...', 'admin.settings.payment.hint': 'Данные для подключения к ePay Piraeus Bank.', 'admin.settings.env.test': 'Тест (sandbox)', 'admin.settings.env.prod': 'Боевой режим', 'admin.settings.env.label': 'Среда', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Активен', 'admin.settings.saving': 'Сохранение...', 'admin.settings.saved': 'Сохранено', 'admin.notif.vars_hint': 'Доступные переменные в шаблонах', 'admin.notif.tmpl.not_set': 'Шаблон не настроен', 'admin.notif.tmpl.subject_label': 'Тема письма', 'admin.notif.tmpl.body_label': 'Текст письма (HTML)', 'admin.notif.tmpl.save': 'Сохранить', 'admin.notif.tmpl.close': 'Закрыть', 'admin.notif.tmpl.translate': 'Авто-перевод на другие языки', 'admin.notif.tmpl.translating': 'Перевод...', 'admin.notif.tmpl.saving': 'Сохранение...', 'admin.notif.email_verification': 'Подтверждение email адреса', 'admin.notif.registration_success': 'Успешная регистрация', 'admin.notif.password_reset': 'Восстановление пароля', 'admin.notif.new_offer': 'Новое предложение', 'admin.notif.new_task': 'Новая задача', 'admin.notif.offer_accepted': 'Предложение принято', 'admin.notif.new_message': 'Новое сообщение', 'admin.notif.offer_declined': 'Отклонение предложения', 'admin.notif.offer_other_accepted': 'Выбран другой исполнитель', 'admin.notif.task_updated': 'Изменение задания', 'admin.notif.deadline_reminder': 'Напоминание о дедлайне', 'admin.notif.task_archived': 'Автоснятие задания', 'admin.notif.referral_reward': 'Реферальная награда', // Шаблоны email для тарифов 'admin.email_template.plan_activated': 'Тарифы — активация тарифа', 'admin.email_template.plan_upgraded': 'Тарифы — повышение тарифа', 'admin.email_template.plan_downgrade_scheduled': 'Тарифы — запланированное понижение', 'admin.email_template.plan_downgrade_applied': 'Тарифы — применение понижения', 'admin.email_template.plan_renewal_reminder': 'Тарифы — напоминание о продлении', 'admin.email_template.plan_insufficient_funds': 'Тарифы — нехватка средств', // Модальное окно подтверждения тарифа 'pricing.confirm.title': 'Подтвердите выбор тарифа', 'pricing.confirm.plan': 'Тариф', 'pricing.confirm.prorated': 'Зачёт остатка', 'pricing.confirm.effective_price': 'К оплате', 'pricing.confirm.your_balance': 'Ваш баланс', 'pricing.confirm.downgrade_info': 'Переход на новый тариф произойдёт автоматически после окончания текущего периода.', 'pricing.confirm.insufficient': 'Недостаточно средств на балансе.', 'pricing.confirm.top_up': 'Пополнить', 'pricing.confirm.schedule_downgrade': 'Запланировать переход', 'pricing.confirm.pay': 'Оплатить', 'admin.user_edit.title': 'Редактирование пользователя', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email подтверждён', 'admin.user_edit.email_not_verified': 'Email не подтверждён', 'admin.user_edit.verify_email_btn': 'Подтвердить вручную', 'admin.user_edit.verify_email_done': 'Email подтверждён!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Регистрация', 'admin.user_edit.last_seen': 'Последний визит', 'admin.user_edit.lang': 'Язык', 'admin.user_edit.first_name': 'Имя', 'admin.user_edit.last_name': 'Фамилия', 'admin.user_edit.phone': 'Телефон', 'admin.user_edit.bio': 'О себе', 'admin.user_edit.role': 'Роль', 'admin.user_edit.plan': 'Тариф', 'admin.user_edit.no_plan': '— Без тарифа —', 'admin.user_edit.active': 'Активный аккаунт', 'admin.user_edit.balance': 'Баланс (EUR)', 'admin.user_edit.skills': 'Навыки', 'admin.user_edit.tab.profile': 'Профиль', 'admin.user_edit.tab.account': 'Аккаунт', 'admin.user_edit.tab.balance': 'Баланс', 'admin.user_edit.tab.settings': 'Настройки', 'admin.user_edit.tab.specialist': 'Портфолио', 'admin.user_edit.tab.site': 'Сайт', 'admin.user_edit.plan_expires': 'Тариф истекает', 'admin.user_edit.interface_lang': 'Язык интерфейса', 'admin.user_edit.comm_languages': 'Языки общения', 'admin.user_edit.personal_site_slug': 'Персональная страница', 'admin.user_edit.show_contact_info': 'Показывать контакты', 'admin.user_edit.show_contact_info.hint': 'Видно заказчикам', 'admin.user_edit.notify_new_tasks': 'Уведомлять о новых задачах', 'admin.user_edit.notify_new_tasks.hint': 'Push и email уведомления', 'admin.user_edit.notif_messages': 'Уведомления о сообщениях', 'admin.user_edit.notif_messages.hint': 'Новые сообщения в чате', 'admin.user_edit.site_settings': 'Настройки персональной страницы', 'admin.user_edit.categories': 'Категории услуг', 'admin.user_edit.locations': 'Районы обслуживания', 'admin.user_edit.skill_placeholder': 'Новый навык...', 'admin.user_edit.add_category': '— Выберите категорию —', 'admin.user_edit.add_location': '— Выберите район —', 'admin.user_edit.specialist_cards': 'Портфолио специалиста', 'admin.user_edit.no_cards': 'Портфолио не найдено', 'admin.user_edit.card_title': 'Заголовок портфолио', 'admin.user_edit.card_description': 'Описание', 'admin.balance.topup.btn': 'Пополнить', 'admin.balance.withdraw.btn': 'Списать', 'admin.balance.modal_hint': 'Изменения применяются сразу и фиксируются в истории', 'admin.balance.topup.title': 'Пополнение баланса', 'admin.balance.topup.amount': 'Сумма', 'admin.balance.topup.description': 'Комментарий', 'admin.balance.topup.description.placeholder': 'Например: бонус или ручное пополнение', 'admin.balance.topup.submit': 'Пополнить баланс', 'admin.balance.withdraw.title': 'Снятие баланса', 'admin.balance.withdraw.amount': 'Сумма', 'admin.balance.withdraw.description': 'Комментарий', 'admin.balance.withdraw.description.placeholder': 'Например: возврат или ручное списание', 'admin.balance.withdraw.submit': 'Списать баланс', 'admin.user_edit.role.customer': 'Заказчик', 'admin.user_edit.role.specialist': 'Исполнитель', 'admin.user_edit.role.admin': 'Администратор', 'common.refresh': 'Обновить', 'common.back_home': 'На главную', 'admin.loc.hint': 'Управление городами и районами', 'admin.loc.add_city': 'Новый город', 'admin.loc.add_district': 'Добавить район', 'admin.loc.new': 'Новая локация', 'admin.loc.edit': 'Редактировать локацию', 'admin.loc.district': 'район', 'admin.loc.empty': 'Нет локаций', 'admin.loc.delete.confirm': 'Удалить локацию? Все районы также будут удалены.', 'admin.cat.add_root': 'Новая категория', 'admin.cat.add_sub': 'Подкатегория', 'admin.cat.edit': 'Редактировать', 'admin.cat.delete': 'Удалить', 'admin.cat.delete.confirm': 'Удалить категорию? Все подкатегории также будут удалены.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Иконка', 'admin.cat.name_el': 'Греческий', 'admin.cat.name_en': 'Английский', 'admin.cat.name_ru': 'Русский', 'admin.cat.order': 'Порядок', 'admin.cat.active': 'Активна', 'admin.cat.parent': 'Родительская категория', 'admin.cat.no_parent': 'Верхний уровень', 'admin.cat.save': 'Сохранить', 'admin.cat.cancel': 'Отмена', 'admin.cat.empty': 'Нет категорий', 'admin.cat.hint': 'Управление категориями с многоуровневой иерархией', 'admin.cat.new': 'Новая категория', 'admin.cat.subcategory': 'подкатегория', 'admin.cat.add_child': 'Добавить подкатегорию', 'admin.cat.inactive': 'Неактивна', 'admin.event.user_login': 'Вход', 'admin.event.user_register': 'Регистрация', 'admin.event.admin_user_deactivate': 'Блокировка юзера', 'admin.event.admin_user_activate': 'Разблокировка юзера', 'admin.event.admin_user_role_changed': 'Смена роли', 'admin.event.admin_task_cancelled': 'Отмена задачи', 'admin.event.admin_task_deleted': 'Удаление задачи', 'admin.event.admin_report_reviewed': 'Жалоба рассмотрена', 'admin.event.admin_report_dismissed': 'Жалоба отклонена', 'admin.event.task_created': 'Создана задача', // User status 'user.online': 'Онлайн', 'user.seen_minutes': 'был здесь {n} мин назад', 'user.seen_hours': 'был здесь {n} ч назад', 'user.seen_yesterday': 'был здесь вчера', 'user.seen_days': 'был здесь {n} дн назад', // Specialists 'specialists.title': 'Специалисты', 'specialists.search': 'Поиск специалиста...', 'specialists.search.btn': 'Поиск', 'specialists.empty': 'Специалисты не найдены', 'specialists.no_bio': 'Без описания', 'specialists.view': 'Смотреть профиль', 'specialists.reviews': 'отзывов', 'specialist.favorite': 'Добавить в избранное', 'specialist.unfavorite': 'Убрать из избранного', 'specialist.site_link': 'Личный сайт', 'favorites.specialists.title': 'Избранные специалисты', 'favorites.specialists.empty': 'Вы ещё не добавили специалистов в избранное', 'nav.favorites': 'Избранное', 'nav.schedule': 'Расписание', 'nav.find_tasks': 'Поиск заказов', 'schedule.title': 'Моё расписание', 'schedule.subtitle': 'Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность', 'schedule.available': 'Свободен', 'schedule.busy': 'Занят', 'schedule.unset': 'Не указано', 'schedule.click_hint': '← клик меняет статус по кругу', 'schedule.range_mode': 'Выделить диапазон', 'schedule.range_from': 'С {date} — выберите конечную дату', 'schedule.click_to_set': 'Нажмите чтобы отметить', 'schedule.free': 'свободно', 'schedule.busy_count': 'занято', 'schedule.free_days': 'свободных дней', 'schedule.googleCalendar': 'Google Календарь', 'schedule.connectGoogle': 'Подключить Google Календарь', 'schedule.disconnectGoogle': 'Отключить', 'schedule.connectedAs': 'Подключено как', 'schedule.importFromGoogle': 'Синхр. из Google', 'schedule.gcalConnected': '\u2713 Google Календарь подключён', 'schedule.gcalError': 'Ошибка подключения Google Календарь', 'schedule.gcalImportDone': 'Импортировано {n} дней из Google Календарь', 'schedule.gcalAutoSyncNote': 'Изменения доступности автоматически отправляются в Google Календарь', 'schedule.gcalConnectDesc': 'Подключите Google Календарь для автоматической синхронизации расписания', 'schedule.gcalDisconnectConfirm': 'Отключить Google Календарь?', 'find_tasks.title': 'Поиск заказов', 'find_tasks.for_me': 'Для меня', 'find_tasks.all': 'Все заказы', 'find_tasks.by_category': 'По категориям', 'find_tasks.list': 'Списком', 'find_tasks.already_offered': 'Предложение отправлено', 'find_tasks.offer_now': 'Откликнуться', 'find_tasks.empty_for_me': 'Нет заказов в ваших категориях', 'find_tasks.banner_hint': 'Найдите заказы по категориям вашего портфолио', 'find_tasks.no_cards': 'Создайте портфолио специалиста, чтобы видеть подходящие заказы', 'find_tasks.add_card': 'Создать портфолио', 'find_tasks.search': 'Поиск заказов...', 'find_tasks.tasks_count': 'заданий', 'footer.tagline': 'Платформа задач для Греции', 'footer.rights': 'Все права защищены.', // App download section 'app.download_title': 'Скачайте мобильное приложение CanHelp', 'app.download_desc': 'Всё CanHelp — всегда под рукой. Доступно для Android и iOS.', // Nav 'nav.pricing': 'Тарифы', // Pricing page 'pricing.title': 'Тарифы', 'pricing.subtitle': 'Выберите подходящий план', 'pricing.role.customer': 'Заказчик', 'pricing.role.specialist': 'Специалист', 'pricing.free': 'Бесплатно', 'pricing.per_month': 'мес', 'pricing.duration': 'Срок', 'pricing.days': 'дн.', 'pricing.current_plan': 'Ваш план', 'pricing.popular': 'Популярный', 'pricing.choose': 'Выбрать', 'pricing.your_plan': 'Активный план', 'pricing.free_default': 'По умолчанию', 'pricing.compare': 'Сравнение функций', 'pricing.feature': 'Функция', 'pricing.faq_note': 'Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.', 'pricing.feat.messages': 'Сообщений / день', 'pricing.feat.orders': 'Заказов / день', 'pricing.feat.contact_all': 'Связь со всеми', 'pricing.feat.view_phone': 'Просмотр телефона', 'pricing.feat.show_contact': 'Показывать контакты', 'pricing.feat.favorites': 'Избранное', 'pricing.feat.verified_badge': 'Верифицированный бейдж', 'pricing.feat.google_calendar': 'Google Календарь', 'pricing.feat.personal_site': 'Персональный сайт', 'pricing.feat.auto_response': 'Авто-ответ', 'pricing.feat.auto_match': 'Авто-подбор', 'pricing.feat.highlighted_reviews': 'Выделенные отзывы', 'pricing.feat.portfolio': 'Элементов портфолио', 'pricing.feat.cards': 'Карточки специалиста', 'pricing.feat.notify_tasks': 'Уведомления о новых задачах', 'pricing.feat.video': 'Видео в портфолио', // Upgrade prompt 'upgrade.available_in': 'Доступно в', 'upgrade.cta': 'Улучшить', // Dashboard plan block 'dashboard.plan.title': 'Мой план', 'dashboard.plan.expires': 'Истекает через {n} дней', 'dashboard.plan.upgrade': 'Улучшить план', 'dashboard.plan.no_plan': 'Бесплатный план', 'dashboard.plan.messages': 'Сообщений сегодня', 'dashboard.plan.orders': 'Заказов сегодня', 'dashboard.plan.limits': 'Дневные лимиты', 'dashboard.plan.features': 'Функции', 'dashboard.plan.stats': 'Статистика', 'dashboard.stats.cards': 'Портфолио', 'dashboard.stats.maxCards': 'Макс. портфолио', 'dashboard.stats.portfolioItems': 'Элементы портфолио', 'dashboard.stats.maxPortfolioItems': 'Макс. элементы', 'dashboard.stats.activeOffers': 'Активные отклики', 'dashboard.stats.reviewsReceived': 'Отзывы', 'dashboard.stats.activeTasks': 'Активные задачи', 'dashboard.stats.completedTasks': 'Завершённые', 'status.need_help': 'Нужна помощь', 'status.active': 'Активен', 'status.toggle_on': 'Включить', 'status.toggle_off': 'Выключить', // FOMO 'fomo.missed_orders': 'Пропущено {n} заказов', 'fomo.missed_value': 'На сумму €{v}', 'fomo.upgrade_hint': 'Улучшите план — получайте больше заказов', 'fomo.conversion': 'Конверсия задач', 'fomo.active': 'Активные', 'fomo.with_offers': 'С офертами', 'fomo.completed': 'Завершённые', 'fomo.already_offered': '{n} специалистов уже откликнулись', 'fomo.specialist_missed': 'Вы пропустили {n} заказов', 'fomo.top_categories': 'Категории', 'fomo.offers_received': 'предложений получено', 'fomo.avg_offers': 'В среднем {n}/задача', 'fomo.completion_rate': 'завершено', // Task auto-match 'task.auto_match': 'Авто-матч', 'task.auto_match_results': 'Топ специалисты', 'task.no_offer_yet': 'Вы ещё не отправили предложение', 'task.make_offer': 'Отправить предложение', 'auto_response.title': 'Авто-ответ', 'auto_response.enabled': 'Включить авто-ответ', 'auto_response.min_budget': 'Мин. бюджет', 'auto_response.max_budget': 'Макс. бюджет', 'auto_response.default_price': 'Цена по умолчанию', 'auto_response.default_message': 'Сообщение по умолчанию', 'auto_response.max_per_day': 'Макс. авто-офертов в день', 'auto_response.save': 'Сохранить', 'auto_response.saved': 'Сохранено', 'auto_response.categories': 'Категории', 'auto_response.locations': 'Локации', // Personal site 'profile.personal_site': 'Персональный сайт', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Только латинские буквы, цифры, - и _', 'profile.site_open': 'Открыть сайт', 'profile.site_preview': 'Ваш сайт', 'profile.show_contact': 'Показывать контакты', 'profile.show_contact_hint': 'Заказчики с Pro/Ultimate-планом увидят ваш телефон', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Календарь требует план Pro или Ultimate', // Chat limits 'chat.limit_warning': 'Осталось {n} сообщений сегодня', 'chat.limit_reached': 'Лимит сообщений исчерпан. Улучшите план', 'chat.upgrade': 'Улучшить', // Site page 'site.member_since': 'С нами с', 'site.rating': 'Рейтинг', 'site.completed_tasks': 'Выполнено', 'site.languages': 'Языков', 'site.photos': 'фото', 'site.contact_form': 'Связаться', 'site.contact_sent': 'Сообщение отправлено!', 'site.contact_sent_desc': 'Специалист свяжется с вами в ближайшее время', 'site.contact_name': 'Имя', 'site.contact_name_ph': 'Ваше имя', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Сообщение', 'site.contact_message_ph': 'Опишите вашу задачу...', 'site.contact_send': 'Отправить', 'site.share': 'Поделиться', 'site.speaks_languages': 'Говорит на языках', 'site.message_sent': 'Сообщение отправлено!', 'site.message_sent_desc': 'Специалист получит его в чате', 'site.message_placeholder': 'Напишите сообщение...', 'site.write_to_chat': 'Написать в чат', 'site.auth_required_title': 'Нужна авторизация', 'site.auth_required_desc': 'Чтобы написать в чат, необходимо войти в аккаунт CanHelp.', 'site.auth_login_btn': 'Войти в аккаунт', 'site.auth_contact_form_btn': 'Написать через форму обратной связи', 'specialist.services': 'Услуги', 'portfolio.title': 'Портфолио', 'status.can_help_now': 'Готов помочь', 'common.not_found': 'Страница не найдена', 'common.anonymous': 'Анонимно', 'specialist_setup.page_title': 'Настройка профиля специалиста', 'specialist_setup.step_of': 'Шаг {current} из {total}', 'specialist_setup.next': 'Далее', 'specialist_setup.back': 'Назад', 'specialist_setup.skip': 'Пропустить', 'specialist_setup.finish': 'Завершить', 'specialist_setup.go_to_profile': 'Перейти в профиль', 'specialist_setup.browse_tasks': 'Найти задачи', 'specialist_setup.step1.title': 'Добро пожаловать!', 'specialist_setup.step1.subtitle': 'Давайте настроим ваш профиль', 'specialist_setup.step1.desc': 'Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.', 'specialist_setup.step1.what_next': 'Что мы сделаем:', 'specialist_setup.step1.item1': 'Заполним основную информацию', 'specialist_setup.step1.item2': 'Создадим карточку услуги', 'specialist_setup.step1.item3': 'Добавим навыки и категории', 'specialist_setup.step1.item4': 'Выберем географию обслуживания', 'specialist_setup.step1.item5': 'Загрузим фото портфолио', 'specialist_setup.step2.title': 'Базовый профиль', 'specialist_setup.step2.subtitle': 'Расскажите о себе', 'specialist_setup.step2.bio_label': 'О себе', 'specialist_setup.step2.bio_placeholder': 'Опишите ваш опыт, услуги которые вы предлагаете...', 'specialist_setup.step2.phone_label': 'Телефон', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Фото профиля', 'specialist_setup.step2.photo_btn': 'Загрузить фото', 'specialist_setup.step2.photo_uploading': 'Загрузка...', 'specialist_setup.step2.photo_hint': 'Отображается в вашем профиле', 'specialist_setup.step3.title': 'Карточка услуги', 'specialist_setup.step3.subtitle': 'Создайте вашу первую карточку услуги', 'specialist_setup.step3.title_label': 'Название карточки', 'specialist_setup.step3.title_placeholder': 'Напр. Сантехник, Электрик, Уборка...', 'specialist_setup.step3.desc_label': 'Описание', 'specialist_setup.step3.desc_placeholder': 'Подробно опишите что вы предлагаете, опыт, преимущества...', 'specialist_setup.step3.title_required': 'Название обязательно', 'specialist_setup.step4.title': 'Навыки и категории', 'specialist_setup.step4.subtitle': 'Добавьте навыки и выберите категории', 'specialist_setup.step4.skills_label': 'Навыки', 'specialist_setup.step4.skills_placeholder': 'Напр. Монтаж труб...', 'specialist_setup.step4.skills_add': 'Добавить', 'specialist_setup.step4.categories_label': 'Категории', 'specialist_setup.step5.title': 'География обслуживания', 'specialist_setup.step5.subtitle': 'Где вы оказываете услуги?', 'specialist_setup.step5.hint': 'Выберите города или конкретные районы', 'specialist_setup.done.title': 'Ваш профиль готов!', 'specialist_setup.done.subtitle': 'Поздравляем! Профиль настроен', 'specialist_setup.done.desc': 'Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам.' } }; function getTranslations(locale) { const t = translations[locale] ?? translations.el; return (key, fallback)=>t[key] ?? translations.el[key] ?? fallback ?? key; } /***/ }), /***/ 13260: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CI: () => (/* binding */ signOut), /* harmony export */ Hh: () => (/* binding */ signUp), /* harmony export */ Jv: () => (/* binding */ signIn), /* harmony export */ wV: () => (/* binding */ useSession), /* harmony export */ yK: () => (/* binding */ authClient) /* harmony export */ }); /* harmony import */ var better_auth_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(69183); const API_URL = "https://api.canhelp.gr" || 0; const authClient = (0,better_auth_react__WEBPACK_IMPORTED_MODULE_0__/* .createAuthClient */ .M)({ baseURL: API_URL }); const { signIn, signOut, signUp, useSession } = authClient; /***/ }), /***/ 14276: /***/ (() => { /***/ }), /***/ 15043: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // EXPORTS __webpack_require__.d(__webpack_exports__, { Footer: () => (/* binding */ Footer) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ./src/context/locale.tsx var locale = __webpack_require__(96484); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); ;// ./src/components/SocialIcons.tsx const ICONS = [ { key: 'telegram', label: 'Telegram', hoverClass: 'hover:text-sky-500', svg: '' }, { key: 'instagram', label: 'Instagram', hoverClass: 'hover:text-pink-500', svg: '' }, { key: 'facebook', label: 'Facebook', hoverClass: 'hover:text-blue-600', svg: '' }, { key: 'twitter', label: 'X', hoverClass: 'hover:text-gray-900', svg: '' }, { key: 'youtube', label: 'YouTube', hoverClass: 'hover:text-red-600', svg: '' }, { key: 'tiktok', label: 'TikTok', hoverClass: 'hover:text-black', svg: '' }, { key: 'whatsapp', label: 'WhatsApp', hoverClass: 'hover:text-green-500', svg: '' }, { key: 'viber', label: 'Viber', hoverClass: 'hover:text-purple-600', svg: '' } ]; function SocialIcons({ className = '', links }) { const active = ICONS.filter(({ key })=>links?.[key]); if (active.length === 0) return null; return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: `flex gap-4 flex-wrap ${className}`, children: active.map(({ key, label, hoverClass, svg })=>/*#__PURE__*/ (0,react_jsx_runtime.jsx)("a", { href: links[key], target: "_blank", rel: "noopener noreferrer", "aria-label": label, className: `text-gray-500 transition ${hoverClass}`, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", dangerouslySetInnerHTML: { __html: svg } }) }, key)) }); } ;// ./src/components/Footer.tsx /* __next_internal_client_entry_do_not_use__ Footer auto */ const API = "https://api.canhelp.gr" || 0; function Footer() { const { t } = (0,locale/* useLocale */.Y)(); const year = new Date().getFullYear(); const [socialLinks, setSocialLinks] = (0,react.useState)({}); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ fetch(`${API}/api/admin/social-public`).then((r)=>r.ok ? r.json() : {}).then((kv)=>{ const links = {}; for (const [k, v] of Object.entries(kv)){ if (v) links[k.replace('social.', '')] = v; } setSocialLinks(links); }).catch(()=>{}); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsx)("footer", { className: "bg-white border-t border-gray-200 mt-16", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex flex-col md:flex-row justify-between items-start gap-10", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[200px] flex flex-col items-start", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "logo-text text-3xl text-blue-700 font-bold mb-2", children: "CanHelp" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-base text-gray-600 mb-4", children: t('footer.slogan') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.links') }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("ul", { className: "space-y-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/", className: "hover:text-blue-600 transition", children: t('nav.home') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks", className: "hover:text-blue-600 transition", children: t('nav.tasks') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/become-specialist", className: "hover:text-blue-600 transition", children: t('nav.specialists') }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("li", { children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/pricing", className: "hover:text-blue-600 transition", children: t('nav.pricing') }) }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-[180px]", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-blue-900 mb-3", children: t('footer.socials') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-gray-500 text-sm mb-2", children: "info@canhelp.gr" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)(SocialIcons, { className: "mt-2", links: socialLinks }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm", children: [ "\xa9 ", year, " CanHelp. ", t('footer.rights') ] }) ] }) }); } /***/ }), /***/ 20138: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider) /* harmony export */ }); /* unused harmony export useLocale */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const LocaleProvider = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "LocaleProvider", );const useLocale = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "useLocale", ); /***/ }), /***/ 21046: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* __next_internal_client_entry_do_not_use__ ScrollToTopButton auto */ function ScrollToTopButton() { const [visible, setVisible] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const onScroll = ()=>{ setVisible(window.scrollY > 200); }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", { className: `scroll-to-top-btn${visible ? ' visible' : ''}`, "aria-label": "Наверх", onClick: ()=>window.scrollTo({ top: 0, behavior: 'smooth' }), children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("path", { d: "M10 16V4M10 4L4 10M10 4L16 10", stroke: "white", strokeWidth: "2.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }); } /***/ }), /***/ 30460: /***/ (() => { /* (ignored) */ /***/ }), /***/ 32948: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const ScrollToTopButton = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx", "ScrollToTopButton", ); /***/ }), /***/ 33506: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NotFound) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); function NotFound() { return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", { className: "min-h-screen flex items-center justify-center text-center px-4", children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", { children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("h1", { className: "text-8xl font-bold text-blue-600 mb-4", children: "404" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", { className: "text-xl text-gray-700 mb-6", children: "Η σελίδα δεν βρέθηκε" }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)((next_link__WEBPACK_IMPORTED_MODULE_1___default()), { href: "/", className: "bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700", children: "Επιστροφή στην Αρχική" }) ] }) }); } /***/ }), /***/ 39348: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Footer: () => (/* binding */ Footer) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const Footer = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Footer.tsx", "Footer", ); /***/ }), /***/ 47570: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ RootLayout), /* harmony export */ generateMetadata: () => (/* binding */ generateMetadata) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56057); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14276); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_globals_css__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _components_Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67674); /* harmony import */ var _components_Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39348); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(20138); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1697); /* harmony import */ var _components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32948); async function fetchSeoSettings() { try { const apiBase = "https://api.canhelp.gr" || 0; const res = await fetch(`${apiBase}/api/admin/seo-public`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return res.json(); } catch { return {}; } } async function generateMetadata() { const seo = await fetchSeoSettings(); return { title: seo['seo.siteTitle'] || 'CanHelp — Βρες ειδικό για κάθε δουλειά', description: seo['seo.siteDescription'] || 'Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.', keywords: 'εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά', robots: seo['seo.indexingEnabled'] === 'false' ? 'noindex, nofollow' : undefined }; } async function RootLayout({ children }) { const cookieStore = await (0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .cookies */ .UL)(); const headerStore = await (0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .headers */ .b3)(); const pathname = headerStore.get('x-pathname') ?? ''; const isStandalone = pathname.startsWith('/site/'); const rawLocale = cookieStore.get('canhelp_locale')?.value; const locales = [ 'el', 'en', 'ru' ]; const initialLocale = locales.includes(rawLocale) ? rawLocale : 'el'; const initialLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const seo = await fetchSeoSettings(); const headScripts = seo['seo.headScripts'] ?? ''; const parsedScripts = []; if (headScripts.trim()) { const re = /]*)>([\s\S]*?)<\/script>|]*)\/>/gi; let m; while((m = re.exec(headScripts)) !== null){ const attrs = m[1] ?? m[3] ?? ''; const inline = (m[2] ?? '').trim(); const srcMatch = attrs.match(/src=["']([^"']+)["']/); parsedScripts.push({ src: srcMatch?.[1], async: /\basync\b/i.test(attrs), defer: /\bdefer\b/i.test(attrs), inline: inline || undefined }); } } return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("html", { lang: initialLocale, children: [ /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("head", { children: parsedScripts.map((s, i)=>{ if (s.src) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("script", { src: s.src, async: s.async, defer: s.defer }, i); if (s.inline) return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("script", { dangerouslySetInnerHTML: { __html: s.inline } }, i); return null; }) }), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("body", { children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_context_locale__WEBPACK_IMPORTED_MODULE_5__.LocaleProvider, { initialLocale: initialLocale, children: /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_context_location__WEBPACK_IMPORTED_MODULE_6__.LocationProvider, { initialSlug: initialLocation, children: [ !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_Header__WEBPACK_IMPORTED_MODULE_3__.Header, {}), /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("main", { className: "min-h-screen", children: children }), !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__.ScrollToTopButton, {}), !isStandalone && /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_components_Footer__WEBPACK_IMPORTED_MODULE_4__.Footer, {}) ] }) }) }) ] }); } /***/ }), /***/ 48178: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ E: () => (/* binding */ shortName), /* harmony export */ H: () => (/* binding */ formatShortName) /* harmony export */ }); /** * Shortens the last name to first letter + period. * "Иван Петров" → "Иван П." * Works with a pre-composed full name string. */ function shortName(fullName) { if (!fullName?.trim()) return '—'; const parts = fullName.trim().split(/\s+/); if (parts.length < 2 || !parts[1]) return parts[0]; return `${parts[0]} ${parts[1][0].toUpperCase()}.`; } /** * Formats separate firstName + lastName fields, shortening the last name. * Falls back to parsing fullName if firstName is not available. */ function formatShortName(firstName, lastName, fallbackName) { if (firstName?.trim()) { const l = lastName?.trim(); return l ? `${firstName.trim()} ${l[0].toUpperCase()}.` : firstName.trim(); } return shortName(fallbackName); } /***/ }), /***/ 49046: /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 94496, 23)); /***/ }), /***/ 56003: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider), /* harmony export */ z: () => (/* binding */ useLocation) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91864); /* __next_internal_client_entry_do_not_use__ LocationProvider,useLocation auto */ const LocationContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({ locationSlug: '', locationTree: [], locationLoading: true, setLocation: ()=>{}, getLabel: ()=>'' }); function readCookieLocation() { if (typeof document === 'undefined') return ''; const match = document.cookie.match(/(?:^|;\s*)canhelp_location=([^;]+)/); return match?.[1] ? decodeURIComponent(match[1]) : ''; } function LocationProvider({ children, initialSlug = '' }) { const [locationSlug, setLocationSlug] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialSlug); const [locationTree, setLocationTree] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)([]); const [locationLoading, setLocationLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(true); // Sync from cookie on client mount process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const cookieSlug = readCookieLocation(); setLocationSlug(cookieSlug); }, []); // Load location tree once process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ (0,_lib_api__WEBPACK_IMPORTED_MODULE_2__/* .getLocations */ .Vs)().then((tree)=>setLocationTree(tree)).catch(()=>{}).finally(()=>setLocationLoading(false)); }, []); const setLocation = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((slug)=>{ setLocationSlug(slug); const encoded = encodeURIComponent(slug); document.cookie = `canhelp_location=${encoded}; path=/; max-age=31536000; SameSite=Lax`; }, []); const getLabel = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((locale)=>{ if (!locationSlug) return ''; for (const city of locationTree){ if (city.slug === locationSlug) return city.names[locale] ?? city.names.el; for (const d of city.children ?? []){ if (d.slug === locationSlug) return d.names[locale] ?? d.names.el; } } return locationSlug; }, [ locationSlug, locationTree ]); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(LocationContext.Provider, { value: { locationSlug, locationTree, locationLoading, setLocation, getLabel }, children: children }); } function useLocation() { return (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(LocationContext); } /***/ }), /***/ 58719: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // EXPORTS __webpack_require__.d(__webpack_exports__, { Header: () => (/* binding */ Header) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); // EXTERNAL MODULE: ../../node_modules/next/dist/api/navigation.js var navigation = __webpack_require__(71159); // EXTERNAL MODULE: ./src/lib/auth.ts var auth = __webpack_require__(13260); // EXTERNAL MODULE: ./src/context/locale.tsx var context_locale = __webpack_require__(96484); // EXTERNAL MODULE: ./src/lib/formatName.ts var formatName = __webpack_require__(48178); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ./src/lib/translations.ts var translations = __webpack_require__(12998); ;// ./src/components/LanguageSwitcher.tsx /* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ function LanguageSwitcher() { const { locale, setLocale } = (0,context_locale/* useLocale */.Y)(); const [open, setOpen] = (0,react.useState)(false); const ref = (0,react.useRef)(null); const current = translations/* LOCALES */.YZ.find((l)=>l.code === locale) ?? translations/* LOCALES */.YZ[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: translations/* LOCALES */.YZ.map((loc)=>/*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } // EXTERNAL MODULE: ./src/lib/api.ts var api = __webpack_require__(91864); // EXTERNAL MODULE: ../../node_modules/socket.io-client/build/esm-debug/index.js + 30 modules var esm_debug = __webpack_require__(44826); ;// ./src/components/Header.tsx /* __next_internal_client_entry_do_not_use__ Header auto */ const API_URL = "https://api.canhelp.gr" || 0; function Header() { const router = (0,navigation.useRouter)(); const pathname = (0,navigation.usePathname)(); const { data: session } = (0,auth/* useSession */.wV)(); const { t, locale } = (0,context_locale/* useLocale */.Y)(); const [menuOpen, setMenuOpen] = (0,react.useState)(false); const [profileOpen, setProfileOpen] = (0,react.useState)(false); const [unreadNotif, setUnreadNotif] = (0,react.useState)(0); const [unreadChat, setUnreadChat] = (0,react.useState)(0); const [msgToast, setMsgToast] = (0,react.useState)(null); const [planTier, setPlanTier] = (0,react.useState)(null); const profileRef = (0,react.useRef)(null); const headerRef = (0,react.useRef)(null); const toastTimer = (0,react.useRef)(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) return; const socket = (0,esm_debug.io)(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>(0,api/* getUnreadCount */.$M)().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ if (!session) { setPlanTier(null); return; } (0,api/* getMyDashboard */.H)().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react.useEffect)(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "truncate max-w-[100px]", children: (0,formatName/* formatShortName */.H)(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); (0,auth/* signOut */.CI)().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)(LanguageSwitcher, {}) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)(LanguageSwitcher, {}), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)((link_default()), { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("button", { onClick: ()=>{ setMenuOpen(false); (0,auth/* signOut */.CI)().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ (0,react_jsx_runtime.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ (0,react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ (0,react_jsx_runtime.jsx)("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ (0,react_jsx_runtime.jsxs)("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ (0,react_jsx_runtime.jsx)("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ (0,react_jsx_runtime.jsx)((link_default()), { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } /***/ }), /***/ 64271: /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 58671, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56542, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 88248, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 49743, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 96231, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 10959, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 72041, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 95094, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67487, 23)); /***/ }), /***/ 67674: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Header: () => (/* binding */ Header) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. const Header = (0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)( function() { throw new Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Header.tsx", "Header", ); /***/ }), /***/ 72088: /***/ (() => { /* (ignored) */ /***/ }), /***/ 72519: /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 48365, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 64596, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56186, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67805, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 27561, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 47569, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 42747, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56676, 23)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 97225)); /***/ }), /***/ 85105: /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 15043)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 58719)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 21046)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96484)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 56003)); /***/ }), /***/ 85998: /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 3498, 23)); /***/ }), /***/ 91864: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $7: () => (/* binding */ updateCategory), /* harmony export */ $H: () => (/* binding */ acceptOffer), /* harmony export */ $M: () => (/* binding */ getUnreadCount), /* harmony export */ Bb: () => (/* binding */ getMySpecialistCards), /* harmony export */ Bm: () => (/* binding */ getUserRating), /* harmony export */ Bq: () => (/* binding */ getSpecialistCards), /* harmony export */ Br: () => (/* binding */ getAdminNotifLogs), /* harmony export */ CX: () => (/* binding */ updateAdminSettings), /* harmony export */ Cs: () => (/* binding */ previewPlanChange), /* harmony export */ D1: () => (/* binding */ setAvailabilityRange), /* harmony export */ Em: () => (/* binding */ request), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ F9: () => (/* binding */ getTaskInvite), /* harmony export */ FI: () => (/* binding */ sendTestEmail), /* harmony export */ Fu: () => (/* binding */ getMyTasks), /* harmony export */ GB: () => (/* binding */ deleteTaskAdmin), /* harmony export */ Gp: () => (/* binding */ getAutoResponseSettings), /* harmony export */ H: () => (/* binding */ getMyDashboard), /* harmony export */ H6: () => (/* binding */ getTaskReviews), /* harmony export */ He: () => (/* binding */ activateUser), /* harmony export */ Ip: () => (/* binding */ markRead), /* harmony export */ Je: () => (/* binding */ purchasePlan), /* harmony export */ K7: () => (/* binding */ deleteCategory), /* harmony export */ KD: () => (/* binding */ getAdminCategories), /* harmony export */ Lb: () => (/* binding */ declineOffer), /* harmony export */ Lp: () => (/* binding */ getAdminEmailTemplates), /* harmony export */ ML: () => (/* binding */ getCustomerFomoDashboard), /* harmony export */ Mm: () => (/* binding */ changeUserRole), /* harmony export */ NL: () => (/* binding */ markAllRead), /* harmony export */ Nt: () => (/* binding */ updateLocation), /* harmony export */ OM: () => (/* binding */ setAvailability), /* harmony export */ OV: () => (/* binding */ runAutoMatch), /* harmony export */ OX: () => (/* binding */ getAdminPlans), /* harmony export */ On: () => (/* binding */ getCanMessage), /* harmony export */ P0: () => (/* binding */ adminTopUpUserBalance), /* harmony export */ QN: () => (/* binding */ getOrCreateDirectRoom), /* harmony export */ RN: () => (/* binding */ getSiteStats), /* harmony export */ RQ: () => (/* binding */ updateAutoResponseSettings), /* harmony export */ Rt: () => (/* binding */ completeTask), /* harmony export */ S$: () => (/* binding */ getPublicSiteProfile), /* harmony export */ Sw: () => (/* binding */ getOffers), /* harmony export */ T9: () => (/* binding */ getPlans), /* harmony export */ Tr: () => (/* binding */ getNotifications), /* harmony export */ UE: () => (/* binding */ trackSiteMessage), /* harmony export */ UT: () => (/* binding */ createTask), /* harmony export */ V: () => (/* binding */ addSpecialistFavorite), /* harmony export */ VL: () => (/* binding */ getMessages), /* harmony export */ VM: () => (/* binding */ getUserProfile), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ Wi: () => (/* binding */ deactivateUser), /* harmony export */ Xz: () => (/* binding */ getSpecialistAvailability), /* harmony export */ Yj: () => (/* binding */ getAdminTasks), /* harmony export */ Zp: () => (/* binding */ getChatRooms), /* harmony export */ _z: () => (/* binding */ sendMessage), /* harmony export */ aT: () => (/* binding */ getMyOffers), /* harmony export */ bR: () => (/* binding */ deletePlan), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ bc: () => (/* binding */ toggleStatus), /* harmony export */ bi: () => (/* binding */ getAdminNotifStats), /* harmony export */ bx: () => (/* binding */ createReview), /* harmony export */ cS: () => (/* binding */ getAdminUsers), /* harmony export */ dE: () => (/* binding */ getAdminStats), /* harmony export */ eR: () => (/* binding */ createSpecialistCard), /* harmony export */ eU: () => (/* binding */ updateReportStatus), /* harmony export */ f5: () => (/* binding */ deleteSpecialistCard), /* harmony export */ fm: () => (/* binding */ getBalanceHistory), /* harmony export */ g0: () => (/* binding */ getAdminBalanceHistory), /* harmony export */ gg: () => (/* binding */ getTask), /* harmony export */ hD: () => (/* binding */ adminWithdrawUserBalance), /* harmony export */ hl: () => (/* binding */ updatePortfolioItem), /* harmony export */ iN: () => (/* binding */ getMyAvailability), /* harmony export */ j_: () => (/* binding */ getAdminAiLogs), /* harmony export */ jd: () => (/* binding */ getAdminUser), /* harmony export */ jg: () => (/* binding */ updateAdminEmailTemplate), /* harmony export */ k_: () => (/* binding */ getAdminLocations), /* harmony export */ lC: () => (/* binding */ updateTask), /* harmony export */ nf: () => (/* binding */ cancelTaskAdmin), /* harmony export */ oh: () => (/* binding */ initiateTopUp), /* harmony export */ oq: () => (/* binding */ adminUpdateSpecialistCard), /* harmony export */ pD: () => (/* binding */ getSpecialistFavorites), /* harmony export */ pK: () => (/* binding */ getPaymentHistory), /* harmony export */ q7: () => (/* binding */ getMyReviews), /* harmony export */ qT: () => (/* binding */ createPlan), /* harmony export */ qt: () => (/* binding */ getAdminMailLogs), /* harmony export */ rC: () => (/* binding */ getAdminSettings), /* harmony export */ rl: () => (/* binding */ getSkillSuggestions), /* harmony export */ sD: () => (/* binding */ removeSpecialistFavorite), /* harmony export */ st: () => (/* binding */ getMyReferralInfo), /* harmony export */ td: () => (/* binding */ updatePlan), /* harmony export */ ts: () => (/* binding */ createOffer), /* harmony export */ u4: () => (/* binding */ getAdminMailStats), /* harmony export */ uQ: () => (/* binding */ verifyAdminUserEmail), /* harmony export */ v9: () => (/* binding */ getUserReviews), /* harmony export */ vh: () => (/* binding */ getTaskStats), /* harmony export */ vy: () => (/* binding */ getAdminUserSpecialistCards), /* harmony export */ wc: () => (/* binding */ translateAdminEmailTemplate), /* harmony export */ wl: () => (/* binding */ updateAdminUser), /* harmony export */ yJ: () => (/* binding */ createLocation), /* harmony export */ yO: () => (/* binding */ getAdminActivityLogs), /* harmony export */ yk: () => (/* binding */ dismissNotification), /* harmony export */ z4: () => (/* binding */ getDailyUsage), /* harmony export */ z5: () => (/* binding */ getAdminReports), /* harmony export */ z6: () => (/* binding */ getMyStatuses), /* harmony export */ zB: () => (/* binding */ deletePortfolioItem), /* harmony export */ zR: () => (/* binding */ deleteLocation), /* harmony export */ zZ: () => (/* binding */ createCategory), /* harmony export */ zc: () => (/* binding */ updateSpecialistCard), /* harmony export */ zk: () => (/* binding */ getSpecialistFomoDashboard) /* harmony export */ }); /* unused harmony exports getTasks, getTaskBudgetRange, searchTasks, getTasksForSpecialist, getTaskCountsByCategory, cancelTask, updateNotifSettings, getFavorites, addFavorite, removeFavorite, getMyPortfolio, addPortfolioItem, getSpecialistPortfolio, getFomoRecommendations, getAutoMatchResults, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); /***/ }), /***/ 91946: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43560); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (async (props) => { const imageData = {"type":"image/svg+xml","sizes":"any"} const imageUrl = (0,next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__.fillMetadataSegment)(".", await props.params, "icon.svg") return [{ ...imageData, url: imageUrl + "?71a523b2dd824001", }] }); /***/ }), /***/ 94833: /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 39348)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 67674)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 32948)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 20138)); ; Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1697)); /***/ }), /***/ 96484: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider), /* harmony export */ Y: () => (/* binding */ useLocale) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71159); /* harmony import */ var _lib_translations__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12998); /* __next_internal_client_entry_do_not_use__ LocaleProvider,useLocale auto */ const COOKIE_KEY = 'canhelp_locale'; const DEFAULT_LOCALE = 'el'; const LocaleContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({ locale: DEFAULT_LOCALE, setLocale: ()=>{}, t: (key)=>key }); function readCookieLocale() { if (typeof document === 'undefined') return DEFAULT_LOCALE; const match = document.cookie.match(/canhelp_locale=([^;]+)/); const val = match?.[1]; return val && [ 'el', 'en', 'ru' ].includes(val) ? val : DEFAULT_LOCALE; } function LocaleProvider({ children, initialLocale }) { const router = (0,next_navigation__WEBPACK_IMPORTED_MODULE_2__.useRouter)(); const [locale, setLocaleState] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(initialLocale ?? DEFAULT_LOCALE); // Sync from cookie on mount (client-side) process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{ const cookieLocale = readCookieLocale(); if (cookieLocale !== locale) setLocaleState(cookieLocale); // Sync cookie locale to DB on first load (in case DB is out of sync) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: cookieLocale }) }).catch(()=>{}); }, []); const setLocale = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((next)=>{ setLocaleState(next); document.cookie = `${COOKIE_KEY}=${next}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.lang = next; // Persist locale to user profile in DB (best-effort, non-blocking) const apiBase = "https://api.canhelp.gr" || 0; fetch(`${apiBase}/api/users/me`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ locale: next }) }).catch(()=>{}); // Re-render server components with new cookie router.refresh(); }, [ router ]); const t = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((key, fallback)=>(0,_lib_translations__WEBPACK_IMPORTED_MODULE_3__/* .getTranslations */ .$)(locale)(key, fallback), [ locale ]); return /*#__PURE__*/ (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(LocaleContext.Provider, { value: { locale, setLocale, t }, children: children }); } function useLocale() { return (0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)(LocaleContext); } /***/ }) }; ;    @$Hexports.id = 892; exports.ids = [892]; exports.modules = { /***/ 1241: 0/* (ignored) *///, /***/ 1697:  /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider) /* harmony export */ }); /* unused harmony export useLocation */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocationProvider = registerClientReference( function() { throw new Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "LocationProvider", );export const useLocation = registerClientReference( function() { throw new Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/location.tsx", "useLocation", );61134undefined136142undefined168190(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined537543undefined564586(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined++, /***/ 12998: /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ $: () => (/* binding */ getTranslations), /* harmony export */ YZ: () => (/* binding */ LOCALES) /* harmony export */ }); /* unused harmony export translations */ nexport const LOCALES = [ { code: 'el', label: 'Ελληνικά', flag: '🇬🇷' }, { code: 'en', label: 'English', flag: '🇬🇧' }, { code: 'ru', label: 'Русский', flag: '🇷🇺' } ]; export const translations = { el: { 'footer.slogan': 'Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.', 'footer.links': 'Σύνδεσμοι', 'footer.socials': 'Στα κοινωνικά δίκτυα', // Nav 'nav.home': 'Αρχική', 'nav.tasks': 'Εργασίες', 'nav.post': '+ Δημοσίευση', 'nav.dashboard': 'Πίνακας', 'nav.chat': 'Μηνύματα', 'nav.notifications': 'Ειδοποιήσεις', 'nav.profile': 'Προφίλ', 'nav.admin': 'Διαχείριση', 'nav.specialists': 'Ειδικοί', 'nav.new_task': 'Νέα εργασία', 'nav.login': 'Σύνδεση', 'nav.register': 'Εγγραφή', 'nav.logout': 'Έξοδος', // Hero 'hero.title': 'Βρες ειδικό για κάθε δουλειά', 'hero.subtitle': 'Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία', 'hero.cta.post': 'Δημοσίευσε εργασία', 'hero.cta.browse': 'Γίνε ειδικός', 'hero.search.placeholder': 'Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...', 'stats.specialists': 'ειδικοί', 'stats.tasks': 'εργασίες', 'stats.categories': 'κατηγορίες', 'stats.free': 'δωρεάν εγγραφή', // Sections 'section.categories': 'Δημιούργησε εργασία σε οποιαδήποτε κατηγορία', 'section.how': 'Πώς λειτουργεί', 'section.recent': 'Πρόσφατες εργασίες', 'section.all': 'Δες όλες →', 'section.more': 'ακόμα', 'section.cities': 'Πόλεις & Περιοχές', 'section.community': 'Ένα κοινοτικό έργο για όλους', 'community.subtitle': 'Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.', 'community.point1.title': 'Είσαι ειδικός σε κάτι;', 'community.point1.desc': 'Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.', 'community.point2.title': 'Χρειάζεσαι βοήθεια;', 'community.point2.desc': 'Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.', 'community.point3.title': 'Βοήθησε το έργο να αναπτυχθεί', 'community.point3.desc': 'Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.', 'community.share': 'Μοιράσου με φίλους', 'community.share.copied': 'Σύνδεσμος αντιγράφηκε!', // Referral section on home page 'section.referral': 'Πρόγραμμα παραπομπών', 'referral.home.subtitle': 'Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.', 'referral.home.step1.title': 'Εγγραφείσε και λάβε σύνδεσμο', 'referral.home.step1.desc': 'Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.', 'referral.home.step2.title': 'Μοιράσου με φίλους', 'referral.home.step2.desc': 'Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.', 'referral.home.step3.title': 'Κέρδισε ανταμοιβές', 'referral.home.step3.desc': 'Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.', 'referral.home.cta': 'Πάρε τον σύνδεσμό σου', 'referral.home.badge': 'Πρόγραμμα παραπομπών', // FAQ section 'section.faq': 'Συχνές Ερωτήσεις', 'faq.q1': 'Πώς λειτουργεί το CanHelp;', 'faq.a1': 'Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.', 'faq.q2': 'Πόσο κοστίζει η χρήση της πλατφόρμας;', 'faq.a2': 'Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.', 'faq.q3': 'Πώς μπορώ να γίνω ειδικός;', 'faq.a3': 'Κάνε εγγραφή, πήγαινε στο «Γίνε Ειδικός», συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.', 'faq.q4': 'Πώς επιλέγω τον κατάλληλο ειδικό;', 'faq.a4': 'Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q5': 'Τι γίνεται αν δεν είμαι ικανοποιημένος;', 'faq.a5': 'Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.', 'faq.q6': 'Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;', 'faq.a6': 'Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.', 'faq.q7': 'Πόσος χρόνος χρειάζεται για να λάβω προσφορές;', 'faq.a7': 'Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.', 'faq.q8': 'Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;', 'faq.a8': 'Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.', 'faq.q9': 'Τι είδη εργασιών μπορώ να βρω στο CanHelp;', 'faq.a9': 'Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.', 'faq.q10': 'Υπάρχει εφαρμογή για κινητό;', 'faq.a10': 'Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.', // How it works 'how.step1.title': 'Δημοσίευσε εργασία', 'how.step1.desc': 'Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου', 'how.step2.title': 'Λάβε προσφορές', 'how.step2.desc': 'Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο', 'how.step3.title': 'Επίλεξε & ξεκίνα', 'how.step3.desc': 'Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία', // Tasks page 'tasks.title': 'εργασίες', 'tasks.filters': 'Φίλτρα', 'tasks.search': 'Αναζήτηση', 'tasks.search.placeholder': 'Τίτλος ή λέξη κλειδί...', 'tasks.search.btn': 'Αναζήτηση', 'tasks.publish': 'Δημοσίευση', 'tasks.category.all': 'Όλες', 'tasks.category.all_in': 'Όλα στην', 'tasks.category.label': 'Κατηγορία', 'tasks.location.label': 'Πόλη', 'tasks.location.placeholder': 'π.χ. Αθήνα', 'tasks.empty': 'Δεν βρέθηκαν εργασίες', 'tasks.empty.cta': 'Δημοσίευσε την πρώτη', // Task detail 'task.status.open': 'Ανοιχτή', 'task.status.in_progress': 'Σε εξέλιξη', 'task.status.completed': 'Ολοκληρωμένη', 'task.status.cancelled': 'Ακυρωμένη', 'task.status.draft': 'Πρόχειρο', 'task.budget': 'Προϋπολογισμός', 'task.location': 'Τοποθεσία', 'task.deadline': 'Ημερομηνία έναρξης', 'task.created_at': 'Δημιουργήθηκε', 'task.customer': 'Πελάτης', 'task.offer.btn': 'Υποβολή προσφοράς', 'task.invite.banner_title': 'Σας προσκαλούν σε αυτήν την εργασία', 'task.invite.banner_hint': 'Ο πελάτης σας πρόσκαλεσε προσωπικά', 'task.invite.accept': 'Αποστολή προσφοράς', 'task.invite.decline': 'Άρνηση', 'offer.accept': 'Αποδοχή', 'offer.decline': 'Απόρριψη', 'task.complete': 'Ολοκλήρωση εργασίας', 'task.complete.confirm': 'Να ολοκληρωθεί η εργασία;', 'task.edit': 'Επεξεργασία', 'task.status_label': 'Κατάσταση', 'task.yours': 'Η εργασία σου', 'task.offer.yours': 'Η προσφορά σου', 'review.leave': 'Άφησε αξιολόγηση', 'review.rating': 'Βαθμολογία', 'review.comment': 'Σχόλιο', 'review.comment.placeholder': 'Πες μας για την εμπειρία σου...', 'review.submit': 'Υποβολή αξιολόγησης', 'review.submitting': 'Αποστολή...', 'review.done': 'Η αξιολόγηση καταχωρήθηκε!', 'profile.reviews': 'Αξιολογήσεις', 'profile.no_reviews': 'Δεν υπάρχουν αξιολογήσεις ακόμα', 'profile.rating': 'Βαθμολογία', 'profile.skills.label': 'Δεξιότητες', 'profile.member_since': 'Μέλος από', 'task.offers': 'Προσφορές', 'task.offers.none': 'Δεν υπάρχουν ακόμα προσφορές', // Create task 'create.title': 'Δημοσίευση εργασίας', 'create.field.title': 'Τίτλος', 'create.field.description': 'Περιγραφή', 'create.field.category': 'Κατηγορία', 'create.field.category.select': 'Επιλέξτε...', 'create.field.location': 'Τοποθεσία', 'create.field.location.any': 'Οπουδήποτε', 'create.field.location.all': 'Ολόκληρη η πόλη', 'create.field.budget': 'Προϋπολογισμός (€)', 'create.field.deadline': 'Ημερομηνία έναρξης', 'create.field.budget_negotiable': 'Η τιμή είναι διαπραγματεύσιμη', 'create.field.time_slot': 'Χρόνος εκτέλεσης', 'create.field.time_slot.any': 'Οποιαδήποτε', 'create.field.time_slot.morning': 'Πρωινό (08:00–13:00)', 'create.field.time_slot.afternoon': 'Μεσημέρι (13:00–18:00)', 'create.field.time_slot.evening': 'Βράδυ (18:00–22:00)', 'create.field.time_slot.weekend': 'Σαββατοκύριακο', 'create.field.address': 'Διεύθυνση (προαιρετικά)', 'create.field.address.district': 'Συνοικία', 'create.field.address.street': 'Οδός', 'create.field.address.house': 'Αριθμός', 'create.field.confidential': 'Εμπιστευτική σημείωση', 'create.field.confidential.placeholder': 'Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...', 'create.field.confidential.hint': 'Δεν εμφανίζεται δημόσια', 'create.field.photos': 'Φωτογραφίες', 'create.field.photos.add': 'Προσθήκη φωτογραφίας', 'create.field.photos.uploading': 'Ανέβασμα...', 'task.budget_negotiable': 'Τιμή διαπραγματεύσιμη', 'task.time_slot': 'Χρόνος', 'task.confidential': 'Εμπιστευτική σημείωση', 'create.field.title.placeholder': 'π.χ. Καθαρισμός διαμερίσματος 80τμ', 'create.field.description.placeholder': 'Περίγραψε λεπτομερώς τι χρειάζεσαι...', 'create.field.location.placeholder': 'π.χ. Αθήνα, Κολωνάκι', 'create.field.budget.placeholder': 'π.χ. 100', 'create.submit': 'Δημοσίευση εργασίας', 'create.submitting': 'Δημοσίευση...', // Auth 'login.title': 'Καλωσόρισες', 'login.subtitle': 'Σύνδεση στο CanHelp', 'login.email': 'Email', 'login.password': 'Κωδικός', 'login.submit': 'Σύνδεση', 'login.submitting': 'Σύνδεση...', 'login.error': 'Λάθος email ή κωδικός', 'login.unverified.title': 'Επιβεβαιώστε το email σας', 'login.unverified.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.', 'login.unverified.resend': 'Αποστολή νέου email επαλήθευσης', 'login.unverified.sending': 'Αποστολή...', 'login.unverified.sent': '✓ Εστάλη — ελέγξτε τα εισερχόμενα', 'profile.email.verified': 'Email επαληθεύτηκε', 'profile.email.not_verified': 'Email δεν επαληθεύτηκε', 'login.no_account': 'Δεν έχεις λογαριασμό;', 'login.register_link': 'Εγγραφή', 'login.forgot_password': 'Ξέχασα τον κωδικό', 'login.or_continue_with': 'ή συνεχίστε με', 'login.continue_google': 'Σύνδεση με Google', 'forgot.title': 'Ξέχασα τον κωδικό', 'forgot.subtitle': 'Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης', 'forgot.email': 'Email', 'forgot.submit': 'Αποστολή', 'forgot.submitting': 'Αποστολή...', 'forgot.sent.title': 'Ελέγξτε τα εισερχόμενά σας', 'forgot.sent.desc': 'Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.', 'forgot.back_to_login': 'Επιστροφή στη σύνδεση', 'forgot.error': 'Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.', 'forgot.error.not_found': 'Δεν βρέθηκε λογαριασμός με αυτό το email.', 'forgot.error.send_failed': 'Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα', 'reset.title': 'Νέος κωδικός', 'reset.subtitle': 'Εισάγετε τον νέο σας κωδικό', 'reset.password': 'Νέος κωδικός', 'reset.confirm': 'Επιβεβαίωση κωδικού', 'reset.submit': 'Αλλαγή κωδικού', 'reset.submitting': 'Αποθήκευση...', 'reset.success': 'Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...', 'reset.back_to_login': 'Επιστροφή στη σύνδεση', 'reset.error.mismatch': 'Οι κωδικοί δεν ταιριάζουν', 'reset.error.invalid': 'Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.', 'register.title': 'Εγγραφή', 'register.subtitle': 'Δημιουργία λογαριασμού στο CanHelp', 'register.first_name': 'Όνομα', 'register.last_name': 'Επώνυμο', 'register.email': 'Email', 'register.password': 'Κωδικός (min 8 χαρακτήρες)', 'register.role': 'Ρόλος', 'register.role.customer': 'Χρήστης', 'register.role.customer.desc': 'Δημοσιεύω εργασίες', 'register.role.specialist': 'Ειδικός', 'register.role.specialist.desc': 'Αναλαμβάνω εργασίες', 'register.submit': 'Δημιουργία λογαριασμού', 'register.submitting': 'Εγγραφή...', 'register.has_account': 'Έχεις ήδη λογαριασμό;', 'register.login_link': 'Σύνδεση', 'register.continue_google': 'Εγγραφή με Google', 'register.check_email.title': 'Ελέγξτε το email σας', 'register.check_email.desc': 'Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.', 'register.check_email.login': 'Επιστροφή στη σύνδεση', // Dashboard 'dashboard.title': 'Πίνακας ελέγχου', 'dashboard.new_task': '+ Νέα εργασία', 'dashboard.my_tasks': 'Οι εργασίες μου', 'dashboard.my_offers': 'Οι προσφορές μου', 'dashboard.invitations': 'Προσκλήσεις για εργασία', 'dashboard.offers_count': 'προσφορές', 'dashboard.declined_count': 'απορρίφθηκαν', 'dashboard.completed_tasks': 'Ολοκληρωμένες εργασίες', 'dashboard.completed_offers': 'Ολοκληρωμένες προσφορές', 'dashboard.review_pending': 'Η αξιολόγηση δεν έχει υποβληθεί ακόμα', 'tasks.new.top_specialists': 'Κορυφαίοι ειδικοί', 'tasks.new.select_category': 'Επιλέξτε κατηγορία για να δείτε ειδικούς', 'tasks.new.invite': 'Πρόσκληση', 'tasks.new.invited': 'Επιλέχθηκε ✓', 'reviews.count': 'αξιολογήσεις', 'filter.location': 'Τοποθεσία', 'filter.language': 'Γλώσσες', 'filter.language.any': 'Οποιαδήποτε γλώσσα', 'filter.category.all': 'Όλες οι κατηγορίες', 'user.categories': 'Κατηγορίες', 'user.work_area': 'Περιοχή εργασίας', 'dashboard.tasks.empty': 'Δεν έχεις δημοσιεύσει εργασίες', 'dashboard.tasks.empty.cta': 'Δημοσίευσε την πρώτη σου', 'dashboard.tasks.add_new': 'Πρόσθεσε νέα εργασία', 'dashboard.offers.empty': 'Δεν έχεις υποβάλλει προσφορές', 'dashboard.offers.empty.cta': 'Βρες εργασίες', 'dashboard.customer.specialists_title': 'Ψάχνεις εκτελεστή;', 'dashboard.customer.specialists_hint': 'Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου', 'dashboard.customer.specialists_cta': 'Βρες ειδικό', 'dashboard.customer.how_title': 'Πώς λειτουργεί', 'dashboard.customer.step1': 'Δημιούργησε εργασία με περιγραφή και προϋπολογισμό', 'dashboard.customer.step2': 'Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο', 'dashboard.customer.step3': 'Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία', // Notifications 'notif.title': 'Ειδοποιήσεις', 'notif.mark_all': 'Σήμανση όλων ως αναγνωσμένα', 'notif.empty': 'Δεν υπάρχουν ειδοποιήσεις', 'notif.type.new_offer': 'Νέα προσφορά', 'notif.type.offer_accepted': 'Η προσφορά σας έγινε δεκτή', 'notif.type.offer_declined': 'Η προσφορά σας απορρίφθηκε', 'notif.type.task_completed': 'Η εργασία ολοκληρώθηκε', 'notif.type.task_cancelled': 'Η εργασία ακυρώθηκε', 'notif.type.new_message': 'Νέο μήνυμα', 'notif.type.new_review': 'Νέα αξιολόγηση', 'notif.type.task_invite': 'Πρόσκληση σε εργασία', 'notif.body.new_offer': 'Νέα προσφορά για «{title}»', 'notif.body.offer_accepted': 'Η προσφορά σας για «{title}» έγινε δεκτή', 'notif.body.offer_declined': 'Η προσφορά σας για «{title}» απορρίφθηκε', 'notif.body.task_invite': 'Σας προσκαλούν για «{title}»', 'notif.body.new_review': 'Λάβατε αξιολόγηση {rating}★', // Offer status 'offer.status.pending': 'Εκκρεμεί', 'offer.status.accepted': 'Αποδεκτή', 'offer.status.declined': 'Απορρίφθηκε', 'offer.status.withdrawn': 'Αποσύρθηκε', 'offer.status.other_accepted': 'Επιλέχθηκε άλλος ειδικός', // Common 'common.loading': 'Φόρτωση...', 'common.error': 'Σφάλμα', 'common.save': 'Αποθήκευση', 'common.saving': 'Αποθήκευση...', 'common.cancel': 'Ακύρωση', 'common.add': 'Προσθήκη', 'common.close': 'Κλείσιμο', 'common.edit': 'Επεξεργασία', 'common.delete': 'Διαγραφή', 'common.from': 'από', 'common.currency': '€', 'common.greece': 'Ελλάδα', // Chat 'chat.connected': 'Συνδεδεμένος', 'chat.disconnected': 'Αποσυνδεδεμένος', 'chat.no_rooms': 'Δεν υπάρχουν συνομιλίες ακόμα', 'chat.task_fallback': 'Εργασία', 'chat.select': 'Επίλεξε συνομιλία', 'chat.no_messages': 'Δεν υπάρχουν μηνύματα', 'chat.placeholder': 'Γράψε μήνυμα... (Enter για αποστολή)', 'chat.conversation_fallback': 'Συνομιλία', 'chat.direct_chat': 'Απευθείας συνομιλία', 'chat.linked_task': 'Συνδεδεμένη εργασία', 'chat.write_btn': 'Μήνυμα', 'chat.just_now': 'μόλις τώρα', 'chat.min_ago': 'λ', 'chat.write_specialist': 'Γράψε στον ειδικό', 'chat.write_customer': 'Γράψε στον πελάτη', 'chat.notif_settings': 'Ρυθμίσεις ειδοποιήσεων', 'chat.notif_messages': 'Ειδοποιήσεις για νέα μηνύματα', 'chat.toast_title': 'Νέο μήνυμα', 'chat.toast_open': 'Άνοιγμα συνομιλίας', // Offer form 'offer.price': 'Τιμή', 'offer.price.placeholder': 'π.χ. 80', 'offer.customer_budget': 'Προϋπολογισμός πελάτη', 'offer.message': 'Μήνυμα', 'offer.optional': 'προαιρετικό', 'offer.message.placeholder': 'Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...', 'offer.submitting': 'Αποστολή...', // Profile 'profile.photo': 'Φωτογραφία προφίλ', 'profile.photo.change': 'Αλλαγή φωτογραφίας', 'profile.photo.hint': 'JPEG, PNG, WebP · έως 5MB', 'profile.basic_info': 'Βασικά στοιχεία', 'profile.phone': 'Τηλέφωνο', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Σύντομη περιγραφή', 'profile.bio.placeholder': 'Πες μας λίγα λόγια για εσένα...', 'profile.language': 'Γλώσσα', 'profile.language.hint': 'Γλώσσα διεπαφής και email ειδοποιήσεων', 'profile.languages': 'Γλώσσες επικοινωνίας', 'profile.languages.hint': 'Επιλέξτε όλες τις γλώσσες που μιλάτε', 'profile.skills': 'Δεξιότητες', 'profile.skills.subtitle': 'Προσθέσε τις υπηρεσίες που προσφέρεις', 'profile.skills.placeholder': 'π.χ. Καθαρισμός, IT, Μαθήματα...', 'profile.role': 'Ρόλος λογαριασμού', 'profile.role.specialist': '🔧 Ειδικός', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Χρήστης', 'profile.role.change': 'Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.', 'profile.become_specialist': 'Γίνε Ειδικός', 'profile.become_specialist.desc': 'Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.', 'become_specialist.hero.title': 'Κέρδισε χρήματα κάνοντας αυτό που ξέρεις', 'become_specialist.hero.subtitle': 'Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα', 'become_specialist.how.title': 'Πώς λειτουργεί', 'become_specialist.step1.title': 'Δημιούργησε κάρτα ειδικού', 'become_specialist.step1.desc': 'Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα', 'become_specialist.step2.title': 'Βρες εργασίες', 'become_specialist.step2.desc': 'Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα «Αναζήτηση εργασιών»', 'become_specialist.step3.title': 'Στείλε προσφορά & κέρδισε', 'become_specialist.step3.desc': 'Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες', 'become_specialist.benefits.title': 'Πλεονεκτήματα προφίλ ειδικού', 'become_specialist.benefit1': 'Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία', 'become_specialist.benefit2': 'Δημόσιο προφίλ με αξιολογήσεις πελατών', 'become_specialist.benefit3': 'Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες', 'become_specialist.benefit4': 'Προσθήκη σε αγαπημένα από πελάτες', 'become_specialist.cta': 'Περισσότερα', 'become_specialist.free_badge': 'Δωρεάν εγγραφή', 'profile.tab.notifications': 'Ειδοποιήσεις', 'profile.tab.reviews': 'Αξιολογήσεις', 'profile.tab.referral': 'Παραπομπές', 'profile.tab.auto_response': 'Αυτόματη απάντηση', 'profile.tab.site': 'Site', 'profile.site.title': 'Προσωπική σελίδα', 'profile.site.url_label': 'Προσωπικό site', 'profile.site.copy': 'Αντιγραφή', 'profile.site.copied': 'Αντιγράφηκε', 'profile.site.visible_title': 'Τι εμφανίζεται στη σελίδα σας', 'profile.site.visible.name': 'Όνομα και φωτογραφία', 'profile.site.visible.bio': 'Βιογραφικό', 'profile.site.visible.rating': 'Αξιολόγηση και κριτικές', 'profile.site.visible.portfolio': 'Χαρτοφυλάκιο / Κάρτες', 'profile.site.visible.contacts': 'Στοιχεία επικοινωνίας', 'profile.site.visible.full_last_name': 'Πλήρες επώνυμο', 'profile.site.visible.services': 'Κάρτες υπηρεσιών', 'profile.site.visible.reviews': 'Ενότητα κριτικών', 'profile.site.visible.status': 'Κατάσταση «Έτοιμος να βοηθήσω»', 'profile.site.theme': 'Θέμα εμφάνισης', 'profile.site.theme.dark': 'Σκοτεινό', 'profile.site.theme.light': 'Φωτεινό', 'profile.site.slug_taken': 'Αυτή η διεύθυνση είναι ήδη κατειλημμένη', 'profile.site.stats.title': 'Στατιστικά επισκεψιμότητας', 'profile.site.stats.days': 'τελευταίες 30 ημέρες', 'profile.site.stats.views': 'Προβολές', 'profile.site.stats.unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.messages': 'Μηνύματα', 'profile.site.stats.total_views': 'Συνολικές προβολές', 'profile.site.stats.total_unique': 'Μοναδικοί επισκέπτες', 'profile.site.stats.total_messages': 'Μηνύματα', 'profile.site.stats.empty': 'Δεν υπάρχουν δεδομένα ακόμη', 'profile.site.stats.loading': 'Φόρτωση στατιστικών...', 'profile.site.stats.no_slug': 'Ορίστε τη διεύθυνση του site για να δείτε στατιστικά', 'profile.site.edit_bio_hint': 'Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα «Βασικά».', 'status.can_help_now_hint': 'Η κάρτα σου εμφανίζεται ψηλότερα', 'status.need_help_hint': 'Οι ειδικοί μπορούν να σε βοηθήσουν', 'profile.referral.title': 'Πρόγραμμα παραπομπών', 'profile.referral.desc': 'Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.', 'profile.referral.link_label': 'Ο σύνδεσμος παραπομπής σου', 'profile.referral.copy': 'Αντιγραφή', 'profile.referral.copied': 'Αντιγράφηκε!', 'profile.referral.invited_count': 'επιτυχείς παραπομπές', 'profile.referral.no_code': 'Ο κωδικός παραπομπής δεν είναι διαθέσιμος.', 'notifications.title': 'Ρυθμίσεις ειδοποιήσεων', 'notifications.email.new_tasks': 'Email για νέες εργασίες', 'notifications.email.new_tasks.desc': 'Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου', 'notifications.messages.desc': 'Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα', 'notifications.saved': 'Ρυθμίσεις αποθηκεύτηκαν', 'notifications.plan_required': 'Συνδρομή απαιτείται για αυτή τη λειτουργία', 'profile.tab.info': 'Βασικά στοιχεία', 'profile.tab.finance': 'Οικονομικά', 'profile.tab.skills': 'Δεξιότητες', 'profile.tab.categories': 'Κατηγορίες', 'profile.tab.geography': 'Γεωγραφία', 'profile.specialist.categories': 'Κατηγορίες εργασιών', 'profile.specialist.categories.desc': 'Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι', 'profile.specialist.geography': 'Περιοχές κάλυψης', 'profile.specialist.geography.desc': 'Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι', 'profile.saving': 'Αποθήκευση...', 'profile.upload.error': 'Σφάλμα κατά την αναφόρτωση', 'profile.saved': 'Αποθηκεύτηκε', 'profile.tab.cards': 'Χαρτοφυλάκιο', 'profile.cards.count': 'Χαρτοφυλάκια', 'profile.cards.add': 'Νέο χαρτοφυλάκιο', 'profile.cards.new_title': 'Τίτλος νέου χαρτοφυλακίου', 'profile.cards.placeholder': 'π.χ. Υδραυλικά', 'profile.cards.create': 'Δημιουργία', 'profile.cards.cancel': 'Ακύρωση', 'profile.cards.empty': 'Δεν έχετε χαρτοφυλάκιο', 'profile.cards.create_first': 'Δημιουργήστε το πρώτο σας χαρτοφυλάκιο', 'profile.cards.delete_confirm': 'Διαγραφή χαρτοφυλακίου;', 'profile.card.tab.main': 'Γενικά', 'profile.card.tab.skills': 'Δεξιότητες', 'profile.card.tab.categories': 'Κατηγορίες', 'profile.card.tab.geography': 'Γεωγραφία', 'profile.card.tab.portfolio': 'Γκαλερί', 'profile.card.active': 'Ενεργή', 'profile.card.save': 'Αποθήκευση', 'profile.card.saved': 'Αποθηκεύτηκε', 'profile.card.delete': 'Διαγραφή', 'profile.card.skill.add': 'Προσθήκη δεξιότητας', 'profile.card.photo.add': 'Προσθήκη φωτογραφίας', 'profile.card.photo.uploading': 'Μεταφόρτωση...', 'profile.card.photo.empty': 'Δεν υπάρχουν φωτογραφίες', 'profile.card.item.title': 'Τίτλος', 'profile.card.item.desc': 'Περιγραφή', 'profile.card.item.save': 'Αποθήκευση', 'profile.card.item.cancel': 'Ακύρωση', 'profile.card.item.edit': 'Επεξεργασία', 'profile.upgrade.cards_limit': 'Όριο χαρτοφυλακίων εξαντλήθηκε', 'profile.upgrade.plan': 'Τρέχον πλάνο:', 'profile.upgrade.contact': 'Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου', 'profile.upgrade.ok': 'Εντάξει', 'profile.plan.title': 'Πλάνο συνδρομής', 'profile.balance': 'Υπόλοιπο', 'profile.balance.topup': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'profile.balance.topup.amount': 'Ποσό (σε EUR)', 'profile.balance.topup.hint': 'Επιλέξτε ποσό ή εισαγάγετε μανούαλα', 'profile.balance.topup.submit': 'Πληρωμή', 'profile.balance.topup.loading': 'Ρεδιρεκτάρισμα...', 'profile.balance.topup.error': 'Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.', 'payment.success.title': 'Πληρωμή επιτυχής!', 'payment.success.desc': 'Το υπόλοιπό σας ενημερώθηκε.', 'payment.cancelled.title': 'Ακύρωση πληρωμής', 'payment.cancelled.desc': 'Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.', 'payment.pending.title': 'Σε εξέλιξη...', 'payment.pending.desc': 'Επεξεργαζόμαστε την πληρωμή σας.', 'payment.back_to_profile': 'Επιστροφή στο προφίλ', 'profile.plan.basic': 'Βασικό (δωρεάν)', 'profile.plan.contact_upgrade': 'Επικοινωνήστε με τον διαχειριστή για αναβάθμιση', 'profile.plan.cards_up_to': 'Χαρτοφυλάκια: έως', 'profile.plan.cards_unlimited': 'Χαρτοφυλάκια: απεριόριστα', 'profile.plan.tasks_up_to': 'Εργασίες: έως', 'profile.plan.offers_up_to': 'Προσφορές: έως', 'profile.plan.valid_until': 'Ισχύει έως', 'profile.plan.no_expiry': 'Δεν λήγει', // Create task 'create.error': 'Σφάλμα κατά τη δημοσίευση', // Tasks list extras 'tasks.category.general': 'Γενικά', 'tasks.budget.range': 'Εύρος:', 'tasks.budget.from': 'από', 'tasks.budget.to': 'έως', 'tasks.filter.reset': 'Εκκαθάριση φίλτρων', 'tasks.load_more': 'Φόρτωση ακόμα', 'tasks.showing': 'Αποτελέσματα:', 'tasks.field.budget': 'Προϋπολογισμός, €', // Admin 'admin.title': 'Πίνακας Διαχείρισης', 'admin.tab.stats': 'Στατιστικά', 'admin.tab.users': 'Χρήστες', 'admin.tab.tasks': 'Εργασίες', 'admin.tab.reports': 'Αναφορές', 'admin.stats.users': 'Χρήστες', 'admin.stats.tasks': 'Εργασίες', 'admin.stats.offers': 'Προσφορές', 'admin.stats.reviews': 'Αξιολογήσεις', 'admin.tasks.by_status': 'Εργασίες ανά κατάσταση', 'admin.col.user': 'Χρήστης', 'admin.col.email': 'Email', 'admin.col.role': 'Ρόλος', 'admin.col.registered': 'Εγγραφή', 'admin.col.status': 'Κατάσταση', 'admin.col.title': 'Τίτλος', 'admin.col.budget': 'Προϋπολογισμός', 'admin.col.created': 'Δημιουργία', 'admin.users.active': 'Ενεργός', 'admin.users.inactive': 'Ανενεργός', 'admin.users.deactivate': 'Απενεργοποίηση', 'admin.users.activate': 'Ενεργοποίηση', 'admin.tasks.cancel': 'Ακύρωση', 'admin.reports.none': 'Δεν υπάρχουν αναφορές', 'admin.reports.reviewed': 'Αναθεωρήθηκε', 'admin.reports.dismiss': 'Απόρριψη', 'admin.pagination.total': 'Σύνολο', 'admin.users.role.change': 'Αλλαγή ρόλου', 'admin.users.search.placeholder': 'Αναζήτηση ονόματος ή email...', 'admin.tasks.delete': 'Διαγραφή', 'admin.tasks.delete.confirm': 'Διαγραφή αυτής της εργασίας μόνιμα;', 'admin.tasks.search.placeholder': 'Αναζήτηση τίτλου...', 'admin.col.customer': 'Πελάτης', 'admin.col.reporter': 'Καταγγέλλων', 'admin.col.target': 'Στόχος', 'admin.filter.all_roles': 'Όλοι οι ρόλοι', 'admin.filter.all_statuses': 'Όλες οι καταστάσεις', 'admin.reports.target.task': 'Εργασία', 'admin.reports.target.user': 'Χρήστης', 'admin.tab.categories': 'Κατηγορίες', 'admin.tab.locations': 'Πόλεις & Περιοχές', 'admin.tab.logs': 'Αρχεία', 'admin.tab.plans': 'Πακέτα', 'admin.tab.settings': 'Ρυθμίσεις', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Δραστηριότητα', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Ειδοποιήσεις', 'admin.notif_logs.type': 'Τύπος', 'admin.notif_logs.title': 'Τίτλος', 'admin.notif_logs.read': 'Διαβασμένο', 'admin.notif_logs.empty': 'Δεν υπάρχουν αρχεία ειδοποιήσεων', 'admin.stats.notif_chart_title': 'Ειδοποιήσεις ανά ημέρα', 'admin.stats.notif_label': 'Ειδοποιήσεις', 'admin.stats.mail_chart_title': 'Emails ανά ημέρα', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Όλα', 'admin.stats.specialists': 'Ειδικοί', 'admin.col.plan': 'Πακέτο', 'admin.back_home': 'Αρχική', 'admin.plans.title': 'Πακέτα συνδρομής', 'admin.plans.add': '+ Νέο πακέτο', 'admin.plans.empty': 'Δεν υπάρχουν πακέτα', 'admin.plans.form.new': 'Νέο πακέτο', 'admin.plans.form.edit': 'Επεξεργασία πακέτου', 'admin.plans.form.name': 'Όνομα', 'admin.plans.form.price': 'Τιμή (EUR)', 'admin.plans.form.old_price': 'Παλιά τιμή (EUR, προαιρετικό)', 'admin.plans.form.max_offers': 'Μέγ. προσφορές (κενό = χωρίς όριο)', 'admin.plans.form.max_cards': 'Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)', 'admin.plans.form.duration_days': 'Διάρκεια (ημέρες, κενό = χωρίς λήξη)', 'admin.plans.form.description': 'Περιγραφή', 'admin.plans.form.features': 'Δυνατότητες (μία ανά γραμμή)', 'admin.plans.form.notify': 'Ειδοποιήσεις νέων εργασιών', 'admin.plans.form.default': 'Προεπιλογή', 'admin.plans.form.active': 'Ενεργό', 'admin.plans.form.order': 'Σειρά', 'admin.plans.form.role': 'Ρόλος', 'admin.plans.form.tier': 'Επίπεδο', 'admin.plans.form.role.customer': 'Πελάτης', 'admin.plans.form.role.specialist': 'Ειδικός', 'admin.plans.form.tier.free': 'Δωρεάν', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Όρια (κενό = χωρίς όριο)', 'admin.plans.form.max_messages_day': 'Μέγ. μηνύματα/ημέρα', 'admin.plans.form.max_orders_day': 'Μέγ. παραγγελίες/ημέρα', 'admin.plans.form.max_skills': 'Μέγ. δεξιότητες', 'admin.plans.form.max_profiles': 'Μέγ. προφίλ', 'admin.plans.form.max_portfolio': 'Μέγ. στοιχεία χαρτοφυλακίου', 'admin.plans.form.section.boost': 'Πολλαπλασιαστές & Ενίσχυση', 'admin.plans.form.search_boost': 'Ενίσχυση αναζήτησης', 'admin.plans.form.offers_multiplier': 'Πολλαπλασιαστής προσφορών', 'admin.plans.form.section.contact': 'Δικαιώματα επικοινωνίας', 'admin.plans.form.can_contact_free': 'Επικοινωνία με δωρεάν χρήστες', 'admin.plans.form.can_contact_pro': 'Επικοινωνία με Pro χρήστες', 'admin.plans.form.can_contact_all': 'Επικοινωνία με όλους', 'admin.plans.form.can_show_contact': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.plans.form.can_view_phone': 'Προβολή τηλεφώνου', 'admin.plans.form.section.features': 'Λειτουργίες', 'admin.plans.form.upload_video': 'Μεταφόρτωση βίντεο', 'admin.plans.form.favorites': 'Αγαπημένα', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Σήμα επαλήθευσης', 'admin.plans.form.highlighted_reviews': 'Προβεβλημένες κριτικές', 'admin.plans.form.personal_site': 'Προσωπική σελίδα', 'admin.plans.form.can_help_now': 'Κατάσταση «Μπορώ να βοηθήσω»', 'admin.plans.form.need_help': 'Κατάσταση «Χρειάζομαι βοήθεια»', 'admin.plans.form.auto_response': 'Αυτόματη απάντηση', 'admin.plans.form.auto_match': 'Αυτόματη αντιστοίχιση', 'admin.plans.form.instant_dispatch_free': 'Άμεση αποστολή (δωρεάν)', 'admin.plans.form.instant_dispatch_pro': 'Άμεση αποστολή (Pro)', 'admin.plans.badge.default': 'Προεπιλογή', 'admin.plans.badge.inactive': 'Ανενεργό', 'admin.plans.make_default': 'Ορισμός ως προεπιλογή', 'admin.plans.tasks': 'Εργασίες', 'admin.plans.offers': 'Προσφορές', 'admin.plans.cards': 'Χαρτοφυλάκιο', 'admin.plans.notify_tasks': 'Ειδοποιήσεις εργασιών', 'admin.plans.delete.confirm': 'Διαγραφή πακέτου', 'admin.activity.title': 'Αρχείο δραστηριότητας', 'admin.activity.event': 'Γεγονός', 'admin.activity.all_events': 'Όλα τα γεγονότα', 'admin.activity.from': 'Από', 'admin.activity.to': 'Έως', 'admin.activity.reset': 'Επαναφορά', 'admin.activity.total': 'Σύνολο', 'admin.activity.empty': 'Δεν υπάρχουν εγγραφές', 'admin.mail.event': 'Συμβάν email', 'admin.mail.all_events': 'Όλα τα email συμβάντα', 'admin.mail.from': 'Από', 'admin.mail.to': 'Έως', 'admin.mail.reset': 'Επαναφορά', 'admin.mail.total': 'Σύνολο', 'admin.mail.empty': 'Δεν υπάρχουν email logs', 'admin.mail.recipient': 'Παραλήπτης', 'admin.mail.provider': 'Πάροχος', 'admin.mail.details': 'Λεπτομέρειες', 'admin.mail.status': 'Κατάσταση', 'admin.mail.success': 'Επιτυχία', 'admin.mail.failed': 'Σφάλμα', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'Δεν υπάρχουν εγγραφές', 'admin.logs.date': 'Ημερομηνία', 'admin.logs.provider': 'Πάροχος', 'admin.logs.model': 'Μοντέλο', 'admin.logs.action': 'Ενέργεια', 'admin.logs.langs': 'Γλώσσες', 'admin.logs.in': 'Είσοδος', 'admin.logs.out': 'Έξοδος', 'admin.logs.total': 'Σύνολο', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Κατάσταση', 'admin.stats.activity_30d': 'Δραστηριότητα 30 ημερών', 'admin.stats.tasks_label': 'Εργασίες', 'admin.stats.users_label': 'Χρήστες', 'admin.stats.specialists_label': 'Ειδικοί', 'admin.stats.tokens_title': 'Χρήση tokens (ανά μήνα)', 'admin.stats.tokens_out': 'Εξερχόμενα', 'admin.stats.tokens_in': 'Εισερχόμενα', 'admin.stats.tokens_out_label': 'Εξερχόμενα tokens', 'admin.stats.tokens_in_label': 'Εισερχόμενα tokens', 'admin.stats.cost_label': 'Κόστος (USD)', 'admin.stats.tasks_by_status': 'Εργασίες ανά κατάσταση', 'admin.task_status.open': 'Ανοιχτές', 'admin.task_status.in_progress': 'Σε εξέλιξη', 'admin.task_status.completed': 'Ολοκληρωμένες', 'admin.task_status.cancelled': 'Ακυρωμένες', 'admin.task_status.draft': 'Προσχέδια', 'admin.settings.tab.general': 'Γενικά', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Ειδοποιήσεις', 'admin.settings.tab.payment': 'Πληρωμή', 'admin.settings.tab.referral': 'Παραπομπές', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Κοινωνικά δίκτυα', 'admin.settings.socials.title': 'Σύνδεσμοι κοινωνικών δικτύων', 'admin.settings.socials.hint': 'Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο', 'admin.settings.seo.maintenance_label': 'Λειτουργία συντήρησης', 'admin.settings.seo.maintenance_hint': 'Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες', 'admin.settings.seo.indexing_label': 'Ευρετηρίαση από μηχανές αναζήτησης', 'admin.settings.seo.indexing_hint': 'Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο', 'admin.settings.seo.head_scripts_label': 'Scripts στο (JS)', 'admin.settings.seo.head_scripts_hint': 'Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)', 'admin.settings.seo.site_title_label': 'Τίτλος ιστότοπου', 'admin.settings.seo.site_description_label': 'Περιγραφή ιστότοπου (meta description)', 'admin.settings.referral.title': 'Πρόγραμμα παραπομπών', 'admin.settings.referral.hint': 'Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.', 'admin.settings.referral.enabled_label': 'Ενεργό', 'admin.settings.referral.enabled_hint': 'Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών', 'admin.settings.referral.customer_section': 'Για πελάτες', 'admin.settings.referral.specialist_section': 'Για ειδικούς', 'admin.settings.referral.plan_label': 'Πλάνο ανταμοιβής', 'admin.settings.referral.no_plan': '— χωρίς πλάνο —', 'admin.settings.referral.plan_hint': 'Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.', 'admin.settings.referral.days_label': 'Ημέρες ανταμοιβής', 'admin.settings.referral.days_hint': 'Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.', 'admin.settings.general.title': 'Γενικές ρυθμίσεις', 'admin.settings.general.site_name': 'Όνομα ιστότοπου', 'admin.settings.general.site_url': 'URL ιστότοπου', 'admin.settings.general.contact_email': 'Email επικοινωνίας', 'admin.settings.general.support_phone': 'Τηλέφωνο υποστήριξης', 'admin.settings.smtp.title': 'Ρυθμίσεις SMTP', 'admin.settings.smtp.hint': 'Χρησιμοποιείται για αποστολή ειδοποιήσεων email.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Θύρα', 'admin.settings.smtp.encryption': 'Κρυπτογράφηση', 'admin.settings.smtp.enc.none': 'Χωρίς', 'admin.settings.smtp.enc.tls': 'STARTTLS (θύρα 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (θύρα 465)', 'admin.settings.smtp.username': 'Όνομα χρήστη', 'admin.settings.smtp.password': 'Κωδικός / App Password', 'admin.settings.smtp.from_name': 'Όνομα αποστολέα', 'admin.settings.smtp.from_email': 'Email αποστολέα', 'admin.settings.smtp.test': 'Αποστολή δοκιμαστικού email', 'admin.settings.smtp.sending': 'Αποστολή...', 'admin.settings.payment.hint': 'Τα στοιχεία για ePay Piraeus Bank.', 'admin.settings.env.test': 'Δοκιμαστικό (sandbox)', 'admin.settings.env.prod': 'Παραγωγή', 'admin.settings.env.label': 'Περιβάλλον', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Ενεργό', 'admin.settings.saving': 'Αποθήκευση...', 'admin.settings.saved': '✓ Αποθηκεύτηκε', 'admin.notif.vars_hint': 'Διαθέσιμες μεταβλητές στα πρότυπα', 'admin.notif.tmpl.not_set': 'Πρότυπο δεν έχει οριστεί', 'admin.notif.tmpl.subject_label': 'Θέμα email', 'admin.notif.tmpl.body_label': 'Κείμενο email (HTML)', 'admin.notif.tmpl.save': 'Αποθήκευση', 'admin.notif.tmpl.close': 'Κλείσιμο', 'admin.notif.tmpl.translate': 'Αυτόματη μετάφραση', 'admin.notif.tmpl.translating': 'Μετάφραση...', 'admin.notif.tmpl.saving': 'Αποθήκευση...', 'admin.notif.email_verification': 'Επαλήθευση email', 'admin.notif.registration_success': 'Επιτυχής εγγραφή', 'admin.notif.password_reset': 'Επαναφορά κωδικού', 'admin.notif.new_offer': 'Νέα προσφορά', 'admin.notif.new_task': 'Νέα εργασία', 'admin.notif.offer_accepted': 'Προσφορά αποδεκτή', 'admin.notif.new_message': 'Νέο μήνυμα', 'admin.notif.offer_declined': 'Απόρριψη προσφοράς', 'admin.notif.offer_other_accepted': 'Επιλέχθηκε άλλος ειδικός', 'admin.notif.task_updated': 'Ενημέρωση εργασίας', 'admin.notif.deadline_reminder': 'Υπενθύμιση προθεσμίας', 'admin.notif.task_archived': 'Αυτόματη απόσυρση εργασίας', 'admin.notif.referral_reward': 'Ανταμοιβή παραπομπής', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Τιμολόγιο — ενεργοποίηση πλάνου', 'admin.email_template.plan_upgraded': 'Τιμολόγιο — αναβάθμιση πλάνου', 'admin.email_template.plan_downgrade_scheduled': 'Τιμολόγιο — προγραμματισμένη υποβάθμιση', 'admin.email_template.plan_downgrade_applied': 'Τιμολόγιο — εφαρμογή υποβάθμισης', 'admin.email_template.plan_renewal_reminder': 'Τιμολόγιο — υπενθύμιση ανανέωσης', 'admin.email_template.plan_insufficient_funds': 'Τιμολόγιο — ανεπαρκές υπόλοιπο', // Pricing confirm modal 'pricing.confirm.title': 'Επιβεβαίωση επιλογής πλάνου', 'pricing.confirm.plan': 'Πλάνο', 'pricing.confirm.prorated': 'Αναλογική έκπτωση', 'pricing.confirm.effective_price': 'Προς πληρωμή', 'pricing.confirm.your_balance': 'Το υπόλοιπό σας', 'pricing.confirm.downgrade_info': 'Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.', 'pricing.confirm.insufficient': 'Ανεπαρκές υπόλοιπο.', 'pricing.confirm.top_up': 'Ανανέωση', 'pricing.confirm.schedule_downgrade': 'Προγραμματισμός μετάβασης', 'pricing.confirm.pay': 'Πληρωμή', 'admin.user_edit.title': 'Επεξεργασία χρήστη', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Διευθυνση email επαληθεύτηκε', 'admin.user_edit.email_not_verified': 'Email δεν έχει επαληθευτεί', 'admin.user_edit.verify_email_btn': 'Χειροκίνητη επαλήθευση', 'admin.user_edit.verify_email_done': 'Email επαληθεύτηκε!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Εγγραφή', 'admin.user_edit.last_seen': 'Τελευταία σύνδεση', 'admin.user_edit.lang': 'Γλώσσα', 'admin.user_edit.first_name': 'Όνομα', 'admin.user_edit.last_name': 'Επώνυμο', 'admin.user_edit.phone': 'Τηλέφωνο', 'admin.user_edit.bio': 'Βιογραφικό', 'admin.user_edit.role': 'Ρόλος', 'admin.user_edit.plan': 'Πακέτο', 'admin.user_edit.no_plan': '— Χωρίς πακέτο —', 'admin.user_edit.active': 'Ενεργός λογαριασμός', 'admin.user_edit.balance': 'Υπόλοιπο (EUR)', 'admin.user_edit.skills': 'Δεξιότητες', 'admin.user_edit.tab.profile': 'Προφίλ', 'admin.user_edit.tab.account': 'Λογαριασμός', 'admin.user_edit.tab.balance': 'Υπόλοιπο', 'admin.user_edit.tab.settings': 'Ρυθμίσεις', 'admin.user_edit.tab.specialist': 'Χαρτοφυλάκιο', 'admin.user_edit.tab.site': 'Ιστοσελίδα', 'admin.user_edit.plan_expires': 'Λήξη πλάνου', 'admin.user_edit.interface_lang': 'Γλώσσα διεπαφής', 'admin.user_edit.comm_languages': 'Γλώσσες επικοινωνίας', 'admin.user_edit.personal_site_slug': 'Προσωπική σελίδα', 'admin.user_edit.show_contact_info': 'Εμφάνιση στοιχείων επικοινωνίας', 'admin.user_edit.show_contact_info.hint': 'Ορατό στους πελάτες', 'admin.user_edit.notify_new_tasks': 'Ειδοποίηση για νέες εργασίες', 'admin.user_edit.notify_new_tasks.hint': 'Push και email ειδοποιήσεις', 'admin.user_edit.notif_messages': 'Ειδοποιήσεις μηνυμάτων', 'admin.user_edit.notif_messages.hint': 'Νέα μηνύματα στη συνομιλία', 'admin.user_edit.site_settings': 'Ρυθμίσεις προσωπικής σελίδας', 'admin.user_edit.categories': 'Κατηγορίες υπηρεσιών', 'admin.user_edit.locations': 'Περιοχές εξυπηρέτησης', 'admin.user_edit.skill_placeholder': 'Νέα δεξιότητα...', 'admin.user_edit.add_category': '— Επιλέξτε κατηγορία —', 'admin.user_edit.add_location': '— Επιλέξτε περιοχή —', 'admin.user_edit.specialist_cards': 'Χαρτοφυλάκιο ειδικού', 'admin.user_edit.no_cards': 'Δεν βρέθηκαν στοιχεία χαρτοφυλακίου', 'admin.user_edit.card_title': 'Τίτλος χαρτοφυλακίου', 'admin.user_edit.card_description': 'Περιγραφή', 'admin.balance.topup.btn': 'Αναπλήρωση', 'admin.balance.withdraw.btn': 'Αφαίρεση', 'admin.balance.modal_hint': 'Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό', 'admin.balance.topup.title': 'Αναπλήρωση υπολοίπου', 'admin.balance.topup.amount': 'Ποσό', 'admin.balance.topup.description': 'Σχόλιο', 'admin.balance.topup.description.placeholder': 'Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση', 'admin.balance.topup.submit': 'Αναπλήρωση υπολοίπου', 'admin.balance.withdraw.title': 'Αφαίρεση υπολοίπου', 'admin.balance.withdraw.amount': 'Ποσό', 'admin.balance.withdraw.description': 'Σχόλιο', 'admin.balance.withdraw.description.placeholder': 'Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση', 'admin.balance.withdraw.submit': 'Αφαίρεση από το υπόλοιπο', 'admin.user_edit.role.customer': 'Πελάτης', 'admin.user_edit.role.specialist': 'Ειδικός', 'admin.user_edit.role.admin': 'Διαχειριστής', 'common.refresh': 'Ανανέωση', 'common.back_home': 'Αρχική', 'admin.loc.hint': 'Διαχείριση πόλεων και συνοικιών', 'admin.loc.add_city': 'Νέα πόλη', 'admin.loc.add_district': 'Προσθήκη συνοικίας', 'admin.loc.new': 'Νέα τοποθεσία', 'admin.loc.edit': 'Επεξεργασία τοποθεσίας', 'admin.loc.district': 'συνοικία', 'admin.loc.empty': 'Δεν υπάρχουν τοποθεσίες', 'admin.loc.delete.confirm': 'Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.', 'admin.cat.add_root': 'Νέα κατηγορία', 'admin.cat.add_sub': 'Υποκατηγορία', 'admin.cat.edit': 'Επεξεργασία', 'admin.cat.delete': 'Διαγραφή', 'admin.cat.delete.confirm': 'Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Εικονίδιο', 'admin.cat.name_el': 'Ελληνικά', 'admin.cat.name_en': 'Αγγλικά', 'admin.cat.name_ru': 'Ρωσικά', 'admin.cat.order': 'Σειρά', 'admin.cat.active': 'Ενεργή', 'admin.cat.parent': 'Γονική κατηγορία', 'admin.cat.no_parent': 'Κορυφαίο επίπεδο', 'admin.cat.save': 'Αποθήκευση', 'admin.cat.cancel': 'Ακύρωση', 'admin.cat.empty': 'Δεν υπάρχουν κατηγορίες', 'admin.cat.hint': 'Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία', 'admin.cat.new': 'Νέα κατηγορία', 'admin.cat.subcategory': 'υποκατηγορία', 'admin.cat.add_child': 'Προσθήκη υποκατηγορίας', 'admin.cat.inactive': 'Ανενεργή', 'admin.event.user_login': 'Σύνδεση', 'admin.event.user_register': 'Εγγραφή', 'admin.event.admin_user_deactivate': 'Αποκλεισμός χρήστη', 'admin.event.admin_user_activate': 'Ενεργοποίηση χρήστη', 'admin.event.admin_user_role_changed': 'Αλλαγή ρόλου', 'admin.event.admin_task_cancelled': 'Ακύρωση εργασίας', 'admin.event.admin_task_deleted': 'Διαγραφή εργασίας', 'admin.event.admin_report_reviewed': 'Αναφορά εξετάστηκε', 'admin.event.admin_report_dismissed': 'Αναφορά απορρίφθηκε', 'admin.event.task_created': 'Δημιουργία εργασίας', 'user.online': 'Σε σύνδεση', 'user.seen_minutes': 'ήταν εδώ πριν {n} λεπτά', 'user.seen_hours': 'ήταν εδώ πριν {n} ώρες', 'user.seen_yesterday': 'ήταν εδώ χθες', 'user.seen_days': 'ήταν εδώ πριν {n} μέρες', // Specialists 'specialists.title': 'Ειδικοί', 'specialists.search': 'Αναζήτηση ειδικού...', 'specialists.search.btn': 'Αναζήτηση', 'specialists.empty': 'Δεν βρέθηκαν ειδικοί', 'specialists.no_bio': 'Χωρίς περιγραφή', 'specialists.view': 'Προβολή προφίλ', 'specialists.reviews': 'αξιολογήσεις', 'specialist.favorite': 'Προσθήκη στα αγαπημένα', 'specialist.unfavorite': 'Αφαίρεση από αγαπημένα', 'specialist.site_link': 'Προσωπικό site', 'favorites.specialists.title': 'Αγαπημένοι ειδικοί', 'favorites.specialists.empty': 'Δεν έχετε αγαπημένους ειδικούς', 'nav.favorites': 'Αγαπημένα', 'nav.schedule': 'Πρόγραμμα', 'nav.find_tasks': 'Αναζήτηση εργασιών', 'schedule.title': 'Το πρόγραμμά μου', 'schedule.subtitle': 'Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας', 'schedule.available': 'Ελεύθερος', 'schedule.busy': 'Απασχολημένος', 'schedule.unset': 'Μη ορισμένο', 'schedule.click_hint': '← κλικ για εναλλαγή κατάστασης', 'schedule.range_mode': 'Επιλογή εύρους', 'schedule.range_from': 'Από {date} — επιλέξτε τελική ημερομηνία', 'schedule.click_to_set': 'Κλικ για ορισμό', 'schedule.free': 'ελεύθερα', 'schedule.busy_count': 'απασχολημένα', 'schedule.free_days': 'ελεύθερες ημέρες', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Σύνδεση με Google Calendar', 'schedule.disconnectGoogle': 'Αποσύνδεση', 'schedule.connectedAs': 'Συνδεδεμένο ως', 'schedule.importFromGoogle': 'Συγχρονισμός από Google', 'schedule.gcalConnected': '✓ Google Calendar συνδέθηκε', 'schedule.gcalError': 'Σφάλμα σύνδεσης Google Calendar', 'schedule.gcalImportDone': 'Εισήχθησαν {n} ημερ. από Google Calendar', 'schedule.gcalAutoSyncNote': 'Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar', 'schedule.gcalConnectDesc': 'Συνδέστε το Google Calendar για αυτόματο συγχρονισμό', 'schedule.gcalDisconnectConfirm': 'Αποσύνδεση Google Calendar;', 'find_tasks.title': 'Αναζήτηση εργασιών', 'find_tasks.for_me': 'Για μένα', 'find_tasks.all': 'Όλες οι εργασίες', 'find_tasks.by_category': 'Ανά κατηγορία', 'find_tasks.list': 'Λίστα', 'find_tasks.already_offered': 'Προσφορά υποβλήθηκε', 'find_tasks.offer_now': 'Υποβολή προσφοράς', 'find_tasks.empty_for_me': 'Δεν βρέθηκαν εργασίες στις κατηγορίες σας', 'find_tasks.banner_hint': 'Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας', 'find_tasks.no_cards': 'Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς', 'find_tasks.add_card': 'Δημιουργία χαρτοφυλακίου', 'find_tasks.search': 'Αναζήτηση εργασιών...', 'find_tasks.tasks_count': 'εργασίες', // Footer 'footer.tagline': 'Η πλατφόρμα εργασιών για την Ελλάδα', 'footer.rights': 'Όλα τα δικαιώματα διατηρούνται.', // App download section 'app.download_title': 'Κατεβάστε την εφαρμογή CanHelp', 'app.download_desc': 'Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.', // Nav 'nav.pricing': 'Τιμές', // Pricing page 'pricing.title': 'Τιμολόγηση', 'pricing.subtitle': 'Επιλέξτε το κατάλληλο πρόγραμμα', 'pricing.role.customer': 'Πελάτης', 'pricing.role.specialist': 'Ειδικός', 'pricing.free': 'Δωρεάν', 'pricing.per_month': 'μήνα', 'pricing.duration': 'Διάρκεια', 'pricing.days': 'ημ.', 'pricing.current_plan': 'Το πρόγραμμά σας', 'pricing.popular': 'Δημοφιλές', 'pricing.choose': 'Επιλογή', 'pricing.your_plan': 'Ενεργό πρόγραμμα', 'pricing.free_default': 'Προεπιλογή', 'pricing.compare': 'Σύγκριση λειτουργιών', 'pricing.feature': 'Λειτουργία', 'pricing.faq_note': 'Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.', 'pricing.feat.messages': 'Μηνύματα / ημέρα', 'pricing.feat.orders': 'Παραγγελίες / ημέρα', 'pricing.feat.contact_all': 'Επικοινωνία με όλους', 'pricing.feat.view_phone': 'Εμφάνιση τηλεφώνου', 'pricing.feat.show_contact': 'Εμφάνιση στοιχείων επαφής', 'pricing.feat.favorites': 'Αγαπημένα', 'pricing.feat.verified_badge': 'Επαληθευμένο badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Προσωπικό site', 'pricing.feat.auto_response': 'Αυτόματη απάντηση', 'pricing.feat.auto_match': 'Αυτόματη αντιστοίχιση', 'pricing.feat.highlighted_reviews': 'Επισημασμένες αξιολογήσεις', 'pricing.feat.portfolio': 'Στοιχεία χαρτοφυλακίου', 'pricing.feat.cards': 'Κάρτες ειδικού', 'pricing.feat.notify_tasks': 'Ειδοποιήσεις νέων εργασιών', 'pricing.feat.video': 'Βίντεο στο χαρτοφυλάκιο', // Upgrade prompt 'upgrade.available_in': 'Διαθέσιμο στο', 'upgrade.cta': 'Αναβάθμιση', // Dashboard plan block 'dashboard.plan.title': 'Το πρόγραμμά μου', 'dashboard.plan.expires': 'Λήγει σε {n} ημέρες', 'dashboard.plan.upgrade': 'Αναβάθμιση προγράμματος', 'dashboard.plan.no_plan': 'Δωρεάν πρόγραμμα', 'dashboard.plan.messages': 'Μηνύματα σήμερα', 'dashboard.plan.orders': 'Παραγγελίες σήμερα', 'dashboard.plan.limits': 'Ημερήσια όρια', 'dashboard.plan.features': 'Λειτουργίες', 'dashboard.plan.stats': 'Στατιστικά', 'dashboard.stats.cards': 'Χαρτοφυλάκια', 'dashboard.stats.maxCards': 'Μέγ. χαρτοφυλάκια', 'dashboard.stats.portfolioItems': 'Στοιχεία portfolio', 'dashboard.stats.maxPortfolioItems': 'Μέγ. στοιχεία', 'dashboard.stats.activeOffers': 'Ενεργές προσφορές', 'dashboard.stats.reviewsReceived': 'Αξιολογήσεις', 'dashboard.stats.activeTasks': 'Ενεργές εργασίες', 'dashboard.stats.completedTasks': 'Ολοκληρωμένες', 'status.can_help_now': 'Είμαι διαθέσιμος τώρα', 'status.need_help': 'Χρειάζομαι βοήθεια', 'status.active': 'Ενεργό', 'status.toggle_on': 'Ενεργοποίηση', 'status.toggle_off': 'Απενεργοποίηση', // FOMO 'fomo.missed_orders': 'Χάσατε {n} παραγγελίες', 'fomo.missed_value': 'Αξία €{v}', 'fomo.upgrade_hint': 'Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες', 'fomo.conversion': 'Μετατροπές εργασιών', 'fomo.active': 'Ενεργές', 'fomo.with_offers': 'Με προσφορές', 'fomo.completed': 'Ολοκληρωμένες', 'fomo.already_offered': '{n} ειδικοί έχουν ήδη απαντήσει', 'fomo.specialist_missed': 'Χάσατε {n} παραγγελίες', 'fomo.top_categories': 'Κατηγορίες', 'fomo.offers_received': 'προσφορές ελήφθησαν', 'fomo.avg_offers': 'Μέσο {n}/εργασία', 'fomo.completion_rate': 'ολοκληρωμένες', // Task auto-match 'task.auto_match': 'Αυτόματη αντιστοίχιση', 'task.auto_match_results': 'Κορυφαίοι ειδικοί', 'task.no_offer_yet': 'Δεν έχετε στείλει προσφορά ακόμα', 'task.make_offer': 'Αποστολή προσφοράς', 'auto_response.title': 'Αυτόματη Απάντηση', 'auto_response.enabled': 'Ενεργοποίηση αυτόματης απάντησης', 'auto_response.min_budget': 'Ελάχ. προϋπολογισμός', 'auto_response.max_budget': 'Μέγ. προϋπολογισμός', 'auto_response.default_price': 'Προεπιλεγμένη τιμή', 'auto_response.default_message': 'Προεπιλεγμένο μήνυμα', 'auto_response.max_per_day': 'Μέγ. αυτόματες προσφορές/ημέρα', 'auto_response.save': 'Αποθήκευση', 'auto_response.saved': 'Αποθηκεύτηκε', 'auto_response.categories': 'Κατηγορίες', 'auto_response.locations': 'Τοποθεσίες', // Personal site 'profile.personal_site': 'Προσωπικό Site', 'profile.site_slug': 'Slug URL', 'profile.site_slug_hint': 'Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _', 'profile.site_open': 'Άνοιγμα site', 'profile.site_preview': 'Το site σας', 'profile.show_contact': 'Εμφάνιση στοιχείων επαφής', 'profile.show_contact_hint': 'Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας', // Google Calendar plan gate 'gcal.upgrade_required': 'Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα', // Chat limits 'chat.limit_warning': 'Απομένουν {n} μηνύματα σήμερα', 'chat.limit_reached': 'Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας', 'chat.upgrade': 'Αναβάθμιση', // Site page 'site.member_since': 'Μαζί μας από', 'site.rating': 'Βαθμολογία', 'site.completed_tasks': 'Ολοκληρώθηκαν', 'site.languages': 'Γλώσσες', 'site.photos': 'φωτ.', 'site.contact_form': 'Επικοινωνία', 'site.contact_sent': 'Το μήνυμα στάλθηκε!', 'site.contact_sent_desc': 'Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα', 'site.contact_name': 'Όνομα', 'site.contact_name_ph': 'Το όνομά σας', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Μήνυμα', 'site.contact_message_ph': 'Περιγράψτε την εργασία σας...', 'site.contact_send': 'Αποστολή', 'site.share': 'Κοινοποίηση', 'site.speaks_languages': 'Μιλάει', 'site.message_sent': 'Το μήνυμα εστάλη!', 'site.message_sent_desc': 'Ο ειδικός θα το λάβει στη συνομιλία', 'site.message_placeholder': 'Γράψτε το μήνυμά σας...', 'site.write_to_chat': 'Γράψτε στο chat', 'site.auth_required_title': 'Απαιτείται σύνδεση', 'site.auth_required_desc': 'Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.', 'site.auth_login_btn': 'Σύνδεση', 'site.auth_contact_form_btn': 'Επικοινωνία μέσω φόρμας', 'specialist.services': 'Υπηρεσίες', 'portfolio.title': 'Χαρτοφυλάκιο', 'common.not_found': 'Η σελίδα δεν βρέθηκε', 'common.anonymous': 'Ανώνυμα', 'specialist_setup.page_title': 'Ρύθμιση προφίλ ειδικού', 'specialist_setup.step_of': 'Βήμα {current} από {total}', 'specialist_setup.next': 'Επόμενο', 'specialist_setup.back': 'Πίσω', 'specialist_setup.skip': 'Παράλειψη', 'specialist_setup.finish': 'Ολοκλήρωση', 'specialist_setup.go_to_profile': 'Μεταβείτε στο προφίλ', 'specialist_setup.browse_tasks': 'Εξερεύνηση εργασιών', 'specialist_setup.step1.title': 'Καλωσήλθατε!', 'specialist_setup.step1.subtitle': 'Ας ρυθμίσουμε το προφίλ σας', 'specialist_setup.step1.desc': 'Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.', 'specialist_setup.step1.what_next': 'Τι θα κάνουμε:', 'specialist_setup.step1.item1': 'Συμπλήρωση βασικών πληροφοριών', 'specialist_setup.step1.item2': 'Δημιουργία κάρτας υπηρεσίας', 'specialist_setup.step1.item3': 'Προσθήκη δεξιοτήτων και κατηγοριών', 'specialist_setup.step1.item4': 'Επιλογή γεωγραφικής περιοχής', 'specialist_setup.step1.item5': 'Μεταφόρτωση φωτογραφιών χαρτοφυλακίου', 'specialist_setup.step2.title': 'Βασικό προφίλ', 'specialist_setup.step2.subtitle': 'Πείτε μας για σας', 'specialist_setup.step2.bio_label': 'Σχετικά με εμένα', 'specialist_setup.step2.bio_placeholder': 'Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...', 'specialist_setup.step2.phone_label': 'Τηλέφωνο', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Φωτογραφία προφίλ', 'specialist_setup.step2.photo_btn': 'Μεταφόρτωση φωτογραφίας', 'specialist_setup.step2.photo_uploading': 'Μεταφόρτωση...', 'specialist_setup.step2.photo_hint': 'Εμφανίζεται στο προφίλ σας', 'specialist_setup.step3.title': 'Κάρτα υπηρεσίας', 'specialist_setup.step3.subtitle': 'Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας', 'specialist_setup.step3.title_label': 'Τίτλος κάρτας', 'specialist_setup.step3.title_placeholder': 'Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...', 'specialist_setup.step3.desc_label': 'Περιγραφή', 'specialist_setup.step3.desc_placeholder': 'Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...', 'specialist_setup.step3.title_required': 'Απαιτείται τίτλος', 'specialist_setup.step4.title': 'Δεξιότητες & Κατηγορίες', 'specialist_setup.step4.subtitle': 'Προσθέστε δεξιότητες και επιλέξτε κατηγορίες', 'specialist_setup.step4.skills_label': 'Δεξιότητες', 'specialist_setup.step4.skills_placeholder': 'Π.χ. Εγκατάσταση σωληνώσεων...', 'specialist_setup.step4.skills_add': 'Προσθήκη', 'specialist_setup.step4.categories_label': 'Κατηγορίες', 'specialist_setup.step5.title': 'Γεωγραφική περιοχή', 'specialist_setup.step5.subtitle': 'Πού παρέχετε υπηρεσίες;', 'specialist_setup.step5.hint': 'Επιλέξτε πόλεις ή συγκεκριμένες περιοχές', 'specialist_setup.done.title': 'Το προφίλ σας είναι έτοιμο!', 'specialist_setup.done.subtitle': 'Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί', 'specialist_setup.done.desc': 'Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας.' }, en: { 'footer.slogan': 'Your task — our care! We solve any issue quickly and easily.', 'footer.links': 'Links', 'footer.socials': 'Socials', 'nav.home': 'Home', 'nav.tasks': 'Tasks', 'nav.post': '+ Post task', 'nav.dashboard': 'Dashboard', 'nav.chat': 'Messages', 'nav.notifications': 'Notifications', 'nav.profile': 'Profile', 'nav.admin': 'Admin Panel', 'nav.specialists': 'Specialists', 'nav.new_task': 'New task', 'nav.login': 'Login', 'nav.register': 'Register', 'nav.logout': 'Logout', 'hero.title': 'Find a specialist for any job', 'hero.subtitle': 'Post a task, receive offers and choose the best professional', 'hero.cta.post': 'Post a task', 'hero.cta.browse': 'Become a specialist', 'hero.search.placeholder': 'What do you need? e.g. electrician, cleaning...', 'stats.specialists': 'specialists', 'stats.tasks': 'tasks', 'stats.categories': 'categories', 'stats.free': 'free sign-up', 'section.categories': 'Create a task in any category', 'section.how': 'How it works', 'section.recent': 'Recent tasks', 'section.all': 'See all →', 'section.more': 'more', 'section.cities': 'Cities & Districts', 'section.community': 'A community project for everyone', 'community.subtitle': 'CanHelp is not just a marketplace — it\'s a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.', 'community.point1.title': 'Are you good at something?', 'community.point1.desc': 'Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.', 'community.point2.title': 'Need help with something?', 'community.point2.desc': 'Post a task in under a minute and receive offers from verified specialists in your city.', 'community.point3.title': 'Help the project grow', 'community.point3.desc': 'CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.', 'community.share': 'Share with friends', 'community.share.copied': 'Link copied!', // Referral section on home page 'section.referral': 'Referral Program', 'referral.home.subtitle': 'Share your link — every new user who signs up through it earns you a reward.', 'referral.home.step1.title': 'Sign up and get your link', 'referral.home.step1.desc': 'Create an account and find your unique referral link in your profile.', 'referral.home.step2.title': 'Share with friends', 'referral.home.step2.desc': 'Send the link to friends, acquaintances, or post it on social media.', 'referral.home.step3.title': 'Earn rewards', 'referral.home.step3.desc': 'Once your friend verifies their email, you automatically receive your reward.', 'referral.home.cta': 'Get your link', 'referral.home.badge': 'Referral Program', // FAQ section 'section.faq': 'Frequently Asked Questions', 'faq.q1': 'How does CanHelp work?', 'faq.a1': 'Post a task, receive offers from specialists, choose the best one and start working together. It\'s fast, simple and free for customers.', 'faq.q2': 'How much does it cost to use the platform?', 'faq.a2': 'Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.', 'faq.q3': 'How can I become a specialist?', 'faq.a3': 'Register, go to «Become a Specialist», fill in your profile with skills and categories, and start receiving tasks.', 'faq.q4': 'How do I choose the right specialist?', 'faq.a4': 'Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.', 'faq.q5': 'What if I am not satisfied?', 'faq.a5': 'You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.', 'faq.q6': 'Can I contact a specialist before accepting their offer?', 'faq.a6': 'Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.', 'faq.q7': 'How long does it take to receive offers?', 'faq.a7': 'Usually within a few hours. Specialists get notified about new tasks and can respond quickly.', 'faq.q8': 'Can I post a task in any city in Greece?', 'faq.a8': 'Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.', 'faq.q9': 'What types of tasks can I find on CanHelp?', 'faq.a9': 'Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.', 'faq.q10': 'Is there a mobile app?', 'faq.a10': 'Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.', 'how.step1.title': 'Post a task', 'how.step1.desc': 'Describe what you need and set your budget', 'how.step2.title': 'Receive offers', 'how.step2.desc': 'Specialists will send you offers with price and timeline', 'how.step3.title': 'Choose & start', 'how.step3.desc': 'Pick the best professional and start the collaboration', 'tasks.title': 'tasks', 'tasks.filters': 'Filters', 'tasks.search': 'Search', 'tasks.search.placeholder': 'Title or keyword...', 'tasks.search.btn': 'Search', 'tasks.publish': 'Post', 'tasks.category.all': 'All', 'tasks.category.all_in': 'All in', 'tasks.category.label': 'Category', 'tasks.location.label': 'City', 'tasks.location.placeholder': 'e.g. Athens', 'tasks.empty': 'No tasks found', 'tasks.empty.cta': 'Post the first one', 'task.status.open': 'Open', 'task.status.in_progress': 'In progress', 'task.status.completed': 'Completed', 'task.status.cancelled': 'Cancelled', 'task.status.draft': 'Draft', 'task.budget': 'Budget', 'task.location': 'Location', 'task.deadline': 'Start date', 'task.created_at': 'Created', 'task.customer': 'Customer', 'task.offer.btn': 'Submit offer', 'task.invite.banner_title': "You've been invited to this task", 'task.invite.banner_hint': 'The customer personally invited you', 'task.invite.accept': 'Send offer', 'task.invite.decline': 'Decline', 'offer.accept': 'Accept', 'offer.decline': 'Decline', 'task.complete': 'Complete task', 'task.complete.confirm': 'Mark this task as complete?', 'task.edit': 'Edit', 'task.status_label': 'Status', 'task.yours': 'Your task', 'task.offer.yours': 'Your offer', 'review.leave': 'Leave a review', 'review.rating': 'Rating', 'review.comment': 'Comment', 'review.comment.placeholder': 'Tell us about your experience...', 'review.submit': 'Submit review', 'review.submitting': 'Submitting...', 'review.done': 'Review submitted!', 'profile.reviews': 'Reviews', 'profile.no_reviews': 'No reviews yet', 'profile.rating': 'Rating', 'profile.skills.label': 'Skills', 'profile.member_since': 'Member since', 'task.offers': 'Offers', 'task.offers.none': 'No offers yet', 'create.title': 'Post a task', 'create.field.title': 'Title', 'create.field.description': 'Description', 'create.field.category': 'Category', 'create.field.category.select': 'Select...', 'create.field.location': 'Location', 'create.field.location.any': 'Anywhere', 'create.field.location.all': 'Entire city', 'create.field.budget': 'Budget (€)', 'create.field.deadline': 'Start date', 'create.field.budget_negotiable': 'Price is negotiable', 'create.field.time_slot': 'Time slot', 'create.field.time_slot.any': 'Anytime', 'create.field.time_slot.morning': 'Morning (08:00–13:00)', 'create.field.time_slot.afternoon': 'Afternoon (13:00–18:00)', 'create.field.time_slot.evening': 'Evening (18:00–22:00)', 'create.field.time_slot.weekend': 'Weekend', 'create.field.address': 'Address (optional)', 'create.field.address.district': 'District', 'create.field.address.street': 'Street', 'create.field.address.house': 'Number', 'create.field.confidential': 'Confidential note', 'create.field.confidential.placeholder': 'Details visible only to the assigned specialist...', 'create.field.confidential.hint': 'Not shown publicly', 'create.field.photos': 'Photos', 'create.field.photos.add': 'Add photo', 'create.field.photos.uploading': 'Uploading...', 'task.budget_negotiable': 'Price negotiable', 'task.time_slot': 'Time slot', 'task.confidential': 'Confidential note', 'create.field.title.placeholder': 'e.g. Clean 80sqm apartment', 'create.field.description.placeholder': 'Describe in detail what you need...', 'create.field.location.placeholder': 'e.g. Athens, Kolonaki', 'create.field.budget.placeholder': 'e.g. 100', 'create.submit': 'Post task', 'create.submitting': 'Posting...', 'login.title': 'Welcome back', 'login.subtitle': 'Sign in to CanHelp', 'login.email': 'Email', 'login.password': 'Password', 'login.submit': 'Sign in', 'login.submitting': 'Signing in...', 'login.error': 'Invalid email or password', 'login.unverified.title': 'Verify your email address', 'login.unverified.desc': 'We sent a verification link to your email. Check your inbox (or spam) and click the link.', 'login.unverified.resend': 'Resend verification email', 'login.unverified.sending': 'Sending...', 'login.unverified.sent': '✓ Sent — check your inbox', 'profile.email.verified': 'Email verified', 'profile.email.not_verified': 'Email not verified', 'login.no_account': "Don't have an account?", 'login.register_link': 'Register', 'login.forgot_password': 'Forgot password?', 'login.or_continue_with': 'or continue with', 'login.continue_google': 'Continue with Google', 'forgot.title': 'Forgot password', 'forgot.subtitle': 'Enter your email to receive a reset link', 'forgot.email': 'Email', 'forgot.submit': 'Send reset link', 'forgot.submitting': 'Sending...', 'forgot.sent.title': 'Check your inbox', 'forgot.sent.desc': 'If an account exists with that email, we\'ll send you a password reset link.', 'forgot.back_to_login': 'Back to sign in', 'forgot.error': 'Could not send reset link. Check the email address and try again.', 'forgot.error.not_found': 'No account found with this email address.', 'forgot.error.send_failed': 'Failed to send email. Please try again later.', 'reset.title': 'New password', 'reset.subtitle': 'Enter your new password', 'reset.password': 'New password', 'reset.confirm': 'Confirm password', 'reset.submit': 'Change password', 'reset.submitting': 'Saving...', 'reset.success': 'Password changed successfully. Redirecting to sign in...', 'reset.back_to_login': 'Back to sign in', 'reset.error.mismatch': 'Passwords do not match', 'reset.error.invalid': 'Invalid or expired link. Please request a new one.', 'register.title': 'Register', 'register.subtitle': 'Create a CanHelp account', 'register.first_name': 'First name', 'register.last_name': 'Last name', 'register.email': 'Email', 'register.password': 'Password (min 8 characters)', 'register.role': 'Role', 'register.role.customer': 'User', 'register.role.customer.desc': 'I post tasks', 'register.role.specialist': 'Specialist', 'register.role.specialist.desc': 'I take on tasks', 'register.submit': 'Create account', 'register.submitting': 'Registering...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Sign in', 'register.continue_google': 'Continue with Google', 'register.check_email.title': 'Check your email', 'register.check_email.desc': 'We sent a verification link to your email address. Check your inbox (or spam) and click the link.', 'register.check_email.login': 'Back to sign in', 'dashboard.title': 'Dashboard', 'dashboard.new_task': '+ New task', 'dashboard.my_tasks': 'My tasks', 'dashboard.my_offers': 'My offers', 'dashboard.invitations': 'Job invitations', 'dashboard.offers_count': 'offers', 'dashboard.declined_count': 'declined', 'dashboard.completed_tasks': 'Completed tasks', 'dashboard.completed_offers': 'Completed offers', 'dashboard.review_pending': 'Review not yet submitted', 'tasks.new.top_specialists': 'Top specialists', 'tasks.new.select_category': 'Select a category to see matching specialists', 'tasks.new.invite': 'Offer work', 'tasks.new.invited': 'Selected ✓', 'reviews.count': 'reviews', 'filter.location': 'Location', 'filter.language': 'Languages', 'filter.language.any': 'Any language', 'filter.category.all': 'All categories', 'user.categories': 'Categories', 'user.work_area': 'Work area', 'dashboard.tasks.empty': "You haven't posted any tasks", 'dashboard.tasks.empty.cta': 'Post your first one', 'dashboard.tasks.add_new': 'Add a new task', 'dashboard.offers.empty': "You haven't submitted any offers", 'dashboard.offers.empty.cta': 'Find tasks', 'dashboard.customer.specialists_title': 'Looking for a specialist?', 'dashboard.customer.specialists_hint': 'Browse specialist profiles, read reviews and invite them to your tasks', 'dashboard.customer.specialists_cta': 'Find a specialist', 'dashboard.customer.how_title': 'How it works', 'dashboard.customer.step1': 'Create a task with a description and budget', 'dashboard.customer.step2': 'Specialists will send offers with price and timeline', 'dashboard.customer.step3': 'Choose the right one and start working', 'notif.title': 'Notifications', 'notif.mark_all': 'Mark all as read', 'notif.empty': 'No notifications', 'notif.type.new_offer': 'New offer', 'notif.type.offer_accepted': 'Your offer was accepted', 'notif.type.offer_declined': 'Your offer was declined', 'notif.type.task_completed': 'Task completed', 'notif.type.task_cancelled': 'Task cancelled', 'notif.type.new_message': 'New message', 'notif.type.new_review': 'New review', 'notif.type.task_invite': 'Job invitation', 'notif.body.new_offer': 'New offer for «{title}»', 'notif.body.offer_accepted': 'Your offer for «{title}» was accepted', 'notif.body.offer_declined': 'Your offer for «{title}» was declined', 'notif.body.task_invite': 'You\'ve been invited for «{title}»', 'notif.body.new_review': 'You received a {rating}★ review', 'offer.status.pending': 'Pending', 'offer.status.accepted': 'Accepted', 'offer.status.declined': 'Declined', 'offer.status.withdrawn': 'Withdrawn', 'offer.status.other_accepted': 'Another specialist was chosen', 'common.loading': 'Loading...', 'common.error': 'Error', 'common.save': 'Save', 'common.saving': 'Saving...', 'common.cancel': 'Cancel', 'common.add': 'Add', 'common.close': 'Close', 'common.edit': 'Edit', 'common.delete': 'Delete', 'common.from': 'by', 'common.currency': '€', 'common.greece': 'Greece', // Chat 'chat.connected': 'Connected', 'chat.disconnected': 'Disconnected', 'chat.no_rooms': 'No conversations yet', 'chat.task_fallback': 'Task', 'chat.select': 'Select a conversation', 'chat.no_messages': 'No messages yet', 'chat.placeholder': 'Write a message... (Enter to send)', 'chat.conversation_fallback': 'Conversation', 'chat.direct_chat': 'Direct chat', 'chat.linked_task': 'Linked task', 'chat.write_btn': 'Message', 'chat.just_now': 'just now', 'chat.min_ago': 'm', 'chat.write_specialist': 'Write to specialist', 'chat.write_customer': 'Write to customer', 'chat.notif_settings': 'Notification settings', 'chat.notif_messages': 'Notifications for new messages', 'chat.toast_title': 'New message', 'chat.toast_open': 'Open chat', // Offer form 'offer.price': 'Price', 'offer.price.placeholder': 'e.g. 80', 'offer.customer_budget': 'Client budget', 'offer.message': 'Message', 'offer.optional': 'optional', 'offer.message.placeholder': 'Introduce yourself, your experience and why you are the best choice...', 'offer.submitting': 'Sending...', // Profile 'profile.photo': 'Profile photo', 'profile.photo.change': 'Change photo', 'profile.photo.hint': 'JPEG, PNG, WebP · up to 5MB', 'profile.basic_info': 'Basic info', 'profile.phone': 'Phone', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Short bio', 'profile.bio.placeholder': 'Tell us a bit about yourself...', 'profile.language': 'Language', 'profile.language.hint': 'App interface and email notification language', 'profile.languages': 'Languages spoken', 'profile.languages.hint': 'Select all languages you speak', 'profile.skills': 'Skills', 'profile.skills.subtitle': 'Add the services you offer', 'profile.skills.placeholder': 'e.g. Cleaning, IT, Tutoring...', 'profile.role': 'Account role', 'profile.role.specialist': '🔧 Specialist', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 User', 'profile.role.change': 'To change your role please contact support.', 'profile.become_specialist': 'Become a Specialist', 'profile.become_specialist.desc': 'Upgrade to Specialist to take on tasks and build your profile.', 'become_specialist.hero.title': 'Earn money doing what you do best', 'become_specialist.hero.subtitle': 'Create a specialist profile and receive orders from clients across Greece', 'become_specialist.how.title': 'How it works', 'become_specialist.step1.title': 'Create a specialist portfolio', 'become_specialist.step1.desc': 'Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks', 'become_specialist.step2.title': 'Find tasks', 'become_specialist.step2.desc': 'Discover tasks in your categories in the "Find Orders" section', 'become_specialist.step3.title': 'Send an offer & earn', 'become_specialist.step3.desc': 'Submit offers with price and timeline, chat with clients and complete tasks', 'become_specialist.benefits.title': 'Specialist profile advantages', 'become_specialist.benefit1': 'Task search filtered by your categories and location', 'become_specialist.benefit2': 'Public profile with client reviews', 'become_specialist.benefit3': 'Availability schedule visible to clients', 'become_specialist.benefit4': 'Saved to favourites by clients', 'become_specialist.cta': 'Learn more', 'become_specialist.free_badge': 'Free registration', 'profile.tab.notifications': 'Notifications', 'profile.tab.reviews': 'Reviews', 'profile.tab.referral': 'Referrals', 'profile.tab.auto_response': 'Auto-response', 'profile.tab.site': 'Site', 'profile.site.title': 'Personal page', 'profile.site.url_label': 'Personal site', 'profile.site.copy': 'Copy', 'profile.site.copied': 'Copied', 'profile.site.visible_title': "What's on your page", 'profile.site.visible.name': 'Name and photo', 'profile.site.visible.bio': 'Bio', 'profile.site.visible.rating': 'Rating and reviews', 'profile.site.visible.portfolio': 'Portfolio / Cards', 'profile.site.visible.contacts': 'Contact info', 'profile.site.visible.full_last_name': 'Full last name', 'profile.site.visible.services': 'Service cards', 'profile.site.visible.reviews': 'Reviews section', 'profile.site.visible.status': '"Ready to help" status', 'profile.site.theme': 'Appearance theme', 'profile.site.theme.dark': 'Dark', 'profile.site.theme.light': 'Light', 'profile.site.slug_taken': 'This address is already taken', 'profile.site.stats.title': 'Site analytics', 'profile.site.stats.days': 'last 30 days', 'profile.site.stats.views': 'Views', 'profile.site.stats.unique': 'Unique visitors', 'profile.site.stats.messages': 'Messages', 'profile.site.stats.total_views': 'Total views', 'profile.site.stats.total_unique': 'Unique visitors', 'profile.site.stats.total_messages': 'Messages', 'profile.site.stats.empty': 'No data yet', 'profile.site.stats.loading': 'Loading analytics...', 'profile.site.stats.no_slug': 'Set your site URL to see analytics', 'profile.site.edit_bio_hint': 'Bio and photo are edited in the "Basic info" tab.', 'status.title': 'Status', 'status.can_help_now_hint': 'Your card is shown higher in search', 'status.need_help_hint': 'Specialists can offer you help', 'profile.referral.title': 'Referral program', 'profile.referral.desc': 'Share your link and earn rewards for every new user you invite.', 'profile.referral.link_label': 'Your referral link', 'profile.referral.copy': 'Copy', 'profile.referral.copied': 'Copied!', 'profile.referral.invited_count': 'successful referrals', 'profile.referral.no_code': 'Referral code is not available.', 'notifications.title': 'Notification settings', 'notifications.email.new_tasks': 'Email for new tasks', 'notifications.email.new_tasks.desc': 'Receive an email when a new task is posted in your categories', 'notifications.messages.desc': 'Receive a notification when a new message arrives', 'notifications.saved': 'Settings saved', 'notifications.plan_required': 'Not available in your plan', 'profile.tab.info': 'Basic info', 'profile.tab.finance': 'Finance', 'profile.tab.skills': 'Skills', 'profile.tab.categories': 'Categories', 'profile.tab.geography': 'Geography', 'profile.specialist.categories': 'Work categories', 'profile.specialist.categories.desc': 'Select the categories you work in', 'profile.specialist.geography': 'Coverage areas', 'profile.specialist.geography.desc': 'Select the cities / districts where you are active', 'profile.saving': 'Saving...', 'profile.upload.error': 'Error uploading photo', 'profile.saved': 'Saved', 'profile.tab.cards': 'Portfolio', 'profile.cards.count': 'Portfolio', 'profile.cards.add': 'Add portfolio', 'profile.cards.new_title': 'New portfolio title', 'profile.cards.placeholder': 'e.g. Plumbing', 'profile.cards.create': 'Create', 'profile.cards.cancel': 'Cancel', 'profile.cards.empty': 'No portfolio yet', 'profile.cards.create_first': 'Create your first portfolio', 'profile.cards.delete_confirm': 'Delete portfolio?', 'profile.card.tab.main': 'General', 'profile.card.tab.skills': 'Skills', 'profile.card.tab.categories': 'Categories', 'profile.card.tab.geography': 'Geography', 'profile.card.tab.portfolio': 'Portfolio', 'profile.card.active': 'Active', 'profile.card.save': 'Save', 'profile.card.saved': 'Saved', 'profile.card.delete': 'Delete', 'profile.card.skill.add': 'Add skill', 'profile.card.photo.add': 'Add photo', 'profile.card.photo.uploading': 'Uploading...', 'profile.card.photo.empty': 'No photos yet', 'profile.card.item.title': 'Title', 'profile.card.item.desc': 'Description', 'profile.card.item.save': 'Save', 'profile.card.item.cancel': 'Cancel', 'profile.card.item.edit': 'Edit', 'profile.upgrade.cards_limit': 'Portfolio limit reached', 'profile.upgrade.plan': 'Current plan:', 'profile.upgrade.contact': 'Contact the administrator to change your plan', 'profile.upgrade.ok': 'Got it', 'profile.plan.title': 'Subscription plan', 'profile.balance': 'Balance', 'profile.balance.topup': 'Top Up Balance', 'profile.balance.topup.title': 'Top Up Balance', 'profile.balance.topup.amount': 'Amount (EUR)', 'profile.balance.topup.hint': 'Choose a preset or enter a custom amount', 'profile.balance.topup.submit': 'Proceed to Payment', 'profile.balance.topup.loading': 'Redirecting...', 'profile.balance.topup.error': 'Payment initiation failed. Please try again.', 'payment.success.title': 'Payment Successful!', 'payment.success.desc': 'Your balance has been updated.', 'payment.cancelled.title': 'Payment Cancelled', 'payment.cancelled.desc': 'Payment was cancelled. No charges were made.', 'payment.pending.title': 'Processing...', 'payment.pending.desc': 'Your payment is being processed.', 'payment.back_to_profile': 'Back to Profile', 'profile.plan.basic': 'Basic (free)', 'profile.plan.contact_upgrade': 'Contact admin to upgrade your plan', 'profile.plan.cards_up_to': 'Portfolio: up to', 'profile.plan.cards_unlimited': 'Portfolio: unlimited', 'profile.plan.tasks_up_to': 'Tasks: up to', 'profile.plan.offers_up_to': 'Offers: up to', 'profile.plan.valid_until': 'Valid until', 'profile.plan.no_expiry': 'No expiry', // Create task 'create.error': 'Error posting task', // Tasks list extras 'tasks.category.general': 'General', 'tasks.budget.range': 'Range:', 'tasks.budget.from': 'from', 'tasks.budget.to': 'to', 'tasks.filter.reset': 'Reset filters', 'tasks.load_more': 'Load more', 'tasks.showing': 'Results:', 'tasks.field.budget': 'Budget, €', // Admin 'admin.title': 'Admin Panel', 'admin.tab.stats': 'Statistics', 'admin.tab.users': 'Users', 'admin.tab.tasks': 'Tasks', 'admin.tab.reports': 'Reports', 'admin.stats.users': 'Users', 'admin.stats.tasks': 'Tasks', 'admin.stats.offers': 'Offers', 'admin.stats.reviews': 'Reviews', 'admin.tasks.by_status': 'Tasks by status', 'admin.col.user': 'User', 'admin.col.email': 'Email', 'admin.col.role': 'Role', 'admin.col.registered': 'Registered', 'admin.col.status': 'Status', 'admin.col.title': 'Title', 'admin.col.budget': 'Budget', 'admin.col.created': 'Created', 'admin.users.active': 'Active', 'admin.users.inactive': 'Inactive', 'admin.users.deactivate': 'Deactivate', 'admin.users.activate': 'Activate', 'admin.tasks.cancel': 'Cancel', 'admin.reports.none': 'No reports', 'admin.reports.reviewed': 'Reviewed', 'admin.reports.dismiss': 'Dismiss', 'admin.pagination.total': 'Total', 'admin.users.role.change': 'Change role', 'admin.users.search.placeholder': 'Search name or email...', 'admin.tasks.delete': 'Delete', 'admin.tasks.delete.confirm': 'Permanently delete this task?', 'admin.tasks.search.placeholder': 'Search title...', 'admin.col.customer': 'Customer', 'admin.col.reporter': 'Reporter', 'admin.col.target': 'Target', 'admin.filter.all_roles': 'All roles', 'admin.filter.all_statuses': 'All statuses', 'admin.reports.target.task': 'Task', 'admin.reports.target.user': 'User', 'admin.tab.categories': 'Categories', 'admin.tab.locations': 'Cities & Districts', 'admin.tab.logs': 'Logs', 'admin.tab.plans': 'Plans', 'admin.tab.settings': 'Settings', 'admin.logs.subtab.ai': 'AI Logs', 'admin.logs.subtab.activity': 'Activity', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Notifications', 'admin.notif_logs.type': 'Type', 'admin.notif_logs.title': 'Title', 'admin.notif_logs.read': 'Read', 'admin.notif_logs.empty': 'No notification logs', 'admin.stats.notif_chart_title': 'Notifications per day', 'admin.stats.notif_label': 'Notifications', 'admin.stats.mail_chart_title': 'Emails per day', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'All', 'admin.stats.specialists': 'Specialists', 'admin.col.plan': 'Plan', 'admin.back_home': 'Home', 'admin.plans.title': 'Subscription plans', 'admin.plans.add': '+ New plan', 'admin.plans.empty': 'No plans created', 'admin.plans.form.new': 'New plan', 'admin.plans.form.edit': 'Edit plan', 'admin.plans.form.name': 'Name', 'admin.plans.form.price': 'Price (EUR)', 'admin.plans.form.old_price': 'Old price (EUR, optional)', 'admin.plans.form.max_offers': 'Max offers (empty = no limit)', 'admin.plans.form.max_cards': 'Max portfolio (empty = no limit)', 'admin.plans.form.duration_days': 'Duration (days, empty = no expiry)', 'admin.plans.form.description': 'Description', 'admin.plans.form.features': 'Features (one per line)', 'admin.plans.form.notify': 'Notify about new tasks', 'admin.plans.form.default': 'Default', 'admin.plans.form.active': 'Active', 'admin.plans.form.order': 'Order', 'admin.plans.form.role': 'Role', 'admin.plans.form.tier': 'Tier', 'admin.plans.form.role.customer': 'Customer', 'admin.plans.form.role.specialist': 'Specialist', 'admin.plans.form.tier.free': 'Free', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Limits (empty = unlimited)', 'admin.plans.form.max_messages_day': 'Max Messages/Day', 'admin.plans.form.max_orders_day': 'Max Orders/Day', 'admin.plans.form.max_skills': 'Max Skills', 'admin.plans.form.max_profiles': 'Max Profiles', 'admin.plans.form.max_portfolio': 'Max Portfolio Items', 'admin.plans.form.section.boost': 'Multipliers & Boost', 'admin.plans.form.search_boost': 'Search Boost', 'admin.plans.form.offers_multiplier': 'Offers Multiplier', 'admin.plans.form.section.contact': 'Contact Permissions', 'admin.plans.form.can_contact_free': 'Contact Free Plan users', 'admin.plans.form.can_contact_pro': 'Contact Pro Plan users', 'admin.plans.form.can_contact_all': 'Contact All users', 'admin.plans.form.can_show_contact': 'Show Contact Info', 'admin.plans.form.can_view_phone': 'View Phone', 'admin.plans.form.section.features': 'Feature Flags', 'admin.plans.form.upload_video': 'Upload Video', 'admin.plans.form.favorites': 'Favorites', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Verified Badge', 'admin.plans.form.highlighted_reviews': 'Highlighted Reviews', 'admin.plans.form.personal_site': 'Personal Site', 'admin.plans.form.can_help_now': 'Can Help Now Status', 'admin.plans.form.need_help': 'Need Help Status', 'admin.plans.form.auto_response': 'Auto Response', 'admin.plans.form.auto_match': 'Auto Match', 'admin.plans.form.instant_dispatch_free': 'Instant Dispatch (Free)', 'admin.plans.form.instant_dispatch_pro': 'Instant Dispatch (Pro)', 'admin.plans.badge.default': 'Default', 'admin.plans.badge.inactive': 'Inactive', 'admin.plans.make_default': 'Set as default', 'admin.plans.tasks': 'Tasks', 'admin.plans.offers': 'Offers', 'admin.plans.cards': 'Portfolio', 'admin.plans.notify_tasks': 'Task notifications', 'admin.plans.delete.confirm': 'Delete plan', 'admin.activity.title': 'Activity log', 'admin.activity.event': 'Event', 'admin.activity.all_events': 'All events', 'admin.activity.from': 'From', 'admin.activity.to': 'To', 'admin.activity.reset': 'Reset', 'admin.activity.total': 'Total', 'admin.activity.empty': 'No records', 'admin.mail.event': 'Email event', 'admin.mail.all_events': 'All email events', 'admin.mail.from': 'From', 'admin.mail.to': 'To', 'admin.mail.reset': 'Reset', 'admin.mail.total': 'Total', 'admin.mail.empty': 'No email logs', 'admin.mail.recipient': 'Recipient', 'admin.mail.provider': 'Provider', 'admin.mail.details': 'Details', 'admin.mail.status': 'Status', 'admin.mail.success': 'Success', 'admin.mail.failed': 'Failed', 'admin.event.email_sent': 'Email sent', 'admin.event.email_failed': 'Email failed', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Admin test email sent', 'admin.event.admin_email_test_failed': 'Admin test email failed', 'admin.logs.empty': 'No records', 'admin.logs.date': 'Date', 'admin.logs.provider': 'Provider', 'admin.logs.model': 'Model', 'admin.logs.action': 'Action', 'admin.logs.langs': 'Languages', 'admin.logs.in': 'In', 'admin.logs.out': 'Out', 'admin.logs.total': 'Total', 'admin.logs.ms': 'ms', 'admin.logs.status': 'Status', 'admin.stats.activity_30d': 'Activity over 30 days', 'admin.stats.tasks_label': 'Tasks', 'admin.stats.users_label': 'Users', 'admin.stats.specialists_label': 'Specialists', 'admin.stats.tokens_title': 'Token usage (by month)', 'admin.stats.tokens_out': 'Output', 'admin.stats.tokens_in': 'Input', 'admin.stats.tokens_out_label': 'Output tokens', 'admin.stats.tokens_in_label': 'Input tokens', 'admin.stats.cost_label': 'Cost (USD)', 'admin.stats.tasks_by_status': 'Tasks by status', 'admin.task_status.open': 'Open', 'admin.task_status.in_progress': 'In progress', 'admin.task_status.completed': 'Completed', 'admin.task_status.cancelled': 'Cancelled', 'admin.task_status.draft': 'Drafts', 'admin.settings.tab.general': 'General', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Notifications', 'admin.settings.tab.payment': 'Payment', 'admin.settings.tab.referral': 'Referrals', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Socials', 'admin.settings.socials.title': 'Social Network Links', 'admin.settings.socials.hint': 'Filled links are displayed in the site footer', 'admin.settings.seo.maintenance_label': 'Maintenance Mode', 'admin.settings.seo.maintenance_hint': 'Show a maintenance page to all visitors', 'admin.settings.seo.indexing_label': 'Search Engine Indexing', 'admin.settings.seo.indexing_hint': 'Allow search engines to index the site', 'admin.settings.seo.head_scripts_label': ' Scripts (JS)', 'admin.settings.seo.head_scripts_hint': 'Runs on every page (Google Tag Manager, analytics, etc.)', 'admin.settings.seo.site_title_label': 'Site Title', 'admin.settings.seo.site_description_label': 'Site Description (meta description)', 'admin.settings.referral.title': 'Referral program', 'admin.settings.referral.hint': 'Reward users who bring new registrations.', 'admin.settings.referral.enabled_label': 'Enabled', 'admin.settings.referral.enabled_hint': 'Enable / disable reward application', 'admin.settings.referral.customer_section': 'For customers', 'admin.settings.referral.specialist_section': 'For specialists', 'admin.settings.referral.plan_label': 'Reward plan', 'admin.settings.referral.no_plan': '— no plan —', 'admin.settings.referral.plan_hint': 'This plan will be assigned to the referrer. If their current plan is higher, only days will be added.', 'admin.settings.referral.days_label': 'Reward days', 'admin.settings.referral.days_hint': 'Number of days added to the plan expiry.', 'admin.settings.general.title': 'General settings', 'admin.settings.general.site_name': 'Site name', 'admin.settings.general.site_url': 'Site URL', 'admin.settings.general.contact_email': 'Contact email', 'admin.settings.general.support_phone': 'Support phone', 'admin.settings.smtp.title': 'SMTP settings', 'admin.settings.smtp.hint': 'Used to send email notifications.', 'admin.settings.smtp.host': 'SMTP Host', 'admin.settings.smtp.port': 'Port', 'admin.settings.smtp.encryption': 'Encryption', 'admin.settings.smtp.enc.none': 'None', 'admin.settings.smtp.enc.tls': 'STARTTLS (port 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (port 465)', 'admin.settings.smtp.username': 'Username', 'admin.settings.smtp.password': 'Password / App Password', 'admin.settings.smtp.from_name': 'Sender name', 'admin.settings.smtp.from_email': 'Sender email', 'admin.settings.smtp.test': 'Send test email', 'admin.settings.smtp.sending': 'Sending...', 'admin.settings.payment.hint': 'ePay Piraeus Bank credentials.', 'admin.settings.env.test': 'Test (sandbox)', 'admin.settings.env.prod': 'Production', 'admin.settings.env.label': 'Environment', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Active', 'admin.settings.saving': 'Saving...', 'admin.settings.saved': 'Saved', 'admin.notif.vars_hint': 'Available variables in templates', 'admin.notif.tmpl.not_set': 'Template not configured', 'admin.notif.tmpl.subject_label': 'Email subject', 'admin.notif.tmpl.body_label': 'Email body (HTML)', 'admin.notif.tmpl.save': 'Save', 'admin.notif.tmpl.close': 'Close', 'admin.notif.tmpl.translate': 'Auto-translate to other languages', 'admin.notif.tmpl.translating': 'Translating...', 'admin.notif.tmpl.saving': 'Saving...', 'admin.notif.email_verification': 'Email verification', 'admin.notif.registration_success': 'Successful registration', 'admin.notif.password_reset': 'Password reset', 'admin.notif.new_offer': 'New offer', 'admin.notif.new_task': 'New task', 'admin.notif.offer_accepted': 'Offer accepted', 'admin.notif.new_message': 'New message', 'admin.notif.offer_declined': 'Offer declined', 'admin.notif.offer_other_accepted': 'Another specialist chosen', 'admin.notif.task_updated': 'Task updated', 'admin.notif.deadline_reminder': 'Deadline reminder', 'admin.notif.task_archived': 'Task unpublished automatically', 'admin.notif.referral_reward': 'Referral reward', // Plan lifecycle email templates 'admin.email_template.plan_activated': 'Plan activated', 'admin.email_template.plan_upgraded': 'Plan upgraded', 'admin.email_template.plan_downgrade_scheduled': 'Downgrade scheduled', 'admin.email_template.plan_downgrade_applied': 'Downgrade applied', 'admin.email_template.plan_renewal_reminder': 'Renewal reminder', 'admin.email_template.plan_insufficient_funds': 'Insufficient funds warning', // Pricing confirm modal 'pricing.confirm.title': 'Confirm plan selection', 'pricing.confirm.plan': 'Plan', 'pricing.confirm.prorated': 'Prorated credit', 'pricing.confirm.effective_price': 'Amount due', 'pricing.confirm.your_balance': 'Your balance', 'pricing.confirm.downgrade_info': 'The switch to the new plan will happen automatically after the current period ends.', 'pricing.confirm.insufficient': 'Insufficient balance.', 'pricing.confirm.top_up': 'Top up', 'pricing.confirm.schedule_downgrade': 'Schedule downgrade', 'pricing.confirm.pay': 'Pay', 'admin.user_edit.title': 'Edit user', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email verified', 'admin.user_edit.email_not_verified': 'Email not verified', 'admin.user_edit.verify_email_btn': 'Verify manually', 'admin.user_edit.verify_email_done': 'Email verified!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Registered', 'admin.user_edit.last_seen': 'Last seen', 'admin.user_edit.lang': 'Language', 'admin.user_edit.first_name': 'First name', 'admin.user_edit.last_name': 'Last name', 'admin.user_edit.phone': 'Phone', 'admin.user_edit.bio': 'Bio', 'admin.user_edit.role': 'Role', 'admin.user_edit.plan': 'Plan', 'admin.user_edit.no_plan': '— No plan —', 'admin.user_edit.active': 'Active account', 'admin.user_edit.balance': 'Balance (EUR)', 'admin.user_edit.skills': 'Skills', 'admin.user_edit.tab.profile': 'Profile', 'admin.user_edit.tab.account': 'Account', 'admin.user_edit.tab.balance': 'Balance', 'admin.user_edit.tab.settings': 'Settings', 'admin.user_edit.tab.specialist': 'Portfolio', 'admin.user_edit.tab.site': 'Website', 'admin.user_edit.plan_expires': 'Plan expires', 'admin.user_edit.interface_lang': 'Interface language', 'admin.user_edit.comm_languages': 'Communication languages', 'admin.user_edit.personal_site_slug': 'Personal page', 'admin.user_edit.show_contact_info': 'Show contact info', 'admin.user_edit.show_contact_info.hint': 'Visible to customers', 'admin.user_edit.notify_new_tasks': 'Notify about new tasks', 'admin.user_edit.notify_new_tasks.hint': 'Push and email notifications', 'admin.user_edit.notif_messages': 'Message notifications', 'admin.user_edit.notif_messages.hint': 'New messages in chat', 'admin.user_edit.site_settings': 'Personal page settings', 'admin.user_edit.categories': 'Service categories', 'admin.user_edit.locations': 'Service areas', 'admin.user_edit.skill_placeholder': 'New skill...', 'admin.user_edit.add_category': '— Select category —', 'admin.user_edit.add_location': '— Select location —', 'admin.user_edit.specialist_cards': 'Portfolio', 'admin.user_edit.no_cards': 'No portfolio found', 'admin.user_edit.card_title': 'Portfolio title', 'admin.user_edit.card_description': 'Description', 'admin.balance.topup.btn': 'Top up', 'admin.balance.withdraw.btn': 'Withdraw', 'admin.balance.modal_hint': 'Changes take effect immediately and are recorded in history', 'admin.balance.topup.title': 'Top up balance', 'admin.balance.topup.amount': 'Amount', 'admin.balance.topup.description': 'Comment', 'admin.balance.topup.description.placeholder': 'For example: bonus or manual top-up', 'admin.balance.topup.submit': 'Top up balance', 'admin.balance.withdraw.title': 'Withdraw balance', 'admin.balance.withdraw.amount': 'Amount', 'admin.balance.withdraw.description': 'Comment', 'admin.balance.withdraw.description.placeholder': 'For example: refund or manual debit', 'admin.balance.withdraw.submit': 'Withdraw from balance', 'admin.user_edit.role.customer': 'Customer', 'admin.user_edit.role.specialist': 'Specialist', 'admin.user_edit.role.admin': 'Administrator', 'common.refresh': 'Refresh', 'common.back_home': 'Home', 'admin.loc.hint': 'Manage cities and districts', 'admin.loc.add_city': 'New city', 'admin.loc.add_district': 'Add district', 'admin.loc.new': 'New location', 'admin.loc.edit': 'Edit location', 'admin.loc.district': 'district', 'admin.loc.empty': 'No locations', 'admin.loc.delete.confirm': 'Delete location? All districts will also be deleted.', 'admin.cat.add_root': 'New category', 'admin.cat.add_sub': 'Subcategory', 'admin.cat.edit': 'Edit', 'admin.cat.delete': 'Delete', 'admin.cat.delete.confirm': 'Delete category? All subcategories will also be deleted.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Icon', 'admin.cat.name_el': 'Greek', 'admin.cat.name_en': 'English', 'admin.cat.name_ru': 'Russian', 'admin.cat.order': 'Order', 'admin.cat.active': 'Active', 'admin.cat.parent': 'Parent category', 'admin.cat.no_parent': 'Top level', 'admin.cat.save': 'Save', 'admin.cat.cancel': 'Cancel', 'admin.cat.empty': 'No categories', 'admin.cat.hint': 'Manage categories with multi-level hierarchy', 'admin.cat.new': 'New category', 'admin.cat.subcategory': 'subcategory', 'admin.cat.add_child': 'Add subcategory', 'admin.cat.inactive': 'Inactive', 'admin.event.user_login': 'Login', 'admin.event.user_register': 'Registration', 'admin.event.admin_user_deactivate': 'User blocked', 'admin.event.admin_user_activate': 'User activated', 'admin.event.admin_user_role_changed': 'Role changed', 'admin.event.admin_task_cancelled': 'Task cancelled', 'admin.event.admin_task_deleted': 'Task deleted', 'admin.event.admin_report_reviewed': 'Report reviewed', 'admin.event.admin_report_dismissed': 'Report dismissed', 'admin.event.task_created': 'Task created', // User status 'user.online': 'Online', 'user.seen_minutes': 'was here {n} min ago', 'user.seen_hours': 'was here {n} hr ago', 'user.seen_yesterday': 'was here yesterday', 'user.seen_days': 'was here {n} days ago', // Specialists 'specialists.title': 'Specialists', 'specialists.search': 'Search specialist...', 'specialists.search.btn': 'Search', 'specialists.empty': 'No specialists found', 'specialists.no_bio': 'No description', 'specialists.view': 'View profile', 'specialists.reviews': 'reviews', 'specialist.favorite': 'Add to favorites', 'specialist.unfavorite': 'Remove from favorites', 'specialist.site_link': 'Personal site', 'favorites.specialists.title': 'Favourite specialists', 'favorites.specialists.empty': 'No favourite specialists yet', 'nav.favorites': 'Favourites', 'nav.schedule': 'Schedule', 'nav.find_tasks': 'Find Orders', 'schedule.title': 'My Schedule', 'schedule.subtitle': 'Mark the days when you are free or busy — clients will see your availability', 'schedule.available': 'Available', 'schedule.busy': 'Busy', 'schedule.unset': 'Not set', 'schedule.click_hint': '← click to cycle status', 'schedule.range_mode': 'Select range', 'schedule.range_from': 'From {date} — select end date', 'schedule.click_to_set': 'Click to set', 'schedule.free': 'free', 'schedule.busy_count': 'busy', 'schedule.free_days': 'free days', 'schedule.googleCalendar': 'Google Calendar', 'schedule.connectGoogle': 'Connect Google Calendar', 'schedule.disconnectGoogle': 'Disconnect', 'schedule.connectedAs': 'Connected as', 'schedule.importFromGoogle': 'Sync from Google', 'schedule.gcalConnected': '\u2713 Google Calendar connected', 'schedule.gcalError': 'Google Calendar connection error', 'schedule.gcalImportDone': 'Imported {n} days from Google Calendar', 'schedule.gcalAutoSyncNote': 'Availability changes are automatically synced to Google Calendar', 'schedule.gcalConnectDesc': 'Connect Google Calendar to automatically sync your availability', 'schedule.gcalDisconnectConfirm': 'Disconnect Google Calendar?', 'find_tasks.title': 'Find Orders', 'find_tasks.for_me': 'For me', 'find_tasks.all': 'All orders', 'find_tasks.by_category': 'By category', 'find_tasks.list': 'List', 'find_tasks.already_offered': 'Offer sent', 'find_tasks.offer_now': 'Make an offer', 'find_tasks.empty_for_me': 'No tasks found in your categories', 'find_tasks.banner_hint': 'Find tasks matching your portfolio categories', 'find_tasks.no_cards': 'Create a specialist portfolio to see tasks matched to you', 'find_tasks.add_card': 'Create portfolio', 'find_tasks.search': 'Search tasks...', 'find_tasks.tasks_count': 'tasks', 'footer.tagline': 'The task platform for Greece', 'footer.rights': 'All rights reserved.', // App download section 'app.download_title': 'Download the CanHelp mobile app', 'app.download_desc': 'All of CanHelp — always at your fingertips. Available for Android and iOS.', // Nav 'nav.pricing': 'Pricing', // Pricing page 'pricing.title': 'Pricing', 'pricing.subtitle': 'Choose the right plan for you', 'pricing.role.customer': 'Customer', 'pricing.role.specialist': 'Specialist', 'pricing.free': 'Free', 'pricing.per_month': 'mo', 'pricing.duration': 'Duration', 'pricing.days': 'days', 'pricing.current_plan': 'Your plan', 'pricing.popular': 'Popular', 'pricing.choose': 'Choose', 'pricing.your_plan': 'Active plan', 'pricing.free_default': 'Default', 'pricing.compare': 'Compare features', 'pricing.feature': 'Feature', 'pricing.faq_note': 'Payment is deducted from your CanHelp balance. Top up available in Payments.', 'pricing.feat.messages': 'Messages / day', 'pricing.feat.orders': 'Orders / day', 'pricing.feat.contact_all': 'Contact everyone', 'pricing.feat.view_phone': 'View phone number', 'pricing.feat.show_contact': 'Show contact info', 'pricing.feat.favorites': 'Favorites', 'pricing.feat.verified_badge': 'Verified badge', 'pricing.feat.google_calendar': 'Google Calendar', 'pricing.feat.personal_site': 'Personal site', 'pricing.feat.auto_response': 'Auto-response', 'pricing.feat.auto_match': 'Auto-match', 'pricing.feat.highlighted_reviews': 'Highlighted reviews', 'pricing.feat.portfolio': 'Portfolio items', 'pricing.feat.cards': 'Specialist cards', 'pricing.feat.notify_tasks': 'New task notifications', 'pricing.feat.video': 'Video in portfolio', // Upgrade prompt 'upgrade.available_in': 'Available in', 'upgrade.cta': 'Upgrade', // Dashboard plan block 'dashboard.plan.title': 'My Plan', 'dashboard.plan.expires': 'Expires in {n} days', 'dashboard.plan.upgrade': 'Upgrade plan', 'dashboard.plan.no_plan': 'Free plan', 'dashboard.plan.messages': 'Messages today', 'dashboard.plan.orders': 'Orders today', 'dashboard.plan.limits': 'Daily limits', 'dashboard.plan.features': 'Features', 'dashboard.plan.stats': 'Stats', 'dashboard.stats.cards': 'Portfolios', 'dashboard.stats.maxCards': 'Max portfolios', 'dashboard.stats.portfolioItems': 'Portfolio items', 'dashboard.stats.maxPortfolioItems': 'Max items', 'dashboard.stats.activeOffers': 'Active offers', 'dashboard.stats.reviewsReceived': 'Reviews', 'dashboard.stats.activeTasks': 'Active tasks', 'dashboard.stats.completedTasks': 'Completed', 'status.need_help': 'I need help', 'status.active': 'Active', 'status.toggle_on': 'Enable', 'status.toggle_off': 'Disable', // FOMO 'fomo.missed_orders': 'Missed {n} orders', 'fomo.missed_value': 'Worth €{v}', 'fomo.upgrade_hint': 'Upgrade to receive more orders', 'fomo.conversion': 'Task conversion', 'fomo.active': 'Active', 'fomo.with_offers': 'With offers', 'fomo.completed': 'Completed', 'fomo.already_offered': '{n} specialists have already responded', 'fomo.specialist_missed': 'You missed {n} orders', 'fomo.top_categories': 'Categories', 'fomo.offers_received': 'offers received', 'fomo.avg_offers': 'Avg {n}/task', 'fomo.completion_rate': 'completed', // Task auto-match 'task.auto_match': 'Auto-match', 'task.auto_match_results': 'Top specialists', 'task.no_offer_yet': 'You haven\'t sent an offer yet', 'task.make_offer': 'Send offer', 'auto_response.title': 'Auto-Response', 'auto_response.enabled': 'Enable auto-response', 'auto_response.min_budget': 'Min budget', 'auto_response.max_budget': 'Max budget', 'auto_response.default_price': 'Default price', 'auto_response.default_message': 'Default message', 'auto_response.max_per_day': 'Max auto-offers per day', 'auto_response.save': 'Save', 'auto_response.saved': 'Saved', 'auto_response.categories': 'Categories', 'auto_response.locations': 'Locations', // Personal site 'profile.personal_site': 'Personal Site', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Only latin letters, numbers, - and _', 'profile.site_open': 'Open site', 'profile.site_preview': 'Your site', 'profile.show_contact': 'Show contact info', 'profile.show_contact_hint': 'Customers with Pro/Ultimate plans will see your phone number', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Calendar requires a Pro or Ultimate plan', // Chat limits 'chat.limit_warning': '{n} messages left today', 'chat.limit_reached': 'Message limit reached. Upgrade your plan', 'chat.upgrade': 'Upgrade', // Site page 'site.member_since': 'Member since', 'site.rating': 'Rating', 'site.completed_tasks': 'Completed', 'site.languages': 'Languages', 'site.photos': 'photos', 'site.contact_form': 'Get in touch', 'site.contact_sent': 'Message sent!', 'site.contact_sent_desc': 'The specialist will contact you soon', 'site.contact_name': 'Name', 'site.contact_name_ph': 'Your name', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Message', 'site.contact_message_ph': 'Describe your task...', 'site.contact_send': 'Send', 'site.share': 'Share', 'site.speaks_languages': 'Speaks', 'site.message_sent': 'Message sent!', 'site.message_sent_desc': 'The specialist will receive it in the chat', 'site.message_placeholder': 'Write your message...', 'site.write_to_chat': 'Write to chat', 'site.auth_required_title': 'Sign in required', 'site.auth_required_desc': 'To write in the chat, you need to sign in to your CanHelp account.', 'site.auth_login_btn': 'Sign in', 'site.auth_contact_form_btn': 'Contact via feedback form', 'specialist.services': 'Services', 'portfolio.title': 'Portfolio', 'status.can_help_now': 'Available now', 'common.not_found': 'Page not found', 'common.anonymous': 'Anonymous', 'specialist_setup.page_title': 'Specialist profile setup', 'specialist_setup.step_of': 'Step {current} of {total}', 'specialist_setup.next': 'Next', 'specialist_setup.back': 'Back', 'specialist_setup.skip': 'Skip', 'specialist_setup.finish': 'Finish', 'specialist_setup.go_to_profile': 'Go to profile', 'specialist_setup.browse_tasks': 'Browse tasks', 'specialist_setup.step1.title': 'Welcome!', 'specialist_setup.step1.subtitle': "Let's set up your profile", 'specialist_setup.step1.desc': 'A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.', 'specialist_setup.step1.what_next': 'What we will do:', 'specialist_setup.step1.item1': 'Fill in basic information', 'specialist_setup.step1.item2': 'Create a service card', 'specialist_setup.step1.item3': 'Add skills and categories', 'specialist_setup.step1.item4': 'Select service area', 'specialist_setup.step1.item5': 'Upload portfolio photos', 'specialist_setup.step2.title': 'Basic profile', 'specialist_setup.step2.subtitle': 'Tell us about yourself', 'specialist_setup.step2.bio_label': 'About me', 'specialist_setup.step2.bio_placeholder': 'Describe your experience, services you offer...', 'specialist_setup.step2.phone_label': 'Phone', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Profile photo', 'specialist_setup.step2.photo_btn': 'Upload photo', 'specialist_setup.step2.photo_uploading': 'Uploading...', 'specialist_setup.step2.photo_hint': 'Shown on your profile', 'specialist_setup.step3.title': 'Service card', 'specialist_setup.step3.subtitle': 'Create your first service card', 'specialist_setup.step3.title_label': 'Card title', 'specialist_setup.step3.title_placeholder': 'E.g. Plumber, Electrician, Cleaning...', 'specialist_setup.step3.desc_label': 'Description', 'specialist_setup.step3.desc_placeholder': 'Describe in detail what you offer, your experience, advantages...', 'specialist_setup.step3.title_required': 'Title is required', 'specialist_setup.step4.title': 'Skills & Categories', 'specialist_setup.step4.subtitle': 'Add skills and select categories', 'specialist_setup.step4.skills_label': 'Skills', 'specialist_setup.step4.skills_placeholder': 'E.g. Pipe installation...', 'specialist_setup.step4.skills_add': 'Add', 'specialist_setup.step4.categories_label': 'Categories', 'specialist_setup.step5.title': 'Service area', 'specialist_setup.step5.subtitle': 'Where do you provide services?', 'specialist_setup.step5.hint': 'Select cities or specific areas', 'specialist_setup.done.title': 'Your profile is ready!', 'specialist_setup.done.subtitle': 'Congratulations! Your profile has been set up', 'specialist_setup.done.desc': 'You can now receive orders from clients. Browse tasks that match your skills.' }, ru: { 'footer.slogan': 'Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.', 'footer.links': 'Ссылки', 'footer.socials': 'Мы в соцсетях', 'nav.home': 'Главная', 'nav.tasks': 'Задачи', 'nav.post': '+ Опубликовать', 'nav.dashboard': 'Панель управления', 'nav.chat': 'Сообщения', 'nav.notifications': 'Уведомления', 'nav.profile': 'Профиль', 'nav.admin': 'Админка', 'nav.specialists': 'Специалисты', 'nav.new_task': 'Новая задача', 'nav.login': 'Войти', 'nav.register': 'Регистрация', 'nav.logout': 'Выйти', 'hero.title': 'Найди специалиста для любой работы', 'hero.subtitle': 'Опубликуй задачу, получи предложения и выбери лучшего профессионала', 'hero.cta.post': 'Опубликовать задачу', 'hero.cta.browse': 'Стать специалистом', 'hero.search.placeholder': 'Что нужно? напр. электрик, уборка...', 'stats.specialists': 'специалистов', 'stats.tasks': 'задач', 'stats.categories': 'категорий', 'stats.free': 'бесплатная регистрация', 'section.categories': 'Создай задачу в любой категории', 'section.how': 'Как это работает', 'section.recent': 'Последние задачи', 'section.all': 'Смотреть все →', 'section.more': 'ещё', 'section.cities': 'Города и районы', 'section.community': 'Общественный проект для всех', 'community.subtitle': 'CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.', 'community.point1.title': 'Умеете что-то делать?', 'community.point1.desc': 'Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.', 'community.point2.title': 'Нужна помощь?', 'community.point2.desc': 'Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.', 'community.point3.title': 'Помогите проекту расти', 'community.point3.desc': 'CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.', 'community.share': 'Поделиться с друзьями', 'community.share.copied': 'Ссылка скопирована!', // Referral section on home page 'section.referral': 'Реферальная программа', 'referral.home.subtitle': 'Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.', 'referral.home.step1.title': 'Зарегистрируйтесь и получите ссылку', 'referral.home.step1.desc': 'Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.', 'referral.home.step2.title': 'Поделитесь с друзьями', 'referral.home.step2.desc': 'Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.', 'referral.home.step3.title': 'Получайте награды', 'referral.home.step3.desc': 'Как только друг подтвердит email, вы автоматически получите свою награду.', 'referral.home.cta': 'Получить ссылку', 'referral.home.badge': 'Реферальная программа', // FAQ section 'section.faq': 'Частые вопросы', 'faq.q1': 'Как работает CanHelp?', 'faq.a1': 'Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.', 'faq.q2': 'Сколько стоит использование платформы?', 'faq.a2': 'Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.', 'faq.q3': 'Как стать специалистом?', 'faq.a3': 'Зарегистрируйтесь, перейдите в «Стать специалистом», заполните профиль навыками и категориями и начните получать задачи.', 'faq.q4': 'Как выбрать подходящего специалиста?', 'faq.a4': 'Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.', 'faq.q5': 'Что если я не доволен результатом?', 'faq.a5': 'Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.', 'faq.q6': 'Можно ли связаться со специалистом до принятия предложения?', 'faq.a6': 'Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.', 'faq.q7': 'Сколько времени ждать предложений?', 'faq.a7': 'Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.', 'faq.q8': 'Можно ли разместить задачу в любом городе Греции?', 'faq.a8': 'Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.', 'faq.q9': 'Какие виды задач есть на CanHelp?', 'faq.a9': 'Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.', 'faq.q10': 'Есть ли мобильное приложение?', 'faq.a10': 'Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.', 'how.step1.title': 'Опубликуй задачу', 'how.step1.desc': 'Опиши что нужно и установи бюджет', 'how.step2.title': 'Получи предложения', 'how.step2.desc': 'Специалисты пришлют предложения с ценой и сроками', 'how.step3.title': 'Выбери и начни', 'how.step3.desc': 'Выбери лучшего профессионала и начни сотрудничество', 'tasks.title': 'задач', 'tasks.filters': 'Фильтры', 'tasks.search': 'Поиск', 'tasks.search.placeholder': 'Название или ключевое слово...', 'tasks.search.btn': 'Поиск', 'tasks.publish': 'Опубликовать', 'tasks.category.all': 'Все', 'tasks.category.all_in': 'Все в', 'tasks.category.label': 'Категория', 'tasks.location.label': 'Город', 'tasks.location.placeholder': 'напр. Афины', 'tasks.empty': 'Задачи не найдены', 'tasks.empty.cta': 'Опубликуй первую', 'task.status.open': 'Открыта', 'task.status.in_progress': 'В работе', 'task.status.completed': 'Завершена', 'task.status.cancelled': 'Отменена', 'task.status.draft': 'Черновик', 'task.budget': 'Бюджет', 'task.location': 'Местоположение', 'task.deadline': 'Дата начала', 'task.created_at': 'Создано', 'task.customer': 'Заказчик', 'task.offer.btn': 'Отправить предложение', 'task.invite.banner_title': 'Вас пригласили на это задание', 'task.invite.banner_hint': 'Заказчик лично пригласил вас', 'task.invite.accept': 'Отправить предложение', 'task.invite.decline': 'Отказаться', 'offer.accept': 'Принять', 'offer.decline': 'Отклонить', 'task.complete': 'Завершить задачу', 'task.complete.confirm': 'Отметить задачу как выполненную?', 'task.edit': 'Редактировать', 'task.status_label': 'Статус', 'task.yours': 'Ваша задача', 'task.offer.yours': 'Ваше предложение', 'review.leave': 'Оставить отзыв', 'review.rating': 'Оценка', 'review.comment': 'Комментарий', 'review.comment.placeholder': 'Расскажите о своём опыте...', 'review.submit': 'Отправить отзыв', 'review.submitting': 'Отправка...', 'review.done': 'Отзыв отправлен!', 'profile.reviews': 'Отзывы', 'profile.no_reviews': 'Отзывов пока нет', 'profile.rating': 'Рейтинг', 'profile.skills.label': 'Навыки', 'profile.member_since': 'Участник с', 'task.offers': 'Предложения', 'task.offers.none': 'Предложений пока нет', 'create.title': 'Опубликовать задачу', 'create.field.title': 'Название', 'create.field.description': 'Описание', 'create.field.category': 'Категория', 'create.field.category.select': 'Выберите...', 'create.field.location': 'Местоположение', 'create.field.location.any': 'Где угодно', 'create.field.location.all': 'Весь город', 'create.field.budget': 'Бюджет (€)', 'create.field.deadline': 'Дата начала', 'create.field.budget_negotiable': 'Цена обсуждается', 'create.field.time_slot': 'Время выполнения', 'create.field.time_slot.any': 'В любое время', 'create.field.time_slot.morning': 'Утром (08:00–13:00)', 'create.field.time_slot.afternoon': 'Днём (13:00–18:00)', 'create.field.time_slot.evening': 'Вечером (18:00–22:00)', 'create.field.time_slot.weekend': 'Выходной', 'create.field.address': 'Адрес (необязательно)', 'create.field.address.district': 'Квартал', 'create.field.address.street': 'Улица', 'create.field.address.house': 'Дом', 'create.field.confidential': 'Конфиденциальная заметка', 'create.field.confidential.placeholder': 'Детали, видные только назначенному специалисту...', 'create.field.confidential.hint': 'Не отображается публично', 'create.field.photos': 'Фотографии', 'create.field.photos.add': 'Добавить фото', 'create.field.photos.uploading': 'Загрузка...', 'task.budget_negotiable': 'Цена обсуждается', 'task.time_slot': 'Время', 'task.confidential': 'Конфид. заметка', 'create.field.title.placeholder': 'напр. Уборка квартиры 80кв', 'create.field.description.placeholder': 'Подробно опишите что нужно...', 'create.field.location.placeholder': 'напр. Афины, Колонаки', 'create.field.budget.placeholder': 'напр. 100', 'create.submit': 'Опубликовать задачу', 'create.submitting': 'Публикация...', 'login.title': 'Добро пожаловать', 'login.subtitle': 'Вход в CanHelp', 'login.email': 'Email', 'login.password': 'Пароль', 'login.submit': 'Войти', 'login.submitting': 'Вход...', 'login.error': 'Неверный email или пароль', 'login.unverified.title': 'Подтвердите ваш email', 'login.unverified.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'login.unverified.resend': 'Отправить письмо повторно', 'login.unverified.sending': 'Отправка...', 'login.unverified.sent': '✓ Отправлено — проверьте входящие', 'profile.email.verified': 'Email подтверждён', 'profile.email.not_verified': 'Email не подтверждён', 'login.no_account': 'Нет аккаунта?', 'login.register_link': 'Зарегистрироваться', 'login.forgot_password': 'Забыл пароль?', 'login.or_continue_with': 'или продолжите через', 'login.continue_google': 'Войти через Google', 'forgot.title': 'Забыл пароль', 'forgot.subtitle': 'Введите email для получения ссылки восстановления', 'forgot.email': 'Email', 'forgot.submit': 'Отправить ссылку', 'forgot.submitting': 'Отправка...', 'forgot.sent.title': 'Проверьте входящие', 'forgot.sent.desc': 'Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.', 'forgot.back_to_login': 'Вернуться ко входу', 'forgot.error': 'Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.', 'forgot.error.not_found': 'Аккаунт с таким email не найден.', 'forgot.error.send_failed': 'Ошибка отправки письма. Попробуйте позже.', 'reset.title': 'Новый пароль', 'reset.subtitle': 'Введите новый пароль', 'reset.password': 'Новый пароль', 'reset.confirm': 'Подтвердите пароль', 'reset.submit': 'Изменить пароль', 'reset.submitting': 'Сохранение...', 'reset.success': 'Пароль успешно изменён. Перенаправление ко входу...', 'reset.back_to_login': 'Вернуться ко входу', 'reset.error.mismatch': 'Пароли не совпадают', 'reset.error.invalid': 'Недействительная или устаревшая ссылка. Запросите новую.', 'register.title': 'Регистрация', 'register.subtitle': 'Создать аккаунт в CanHelp', 'register.first_name': 'Имя', 'register.last_name': 'Фамилия', 'register.email': 'Email', 'register.password': 'Пароль (мин. 8 символов)', 'register.role': 'Роль', 'register.role.customer': 'Пользователь', 'register.role.customer.desc': 'Публикую задачи', 'register.role.specialist': 'Специалист', 'register.role.specialist.desc': 'Беру задачи', 'register.submit': 'Создать аккаунт', 'register.submitting': 'Регистрация...', 'register.has_account': 'Уже есть аккаунт?', 'register.login_link': 'Войти', 'register.continue_google': 'Зарегистрироваться через Google', 'register.check_email.title': 'Проверьте почту', 'register.check_email.desc': 'Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.', 'register.check_email.login': 'Вернуться к входу', 'dashboard.title': 'Панель управления', 'dashboard.new_task': '+ Новая задача', 'dashboard.my_tasks': 'Мои задачи', 'dashboard.my_offers': 'Мои предложения', 'dashboard.invitations': 'Приглашения на задания', 'dashboard.offers_count': 'предл.', 'dashboard.declined_count': 'откл.', 'dashboard.completed_tasks': 'Завершённые задачи', 'dashboard.completed_offers': 'Завершённые предложения', 'dashboard.review_pending': 'Оценка ещё не оставлена', 'tasks.new.top_specialists': 'Топ специалисты', 'tasks.new.select_category': 'Выберите категорию, чтобы увидеть специалистов', 'tasks.new.invite': 'Предложить работу', 'tasks.new.invited': 'Выбран ✓', 'reviews.count': 'отзывов', 'filter.location': 'Локация', 'filter.language': 'Языки', 'filter.language.any': 'Любой язык', 'filter.category.all': 'Все категории', 'user.categories': 'Категории', 'user.work_area': 'Район работы', 'dashboard.tasks.empty': 'Вы не публиковали задачи', 'dashboard.tasks.empty.cta': 'Опубликуйте первую', 'dashboard.tasks.add_new': 'Добавить новую задачу', 'dashboard.offers.empty': 'Вы не отправляли предложений', 'dashboard.offers.empty.cta': 'Найти задачи', 'dashboard.customer.specialists_title': 'Ищете исполнителя?', 'dashboard.customer.specialists_hint': 'Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи', 'dashboard.customer.specialists_cta': 'Найти исполнителя', 'dashboard.customer.how_title': 'Как это работает', 'dashboard.customer.step1': 'Создайте задачу с описанием и бюджетом', 'dashboard.customer.step2': 'Специалисты пришлют предложения с ценой и сроками', 'dashboard.customer.step3': 'Выберите подходящего и начните работу', 'notif.title': 'Уведомления', 'notif.mark_all': 'Отметить все как прочитанные', 'notif.empty': 'Нет уведомлений', 'notif.type.new_offer': 'Новое предложение', 'notif.type.offer_accepted': 'Ваше предложение принято', 'notif.type.offer_declined': 'Ваше предложение отклонено', 'notif.type.task_completed': 'Задание выполнено', 'notif.type.task_cancelled': 'Задание отменено', 'notif.type.new_message': 'Новое сообщение', 'notif.type.new_review': 'Новый отзыв', 'notif.type.task_invite': 'Приглашение на задание', 'notif.body.new_offer': 'Новое предложение на «{title}»', 'notif.body.offer_accepted': 'Ваше предложение на «{title}» принято', 'notif.body.offer_declined': 'Ваше предложение на «{title}» отклонено', 'notif.body.task_invite': 'Вас приглашают на «{title}»', 'notif.body.new_review': 'Вы получили оценку {rating}★', 'offer.status.pending': 'Ожидает', 'offer.status.accepted': 'Принято', 'offer.status.declined': 'Отклонено', 'offer.status.withdrawn': 'Отозвано', 'offer.status.other_accepted': 'Выбран другой исполнитель', 'common.loading': 'Загрузка...', 'common.error': 'Ошибка', 'common.save': 'Сохранить', 'common.saving': 'Сохранение...', 'common.cancel': 'Отмена', 'common.add': 'Добавить', 'common.close': 'Закрыть', 'common.edit': 'Редактировать', 'common.delete': 'Удалить', 'common.from': 'от', 'common.currency': '€', 'common.greece': 'Греция', // Chat 'chat.connected': 'Подключено', 'chat.disconnected': 'Отключено', 'chat.no_rooms': 'Переписок пока нет', 'chat.task_fallback': 'Задача', 'chat.select': 'Выберите переписку', 'chat.no_messages': 'Сообщений пока нет', 'chat.placeholder': 'Напишите сообщение... (Enter для отправки)', 'chat.conversation_fallback': 'Переписка', 'chat.direct_chat': 'Личный чат', 'chat.linked_task': 'Прикреплённый заказ', 'chat.write_btn': 'Написать', 'chat.just_now': 'только что', 'chat.min_ago': 'м', 'chat.write_specialist': 'Написать специалисту', 'chat.write_customer': 'Написать заказчику', 'chat.notif_settings': 'Настройки уведомлений', 'chat.notif_messages': 'Уведомления о новых сообщениях', 'chat.toast_title': 'Новое сообщение', 'chat.toast_open': 'Открыть чат', // Offer form 'offer.price': 'Цена', 'offer.price.placeholder': 'напр. 80', 'offer.customer_budget': 'Бюджет заказчика', 'offer.message': 'Сообщение', 'offer.optional': 'необязательно', 'offer.message.placeholder': 'Представьтесь, расскажите об опыте и почему вы лучший выбор...', 'offer.submitting': 'Отправка...', // Profile 'profile.photo': 'Фото профиля', 'profile.photo.change': 'Изменить фото', 'profile.photo.hint': 'JPEG, PNG, WebP · до 5MB', 'profile.basic_info': 'Основная информация', 'profile.phone': 'Телефон', 'profile.phone.placeholder': '+30 6901234567', 'profile.bio': 'Краткое описание', 'profile.bio.placeholder': 'Расскажите немного о себе...', 'profile.language': 'Язык', 'profile.language.hint': 'Язык интерфейса и email-уведомлений', 'profile.languages': 'Языки общения', 'profile.languages.hint': 'Выберите все языки, на которых вы общаетесь', 'profile.skills': 'Навыки', 'profile.skills.subtitle': 'Добавьте услуги, которые вы предлагаете', 'profile.skills.placeholder': 'напр. Уборка, IT, Репетиторство...', 'profile.role': 'Роль аккаунта', 'profile.role.specialist': '🔧 Специалист', 'profile.role.admin': '👑 Admin', 'profile.role.customer': '👤 Пользователь', 'profile.role.change': 'Для смены роли обратитесь в службу поддержки.', 'profile.become_specialist': 'Стать специалистом', 'profile.become_specialist.desc': 'Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.', 'become_specialist.hero.title': 'Зарабатывай, делая то, что умеешь', 'become_specialist.hero.subtitle': 'Создай профиль специалиста и получай заказы от клиентов по всей Греции', 'become_specialist.how.title': 'Как это работает', 'become_specialist.step1.title': 'Создай портфолио специалиста', 'become_specialist.step1.desc': 'Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы', 'become_specialist.step2.title': 'Ищи заказы', 'become_specialist.step2.desc': 'Просматривай задачи по своим категориям в разделе «Поиск заказов»', 'become_specialist.step3.title': 'Откликайся и зарабатывай', 'become_specialist.step3.desc': 'Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы', 'become_specialist.benefits.title': 'Преимущества профиля специалиста', 'become_specialist.benefit1': 'Поиск заказов по вашим категориям и локации', 'become_specialist.benefit2': 'Публичный профиль с отзывами клиентов', 'become_specialist.benefit3': 'Расписание доступности, видимое клиентам', 'become_specialist.benefit4': 'Добавление в избранное клиентами', 'become_specialist.cta': 'Подробнее', 'become_specialist.free_badge': 'Бесплатная регистрация', 'profile.tab.notifications': 'Уведомления', 'profile.tab.reviews': 'Отзывы', 'profile.tab.referral': 'Рефералы', 'profile.tab.auto_response': 'Авто-ответ', 'profile.tab.site': 'Сайт', 'profile.site.title': 'Персональная страница', 'profile.site.url_label': 'Личный сайт', 'profile.site.copy': 'Копировать', 'profile.site.copied': 'Скопировано', 'profile.site.visible_title': 'Что отображается на вашей странице', 'profile.site.visible.name': 'Имя и фото', 'profile.site.visible.bio': 'Биография', 'profile.site.visible.rating': 'Рейтинг и отзывы', 'profile.site.visible.portfolio': 'Портфолио / Карточки', 'profile.site.visible.contacts': 'Контактные данные', 'profile.site.visible.full_last_name': 'Фамилия полностью', 'profile.site.visible.services': 'Карточки услуг', 'profile.site.visible.reviews': 'Раздел с отзывами', 'profile.site.visible.status': 'Статус «Готов помочь»', 'profile.site.theme': 'Тема оформления', 'profile.site.theme.dark': 'Тёмная', 'profile.site.theme.light': 'Светлая', 'profile.site.slug_taken': 'Этот адрес уже занят', 'profile.site.stats.title': 'Аналитика сайта', 'profile.site.stats.days': 'последние 30 дней', 'profile.site.stats.views': 'Просмотры', 'profile.site.stats.unique': 'Уникальные посетители', 'profile.site.stats.messages': 'Сообщения', 'profile.site.stats.total_views': 'Просмотры', 'profile.site.stats.total_unique': 'Уник. посетители', 'profile.site.stats.total_messages': 'Сообщения', 'profile.site.stats.empty': 'Данных пока нет', 'profile.site.stats.loading': 'Загрузка аналитики...', 'profile.site.stats.no_slug': 'Укажите адрес сайта, чтобы видеть статистику', 'profile.site.edit_bio_hint': 'Биография и фото настраиваются во вкладке «Основное».', 'status.title': 'Статус', 'status.can_help_now_hint': 'Ваша карточка показывается выше в поиске', 'status.need_help_hint': 'Специалисты могут предложить вам помощь', 'profile.referral.title': 'Партнёрская программа', 'profile.referral.desc': 'Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.', 'profile.referral.link_label': 'Ваша реферальная ссылка', 'profile.referral.copy': 'Копировать', 'profile.referral.copied': 'Скопировано!', 'profile.referral.invited_count': 'успешных приглашений', 'profile.referral.no_code': 'Реферальный код недоступен.', 'notifications.title': 'Настройки уведомлений', 'notifications.email.new_tasks': 'Email о новых заказах', 'notifications.email.new_tasks.desc': 'Получать email, когда в ваших категориях публикуется новый заказ', 'notifications.messages.desc': 'Получать уведомление при новом входящем сообщении', 'notifications.saved': 'Настройки сохранены', 'notifications.plan_required': 'Недоступно в вашем тарифе', 'profile.tab.info': 'Основное', 'profile.tab.finance': 'Финансы', 'profile.tab.skills': 'Навыки', 'profile.tab.categories': 'Категории', 'profile.tab.geography': 'География', 'profile.specialist.categories': 'Категории работ', 'profile.specialist.categories.desc': 'Выберите категории, в которых вы работаете', 'profile.specialist.geography': 'Города покрытия', 'profile.specialist.geography.desc': 'Выберите города / районы, где вы работаете', 'profile.saving': 'Сохранение...', 'profile.upload.error': 'Ошибка загрузки фото', 'profile.saved': 'Сохранено', 'profile.tab.cards': 'Портфолио', 'profile.cards.count': 'Портфолио', 'profile.cards.add': 'Добавить портфолио', 'profile.cards.new_title': 'Название нового портфолио', 'profile.cards.placeholder': 'Например: Сантехника', 'profile.cards.create': 'Создать', 'profile.cards.cancel': 'Отмена', 'profile.cards.empty': 'У вас нет портфолио', 'profile.cards.create_first': 'Создать первое портфолио', 'profile.cards.delete_confirm': 'Удалить портфолио?', 'profile.card.tab.main': 'Основное', 'profile.card.tab.skills': 'Навыки', 'profile.card.tab.categories': 'Категории', 'profile.card.tab.geography': 'География', 'profile.card.tab.portfolio': 'Галерея', 'profile.card.active': 'Активна', 'profile.card.save': 'Сохранить', 'profile.card.saved': 'Сохранено', 'profile.card.delete': 'Удалить', 'profile.card.skill.add': 'Добавить навык', 'profile.card.photo.add': 'Добавить фото', 'profile.card.photo.uploading': 'Загрузка...', 'profile.card.photo.empty': 'Нет фотографий', 'profile.card.item.title': 'Заголовок', 'profile.card.item.desc': 'Описание', 'profile.card.item.save': 'Сохранить', 'profile.card.item.cancel': 'Отмена', 'profile.card.item.edit': 'Описание работы', 'profile.upgrade.cards_limit': 'Лимит портфолио исчерпан', 'profile.upgrade.plan': 'Текущий тариф:', 'profile.upgrade.contact': 'Обратитесь к администратору для смены тарифа', 'profile.upgrade.ok': 'Понятно', 'profile.plan.title': 'Тарифный план', 'profile.balance': 'Баланс', 'profile.balance.topup': 'Пополнить баланс', 'profile.balance.topup.title': 'Пополнить баланс', 'profile.balance.topup.amount': 'Сумма (в EUR)', 'profile.balance.topup.hint': 'Выберите сумму или введите вручную', 'profile.balance.topup.submit': 'Перейти к оплате', 'profile.balance.topup.loading': 'Перенаправление...', 'profile.balance.topup.error': 'Ошибка инициализации платежа. Попробуйте снова.', 'payment.success.title': 'Оплата прошла успешно!', 'payment.success.desc': 'Ваш баланс обновлён.', 'payment.cancelled.title': 'Оплата отменена', 'payment.cancelled.desc': 'Оплата была отменена. Средства не списаны.', 'payment.pending.title': 'Обрабатывается...', 'payment.pending.desc': 'Ваш платёж в обработке.', 'payment.back_to_profile': 'Вернуться в профиль', 'profile.plan.basic': 'Базовый (бесплатный)', 'profile.plan.contact_upgrade': 'Обратитесь к администратору для подключения тарифа', 'profile.plan.cards_up_to': 'Портфолио: до', 'profile.plan.cards_unlimited': 'Портфолио: безлимитно', 'profile.plan.tasks_up_to': 'Задач: до', 'profile.plan.offers_up_to': 'Откликов: до', 'profile.plan.valid_until': 'Действителен до', 'profile.plan.no_expiry': 'Бессрочно', // Create task 'create.error': 'Ошибка при публикации', // Tasks list extras 'tasks.category.general': 'Общее', 'tasks.budget.range': 'Диапазон:', 'tasks.budget.from': 'от', 'tasks.budget.to': 'до', 'tasks.filter.reset': 'Сбросить фильтры', 'tasks.load_more': 'Загрузить ещё', 'tasks.showing': 'Результатов:', 'tasks.field.budget': 'Бюджет, €', // Admin 'admin.title': 'Панель администратора', 'admin.tab.stats': 'Статистика', 'admin.tab.users': 'Пользователи', 'admin.tab.tasks': 'Задачи', 'admin.tab.reports': 'Жалобы', 'admin.stats.users': 'Пользователи', 'admin.stats.tasks': 'Задачи', 'admin.stats.offers': 'Предложения', 'admin.stats.reviews': 'Отзывы', 'admin.tasks.by_status': 'Задачи по статусу', 'admin.col.user': 'Пользователь', 'admin.col.email': 'Email', 'admin.col.role': 'Роль', 'admin.col.registered': 'Регистрация', 'admin.col.status': 'Статус', 'admin.col.title': 'Название', 'admin.col.budget': 'Бюджет', 'admin.col.created': 'Создано', 'admin.users.active': 'Активен', 'admin.users.inactive': 'Неактивен', 'admin.users.deactivate': 'Деактивировать', 'admin.users.activate': 'Активировать', 'admin.tasks.cancel': 'Отменить', 'admin.reports.none': 'Жалоб нет', 'admin.reports.reviewed': 'Рассмотрено', 'admin.reports.dismiss': 'Отклонить', 'admin.pagination.total': 'Всего', 'admin.users.role.change': 'Изменить роль', 'admin.users.search.placeholder': 'Поиск по имени или email...', 'admin.tasks.delete': 'Удалить', 'admin.tasks.delete.confirm': 'Удалить эту задачу навсегда?', 'admin.tasks.search.placeholder': 'Поиск по названию...', 'admin.col.customer': 'Заказчик', 'admin.col.reporter': 'Жалобщик', 'admin.col.target': 'Цель', 'admin.filter.all_roles': 'Все роли', 'admin.filter.all_statuses': 'Все статусы', 'admin.reports.target.task': 'Задача', 'admin.reports.target.user': 'Пользователь', 'admin.tab.categories': 'Категории', 'admin.tab.locations': 'Города и районы', 'admin.tab.logs': 'Логи', 'admin.tab.plans': 'Тарифы', 'admin.tab.settings': 'Настройки', 'admin.logs.subtab.ai': 'AI логи', 'admin.logs.subtab.activity': 'Активность', 'admin.logs.subtab.mail': 'Mail', 'admin.logs.subtab.notifications': 'Уведомления', 'admin.notif_logs.type': 'Тип', 'admin.notif_logs.title': 'Заголовок', 'admin.notif_logs.read': 'Прочитано', 'admin.notif_logs.empty': 'Логи уведомлений пусты', 'admin.stats.notif_chart_title': 'Уведомления по дням', 'admin.stats.notif_label': 'Уведомления', 'admin.stats.mail_chart_title': 'Email по дням', 'admin.stats.mail_label': 'Emails', 'admin.filter.all': 'Все', 'admin.stats.specialists': 'Исполнители', 'admin.col.plan': 'Тариф', 'admin.back_home': 'На главную', 'admin.plans.title': 'Тарифные пакеты', 'admin.plans.add': '+ Добавить тариф', 'admin.plans.empty': 'Тарифы не созданы', 'admin.plans.form.new': 'Новый тариф', 'admin.plans.form.edit': 'Редактировать тариф', 'admin.plans.form.name': 'Название', 'admin.plans.form.price': 'Цена (EUR)', 'admin.plans.form.old_price': 'Старая цена (EUR, необязательно)', 'admin.plans.form.max_offers': 'Макс. откликов (пусто = без лимита)', 'admin.plans.form.max_cards': 'Макс. портфолио (пусто = без лимита)', 'admin.plans.form.duration_days': 'Срок (дней, пусто = без истечения)', 'admin.plans.form.description': 'Описание', 'admin.plans.form.features': 'Возможности (по одной на строку)', 'admin.plans.form.notify': 'Уведомления о новых заказах', 'admin.plans.form.default': 'По умолчанию', 'admin.plans.form.active': 'Активен', 'admin.plans.form.order': 'Порядок', 'admin.plans.form.role': 'Роль', 'admin.plans.form.tier': 'Уровень', 'admin.plans.form.role.customer': 'Заказчик', 'admin.plans.form.role.specialist': 'Специалист', 'admin.plans.form.tier.free': 'Бесплатный', 'admin.plans.form.tier.pro': 'Pro', 'admin.plans.form.tier.ultimate': 'Ultimate', 'admin.plans.form.section.limits': 'Лимиты (пусто = без ограничений)', 'admin.plans.form.max_messages_day': 'Макс. сообщений/день', 'admin.plans.form.max_orders_day': 'Макс. заказов/день', 'admin.plans.form.max_skills': 'Макс. навыков', 'admin.plans.form.max_profiles': 'Макс. профилей', 'admin.plans.form.max_portfolio': 'Макс. элементов портфолио', 'admin.plans.form.section.boost': 'Множители & Буст', 'admin.plans.form.search_boost': 'Буст в поиске', 'admin.plans.form.offers_multiplier': 'Множитель откликов', 'admin.plans.form.section.contact': 'Права контактов', 'admin.plans.form.can_contact_free': 'Контакт с бесплатными пользователями', 'admin.plans.form.can_contact_pro': 'Контакт с Pro пользователями', 'admin.plans.form.can_contact_all': 'Контакт со всеми', 'admin.plans.form.can_show_contact': 'Показывать контакты', 'admin.plans.form.can_view_phone': 'Просмотр телефона', 'admin.plans.form.section.features': 'Возможности', 'admin.plans.form.upload_video': 'Загрузка видео', 'admin.plans.form.favorites': 'Избранное', 'admin.plans.form.google_calendar': 'Google Calendar', 'admin.plans.form.verified_badge': 'Знак верификации', 'admin.plans.form.highlighted_reviews': 'Выделенные отзывы', 'admin.plans.form.personal_site': 'Личный сайт', 'admin.plans.form.can_help_now': 'Статус «Могу помочь»', 'admin.plans.form.need_help': 'Статус «Нужна помощь»', 'admin.plans.form.auto_response': 'Автоответ', 'admin.plans.form.auto_match': 'Автоподбор', 'admin.plans.form.instant_dispatch_free': 'Мгновенная рассылка (бесплатно)', 'admin.plans.form.instant_dispatch_pro': 'Мгновенная рассылка (Pro)', 'admin.plans.badge.default': 'По умолчанию', 'admin.plans.badge.inactive': 'Неактивен', 'admin.plans.make_default': 'Сделать по умолчанию', 'admin.plans.tasks': 'Задач', 'admin.plans.offers': 'Откликов', 'admin.plans.cards': 'Портфолио', 'admin.plans.notify_tasks': 'Уведомления о заказах', 'admin.plans.delete.confirm': 'Удалить тариф', 'admin.activity.title': 'Журнал активности', 'admin.activity.event': 'Событие', 'admin.activity.all_events': 'Все события', 'admin.activity.from': 'От', 'admin.activity.to': 'До', 'admin.activity.reset': 'Сбросить', 'admin.activity.total': 'Всего', 'admin.activity.empty': 'Нет записей', 'admin.mail.event': 'Email событие', 'admin.mail.all_events': 'Все email события', 'admin.mail.from': 'От', 'admin.mail.to': 'До', 'admin.mail.reset': 'Сбросить', 'admin.mail.total': 'Всего', 'admin.mail.empty': 'Нет email логов', 'admin.mail.recipient': 'Получатель', 'admin.mail.provider': 'Провайдер', 'admin.mail.details': 'Детали', 'admin.mail.status': 'Статус', 'admin.mail.success': 'Успешно', 'admin.mail.failed': 'Ошибка', 'admin.event.email_sent': 'Email отправлен', 'admin.event.email_failed': 'Email не отправлен', 'admin.event.email_dev': 'Email DEV fallback', 'admin.event.admin_email_test_sent': 'Тестовый email отправлен', 'admin.event.admin_email_test_failed': 'Тестовый email не отправлен', 'admin.logs.empty': 'Нет записей', 'admin.logs.date': 'Дата', 'admin.logs.provider': 'Провайдер', 'admin.logs.model': 'Модель', 'admin.logs.action': 'Действие', 'admin.logs.langs': 'Языки', 'admin.logs.in': 'Вход', 'admin.logs.out': 'Выход', 'admin.logs.total': 'Итого', 'admin.logs.ms': 'мс', 'admin.logs.status': 'Статус', 'admin.stats.activity_30d': 'Активность за 30 дней', 'admin.stats.tasks_label': 'Заявки', 'admin.stats.users_label': 'Пользователи', 'admin.stats.specialists_label': 'Исполнители', 'admin.stats.tokens_title': 'Расход токенов (по месяцам)', 'admin.stats.tokens_out': 'Исходящие', 'admin.stats.tokens_in': 'Входящие', 'admin.stats.tokens_out_label': 'Исходящие токены', 'admin.stats.tokens_in_label': 'Входящие токены', 'admin.stats.cost_label': 'Стоимость (USD)', 'admin.stats.tasks_by_status': 'Заявки по статусам', 'admin.task_status.open': 'Открытые', 'admin.task_status.in_progress': 'В работе', 'admin.task_status.completed': 'Завершённые', 'admin.task_status.cancelled': 'Отменённые', 'admin.task_status.draft': 'Черновики', 'admin.settings.tab.general': 'Общие', 'admin.settings.tab.smtp': 'E-Mail', 'admin.settings.tab.notifications': 'Уведомления', 'admin.settings.tab.payment': 'Оплата', 'admin.settings.tab.referral': 'Реферальная', 'admin.settings.tab.seo': 'SEO', 'admin.settings.tab.socials': 'Соцсети', 'admin.settings.socials.title': 'Ссылки на социальные сети', 'admin.settings.socials.hint': 'Заполненные ссылки отображаются в подвале сайта', 'admin.settings.seo.maintenance_label': 'Режим обслуживания', 'admin.settings.seo.maintenance_hint': 'Показывать страницу обслуживания всем посетителям', 'admin.settings.seo.indexing_label': 'Индексация поисковыми системами', 'admin.settings.seo.indexing_hint': 'Разрешить поисковым системам индексировать сайт', 'admin.settings.seo.head_scripts_label': 'Скрипты в (JS)', 'admin.settings.seo.head_scripts_hint': 'Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)', 'admin.settings.seo.site_title_label': 'Заголовок сайта', 'admin.settings.seo.site_description_label': 'Описание сайта (meta description)', 'admin.settings.referral.title': 'Партнёрская программа', 'admin.settings.referral.hint': 'Награждайте пользователей, приводящих новых участников.', 'admin.settings.referral.enabled_label': 'Включено', 'admin.settings.referral.enabled_hint': 'Включить / отключить выдачу наград', 'admin.settings.referral.customer_section': 'Для клиентов', 'admin.settings.referral.specialist_section': 'Для специалистов', 'admin.settings.referral.plan_label': 'Тарифный план за реферала', 'admin.settings.referral.no_plan': '— без плана —', 'admin.settings.referral.plan_hint': 'Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.', 'admin.settings.referral.days_label': 'Дней награды', 'admin.settings.referral.days_hint': 'Количество дней, добавляемых к сроку действия плана.', 'admin.settings.general.title': 'Общие настройки', 'admin.settings.general.site_name': 'Название сайта', 'admin.settings.general.site_url': 'URL сайта', 'admin.settings.general.contact_email': 'Email для связи', 'admin.settings.general.support_phone': 'Телефон поддержки', 'admin.settings.smtp.title': 'Настройки SMTP сервера', 'admin.settings.smtp.hint': 'Используется для отправки email-уведомлений.', 'admin.settings.smtp.host': 'SMTP Хост', 'admin.settings.smtp.port': 'Порт', 'admin.settings.smtp.encryption': 'Шифрование', 'admin.settings.smtp.enc.none': 'Нет', 'admin.settings.smtp.enc.tls': 'STARTTLS (порт 587)', 'admin.settings.smtp.enc.ssl': 'SSL/TLS (порт 465)', 'admin.settings.smtp.username': 'Имя пользователя', 'admin.settings.smtp.password': 'Пароль / App Password', 'admin.settings.smtp.from_name': 'Имя отправителя', 'admin.settings.smtp.from_email': 'Email отправителя', 'admin.settings.smtp.test': 'Отправить тестовый email', 'admin.settings.smtp.sending': 'Отправка...', 'admin.settings.payment.hint': 'Данные для подключения к ePay Piraeus Bank.', 'admin.settings.env.test': 'Тест (sandbox)', 'admin.settings.env.prod': 'Боевой режим', 'admin.settings.env.label': 'Среда', 'admin.settings.merchant_id': 'Merchant ID', 'admin.settings.api_user': 'API User', 'admin.settings.api_password': 'API Password', 'admin.settings.confirm_url': 'Confirmation URL (webhook)', 'admin.settings.cancel_url': 'Cancel URL', 'admin.settings.active': 'Активен', 'admin.settings.saving': 'Сохранение...', 'admin.settings.saved': 'Сохранено', 'admin.notif.vars_hint': 'Доступные переменные в шаблонах', 'admin.notif.tmpl.not_set': 'Шаблон не настроен', 'admin.notif.tmpl.subject_label': 'Тема письма', 'admin.notif.tmpl.body_label': 'Текст письма (HTML)', 'admin.notif.tmpl.save': 'Сохранить', 'admin.notif.tmpl.close': 'Закрыть', 'admin.notif.tmpl.translate': 'Авто-перевод на другие языки', 'admin.notif.tmpl.translating': 'Перевод...', 'admin.notif.tmpl.saving': 'Сохранение...', 'admin.notif.email_verification': 'Подтверждение email адреса', 'admin.notif.registration_success': 'Успешная регистрация', 'admin.notif.password_reset': 'Восстановление пароля', 'admin.notif.new_offer': 'Новое предложение', 'admin.notif.new_task': 'Новая задача', 'admin.notif.offer_accepted': 'Предложение принято', 'admin.notif.new_message': 'Новое сообщение', 'admin.notif.offer_declined': 'Отклонение предложения', 'admin.notif.offer_other_accepted': 'Выбран другой исполнитель', 'admin.notif.task_updated': 'Изменение задания', 'admin.notif.deadline_reminder': 'Напоминание о дедлайне', 'admin.notif.task_archived': 'Автоснятие задания', 'admin.notif.referral_reward': 'Реферальная награда', // Шаблоны email для тарифов 'admin.email_template.plan_activated': 'Тарифы — активация тарифа', 'admin.email_template.plan_upgraded': 'Тарифы — повышение тарифа', 'admin.email_template.plan_downgrade_scheduled': 'Тарифы — запланированное понижение', 'admin.email_template.plan_downgrade_applied': 'Тарифы — применение понижения', 'admin.email_template.plan_renewal_reminder': 'Тарифы — напоминание о продлении', 'admin.email_template.plan_insufficient_funds': 'Тарифы — нехватка средств', // Модальное окно подтверждения тарифа 'pricing.confirm.title': 'Подтвердите выбор тарифа', 'pricing.confirm.plan': 'Тариф', 'pricing.confirm.prorated': 'Зачёт остатка', 'pricing.confirm.effective_price': 'К оплате', 'pricing.confirm.your_balance': 'Ваш баланс', 'pricing.confirm.downgrade_info': 'Переход на новый тариф произойдёт автоматически после окончания текущего периода.', 'pricing.confirm.insufficient': 'Недостаточно средств на балансе.', 'pricing.confirm.top_up': 'Пополнить', 'pricing.confirm.schedule_downgrade': 'Запланировать переход', 'pricing.confirm.pay': 'Оплатить', 'admin.user_edit.title': 'Редактирование пользователя', 'admin.user_edit.email': 'Email', 'admin.user_edit.email_verified': 'Email подтверждён', 'admin.user_edit.email_not_verified': 'Email не подтверждён', 'admin.user_edit.verify_email_btn': 'Подтвердить вручную', 'admin.user_edit.verify_email_done': 'Email подтверждён!', 'admin.user_edit.id': 'ID', 'admin.user_edit.registered': 'Регистрация', 'admin.user_edit.last_seen': 'Последний визит', 'admin.user_edit.lang': 'Язык', 'admin.user_edit.first_name': 'Имя', 'admin.user_edit.last_name': 'Фамилия', 'admin.user_edit.phone': 'Телефон', 'admin.user_edit.bio': 'О себе', 'admin.user_edit.role': 'Роль', 'admin.user_edit.plan': 'Тариф', 'admin.user_edit.no_plan': '— Без тарифа —', 'admin.user_edit.active': 'Активный аккаунт', 'admin.user_edit.balance': 'Баланс (EUR)', 'admin.user_edit.skills': 'Навыки', 'admin.user_edit.tab.profile': 'Профиль', 'admin.user_edit.tab.account': 'Аккаунт', 'admin.user_edit.tab.balance': 'Баланс', 'admin.user_edit.tab.settings': 'Настройки', 'admin.user_edit.tab.specialist': 'Портфолио', 'admin.user_edit.tab.site': 'Сайт', 'admin.user_edit.plan_expires': 'Тариф истекает', 'admin.user_edit.interface_lang': 'Язык интерфейса', 'admin.user_edit.comm_languages': 'Языки общения', 'admin.user_edit.personal_site_slug': 'Персональная страница', 'admin.user_edit.show_contact_info': 'Показывать контакты', 'admin.user_edit.show_contact_info.hint': 'Видно заказчикам', 'admin.user_edit.notify_new_tasks': 'Уведомлять о новых задачах', 'admin.user_edit.notify_new_tasks.hint': 'Push и email уведомления', 'admin.user_edit.notif_messages': 'Уведомления о сообщениях', 'admin.user_edit.notif_messages.hint': 'Новые сообщения в чате', 'admin.user_edit.site_settings': 'Настройки персональной страницы', 'admin.user_edit.categories': 'Категории услуг', 'admin.user_edit.locations': 'Районы обслуживания', 'admin.user_edit.skill_placeholder': 'Новый навык...', 'admin.user_edit.add_category': '— Выберите категорию —', 'admin.user_edit.add_location': '— Выберите район —', 'admin.user_edit.specialist_cards': 'Портфолио специалиста', 'admin.user_edit.no_cards': 'Портфолио не найдено', 'admin.user_edit.card_title': 'Заголовок портфолио', 'admin.user_edit.card_description': 'Описание', 'admin.balance.topup.btn': 'Пополнить', 'admin.balance.withdraw.btn': 'Списать', 'admin.balance.modal_hint': 'Изменения применяются сразу и фиксируются в истории', 'admin.balance.topup.title': 'Пополнение баланса', 'admin.balance.topup.amount': 'Сумма', 'admin.balance.topup.description': 'Комментарий', 'admin.balance.topup.description.placeholder': 'Например: бонус или ручное пополнение', 'admin.balance.topup.submit': 'Пополнить баланс', 'admin.balance.withdraw.title': 'Снятие баланса', 'admin.balance.withdraw.amount': 'Сумма', 'admin.balance.withdraw.description': 'Комментарий', 'admin.balance.withdraw.description.placeholder': 'Например: возврат или ручное списание', 'admin.balance.withdraw.submit': 'Списать баланс', 'admin.user_edit.role.customer': 'Заказчик', 'admin.user_edit.role.specialist': 'Исполнитель', 'admin.user_edit.role.admin': 'Администратор', 'common.refresh': 'Обновить', 'common.back_home': 'На главную', 'admin.loc.hint': 'Управление городами и районами', 'admin.loc.add_city': 'Новый город', 'admin.loc.add_district': 'Добавить район', 'admin.loc.new': 'Новая локация', 'admin.loc.edit': 'Редактировать локацию', 'admin.loc.district': 'район', 'admin.loc.empty': 'Нет локаций', 'admin.loc.delete.confirm': 'Удалить локацию? Все районы также будут удалены.', 'admin.cat.add_root': 'Новая категория', 'admin.cat.add_sub': 'Подкатегория', 'admin.cat.edit': 'Редактировать', 'admin.cat.delete': 'Удалить', 'admin.cat.delete.confirm': 'Удалить категорию? Все подкатегории также будут удалены.', 'admin.cat.slug': 'Slug', 'admin.cat.icon': 'Иконка', 'admin.cat.name_el': 'Греческий', 'admin.cat.name_en': 'Английский', 'admin.cat.name_ru': 'Русский', 'admin.cat.order': 'Порядок', 'admin.cat.active': 'Активна', 'admin.cat.parent': 'Родительская категория', 'admin.cat.no_parent': 'Верхний уровень', 'admin.cat.save': 'Сохранить', 'admin.cat.cancel': 'Отмена', 'admin.cat.empty': 'Нет категорий', 'admin.cat.hint': 'Управление категориями с многоуровневой иерархией', 'admin.cat.new': 'Новая категория', 'admin.cat.subcategory': 'подкатегория', 'admin.cat.add_child': 'Добавить подкатегорию', 'admin.cat.inactive': 'Неактивна', 'admin.event.user_login': 'Вход', 'admin.event.user_register': 'Регистрация', 'admin.event.admin_user_deactivate': 'Блокировка юзера', 'admin.event.admin_user_activate': 'Разблокировка юзера', 'admin.event.admin_user_role_changed': 'Смена роли', 'admin.event.admin_task_cancelled': 'Отмена задачи', 'admin.event.admin_task_deleted': 'Удаление задачи', 'admin.event.admin_report_reviewed': 'Жалоба рассмотрена', 'admin.event.admin_report_dismissed': 'Жалоба отклонена', 'admin.event.task_created': 'Создана задача', // User status 'user.online': 'Онлайн', 'user.seen_minutes': 'был здесь {n} мин назад', 'user.seen_hours': 'был здесь {n} ч назад', 'user.seen_yesterday': 'был здесь вчера', 'user.seen_days': 'был здесь {n} дн назад', // Specialists 'specialists.title': 'Специалисты', 'specialists.search': 'Поиск специалиста...', 'specialists.search.btn': 'Поиск', 'specialists.empty': 'Специалисты не найдены', 'specialists.no_bio': 'Без описания', 'specialists.view': 'Смотреть профиль', 'specialists.reviews': 'отзывов', 'specialist.favorite': 'Добавить в избранное', 'specialist.unfavorite': 'Убрать из избранного', 'specialist.site_link': 'Личный сайт', 'favorites.specialists.title': 'Избранные специалисты', 'favorites.specialists.empty': 'Вы ещё не добавили специалистов в избранное', 'nav.favorites': 'Избранное', 'nav.schedule': 'Расписание', 'nav.find_tasks': 'Поиск заказов', 'schedule.title': 'Моё расписание', 'schedule.subtitle': 'Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность', 'schedule.available': 'Свободен', 'schedule.busy': 'Занят', 'schedule.unset': 'Не указано', 'schedule.click_hint': '← клик меняет статус по кругу', 'schedule.range_mode': 'Выделить диапазон', 'schedule.range_from': 'С {date} — выберите конечную дату', 'schedule.click_to_set': 'Нажмите чтобы отметить', 'schedule.free': 'свободно', 'schedule.busy_count': 'занято', 'schedule.free_days': 'свободных дней', 'schedule.googleCalendar': 'Google Календарь', 'schedule.connectGoogle': 'Подключить Google Календарь', 'schedule.disconnectGoogle': 'Отключить', 'schedule.connectedAs': 'Подключено как', 'schedule.importFromGoogle': 'Синхр. из Google', 'schedule.gcalConnected': '\u2713 Google Календарь подключён', 'schedule.gcalError': 'Ошибка подключения Google Календарь', 'schedule.gcalImportDone': 'Импортировано {n} дней из Google Календарь', 'schedule.gcalAutoSyncNote': 'Изменения доступности автоматически отправляются в Google Календарь', 'schedule.gcalConnectDesc': 'Подключите Google Календарь для автоматической синхронизации расписания', 'schedule.gcalDisconnectConfirm': 'Отключить Google Календарь?', 'find_tasks.title': 'Поиск заказов', 'find_tasks.for_me': 'Для меня', 'find_tasks.all': 'Все заказы', 'find_tasks.by_category': 'По категориям', 'find_tasks.list': 'Списком', 'find_tasks.already_offered': 'Предложение отправлено', 'find_tasks.offer_now': 'Откликнуться', 'find_tasks.empty_for_me': 'Нет заказов в ваших категориях', 'find_tasks.banner_hint': 'Найдите заказы по категориям вашего портфолио', 'find_tasks.no_cards': 'Создайте портфолио специалиста, чтобы видеть подходящие заказы', 'find_tasks.add_card': 'Создать портфолио', 'find_tasks.search': 'Поиск заказов...', 'find_tasks.tasks_count': 'заданий', 'footer.tagline': 'Платформа задач для Греции', 'footer.rights': 'Все права защищены.', // App download section 'app.download_title': 'Скачайте мобильное приложение CanHelp', 'app.download_desc': 'Всё CanHelp — всегда под рукой. Доступно для Android и iOS.', // Nav 'nav.pricing': 'Тарифы', // Pricing page 'pricing.title': 'Тарифы', 'pricing.subtitle': 'Выберите подходящий план', 'pricing.role.customer': 'Заказчик', 'pricing.role.specialist': 'Специалист', 'pricing.free': 'Бесплатно', 'pricing.per_month': 'мес', 'pricing.duration': 'Срок', 'pricing.days': 'дн.', 'pricing.current_plan': 'Ваш план', 'pricing.popular': 'Популярный', 'pricing.choose': 'Выбрать', 'pricing.your_plan': 'Активный план', 'pricing.free_default': 'По умолчанию', 'pricing.compare': 'Сравнение функций', 'pricing.feature': 'Функция', 'pricing.faq_note': 'Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.', 'pricing.feat.messages': 'Сообщений / день', 'pricing.feat.orders': 'Заказов / день', 'pricing.feat.contact_all': 'Связь со всеми', 'pricing.feat.view_phone': 'Просмотр телефона', 'pricing.feat.show_contact': 'Показывать контакты', 'pricing.feat.favorites': 'Избранное', 'pricing.feat.verified_badge': 'Верифицированный бейдж', 'pricing.feat.google_calendar': 'Google Календарь', 'pricing.feat.personal_site': 'Персональный сайт', 'pricing.feat.auto_response': 'Авто-ответ', 'pricing.feat.auto_match': 'Авто-подбор', 'pricing.feat.highlighted_reviews': 'Выделенные отзывы', 'pricing.feat.portfolio': 'Элементов портфолио', 'pricing.feat.cards': 'Карточки специалиста', 'pricing.feat.notify_tasks': 'Уведомления о новых задачах', 'pricing.feat.video': 'Видео в портфолио', // Upgrade prompt 'upgrade.available_in': 'Доступно в', 'upgrade.cta': 'Улучшить', // Dashboard plan block 'dashboard.plan.title': 'Мой план', 'dashboard.plan.expires': 'Истекает через {n} дней', 'dashboard.plan.upgrade': 'Улучшить план', 'dashboard.plan.no_plan': 'Бесплатный план', 'dashboard.plan.messages': 'Сообщений сегодня', 'dashboard.plan.orders': 'Заказов сегодня', 'dashboard.plan.limits': 'Дневные лимиты', 'dashboard.plan.features': 'Функции', 'dashboard.plan.stats': 'Статистика', 'dashboard.stats.cards': 'Портфолио', 'dashboard.stats.maxCards': 'Макс. портфолио', 'dashboard.stats.portfolioItems': 'Элементы портфолио', 'dashboard.stats.maxPortfolioItems': 'Макс. элементы', 'dashboard.stats.activeOffers': 'Активные отклики', 'dashboard.stats.reviewsReceived': 'Отзывы', 'dashboard.stats.activeTasks': 'Активные задачи', 'dashboard.stats.completedTasks': 'Завершённые', 'status.need_help': 'Нужна помощь', 'status.active': 'Активен', 'status.toggle_on': 'Включить', 'status.toggle_off': 'Выключить', // FOMO 'fomo.missed_orders': 'Пропущено {n} заказов', 'fomo.missed_value': 'На сумму €{v}', 'fomo.upgrade_hint': 'Улучшите план — получайте больше заказов', 'fomo.conversion': 'Конверсия задач', 'fomo.active': 'Активные', 'fomo.with_offers': 'С офертами', 'fomo.completed': 'Завершённые', 'fomo.already_offered': '{n} специалистов уже откликнулись', 'fomo.specialist_missed': 'Вы пропустили {n} заказов', 'fomo.top_categories': 'Категории', 'fomo.offers_received': 'предложений получено', 'fomo.avg_offers': 'В среднем {n}/задача', 'fomo.completion_rate': 'завершено', // Task auto-match 'task.auto_match': 'Авто-матч', 'task.auto_match_results': 'Топ специалисты', 'task.no_offer_yet': 'Вы ещё не отправили предложение', 'task.make_offer': 'Отправить предложение', 'auto_response.title': 'Авто-ответ', 'auto_response.enabled': 'Включить авто-ответ', 'auto_response.min_budget': 'Мин. бюджет', 'auto_response.max_budget': 'Макс. бюджет', 'auto_response.default_price': 'Цена по умолчанию', 'auto_response.default_message': 'Сообщение по умолчанию', 'auto_response.max_per_day': 'Макс. авто-офертов в день', 'auto_response.save': 'Сохранить', 'auto_response.saved': 'Сохранено', 'auto_response.categories': 'Категории', 'auto_response.locations': 'Локации', // Personal site 'profile.personal_site': 'Персональный сайт', 'profile.site_slug': 'URL slug', 'profile.site_slug_hint': 'Только латинские буквы, цифры, - и _', 'profile.site_open': 'Открыть сайт', 'profile.site_preview': 'Ваш сайт', 'profile.show_contact': 'Показывать контакты', 'profile.show_contact_hint': 'Заказчики с Pro/Ultimate-планом увидят ваш телефон', // Google Calendar plan gate 'gcal.upgrade_required': 'Google Календарь требует план Pro или Ultimate', // Chat limits 'chat.limit_warning': 'Осталось {n} сообщений сегодня', 'chat.limit_reached': 'Лимит сообщений исчерпан. Улучшите план', 'chat.upgrade': 'Улучшить', // Site page 'site.member_since': 'С нами с', 'site.rating': 'Рейтинг', 'site.completed_tasks': 'Выполнено', 'site.languages': 'Языков', 'site.photos': 'фото', 'site.contact_form': 'Связаться', 'site.contact_sent': 'Сообщение отправлено!', 'site.contact_sent_desc': 'Специалист свяжется с вами в ближайшее время', 'site.contact_name': 'Имя', 'site.contact_name_ph': 'Ваше имя', 'site.contact_email_ph': 'your@email.com', 'site.contact_message': 'Сообщение', 'site.contact_message_ph': 'Опишите вашу задачу...', 'site.contact_send': 'Отправить', 'site.share': 'Поделиться', 'site.speaks_languages': 'Говорит на языках', 'site.message_sent': 'Сообщение отправлено!', 'site.message_sent_desc': 'Специалист получит его в чате', 'site.message_placeholder': 'Напишите сообщение...', 'site.write_to_chat': 'Написать в чат', 'site.auth_required_title': 'Нужна авторизация', 'site.auth_required_desc': 'Чтобы написать в чат, необходимо войти в аккаунт CanHelp.', 'site.auth_login_btn': 'Войти в аккаунт', 'site.auth_contact_form_btn': 'Написать через форму обратной связи', 'specialist.services': 'Услуги', 'portfolio.title': 'Портфолио', 'status.can_help_now': 'Готов помочь', 'common.not_found': 'Страница не найдена', 'common.anonymous': 'Анонимно', 'specialist_setup.page_title': 'Настройка профиля специалиста', 'specialist_setup.step_of': 'Шаг {current} из {total}', 'specialist_setup.next': 'Далее', 'specialist_setup.back': 'Назад', 'specialist_setup.skip': 'Пропустить', 'specialist_setup.finish': 'Завершить', 'specialist_setup.go_to_profile': 'Перейти в профиль', 'specialist_setup.browse_tasks': 'Найти задачи', 'specialist_setup.step1.title': 'Добро пожаловать!', 'specialist_setup.step1.subtitle': 'Давайте настроим ваш профиль', 'specialist_setup.step1.desc': 'Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.', 'specialist_setup.step1.what_next': 'Что мы сделаем:', 'specialist_setup.step1.item1': 'Заполним основную информацию', 'specialist_setup.step1.item2': 'Создадим карточку услуги', 'specialist_setup.step1.item3': 'Добавим навыки и категории', 'specialist_setup.step1.item4': 'Выберем географию обслуживания', 'specialist_setup.step1.item5': 'Загрузим фото портфолио', 'specialist_setup.step2.title': 'Базовый профиль', 'specialist_setup.step2.subtitle': 'Расскажите о себе', 'specialist_setup.step2.bio_label': 'О себе', 'specialist_setup.step2.bio_placeholder': 'Опишите ваш опыт, услуги которые вы предлагаете...', 'specialist_setup.step2.phone_label': 'Телефон', 'specialist_setup.step2.phone_placeholder': '+30 6900000000', 'specialist_setup.step2.photo_label': 'Фото профиля', 'specialist_setup.step2.photo_btn': 'Загрузить фото', 'specialist_setup.step2.photo_uploading': 'Загрузка...', 'specialist_setup.step2.photo_hint': 'Отображается в вашем профиле', 'specialist_setup.step3.title': 'Карточка услуги', 'specialist_setup.step3.subtitle': 'Создайте вашу первую карточку услуги', 'specialist_setup.step3.title_label': 'Название карточки', 'specialist_setup.step3.title_placeholder': 'Напр. Сантехник, Электрик, Уборка...', 'specialist_setup.step3.desc_label': 'Описание', 'specialist_setup.step3.desc_placeholder': 'Подробно опишите что вы предлагаете, опыт, преимущества...', 'specialist_setup.step3.title_required': 'Название обязательно', 'specialist_setup.step4.title': 'Навыки и категории', 'specialist_setup.step4.subtitle': 'Добавьте навыки и выберите категории', 'specialist_setup.step4.skills_label': 'Навыки', 'specialist_setup.step4.skills_placeholder': 'Напр. Монтаж труб...', 'specialist_setup.step4.skills_add': 'Добавить', 'specialist_setup.step4.categories_label': 'Категории', 'specialist_setup.step5.title': 'География обслуживания', 'specialist_setup.step5.subtitle': 'Где вы оказываете услуги?', 'specialist_setup.step5.hint': 'Выберите города или конкретные районы', 'specialist_setup.done.title': 'Ваш профиль готов!', 'specialist_setup.done.subtitle': 'Поздравляем! Профиль настроен', 'specialist_setup.done.desc': 'Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам.' } }; export function getTranslations(locale) { const t = translations[locale] ?? translations.el; return (key, fallback)=>t[key] ?? translations.el[key] ?? fallback ?? key; } /06undefined268274undefined187763187769undefined'', /***/ 13260: 0&&, /***/ 14276: %%, /***/ 15043: ""$$, /***/ 20138: /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocaleProvider: () => (/* binding */ LocaleProvider) /* harmony export */ }); /* unused harmony export useLocale */ /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const LocaleProvider = registerClientReference( function() { throw new Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "LocaleProvider", );export const useLocale = registerClientReference( function() { throw new Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/context/locale.tsx", "useLocale", );61134undefined136142undefined166188(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined527533undefined552574(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined  , /***/ 21046: /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* __next_internal_client_entry_do_not_use__ ScrollToTopButton auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { useEffect, useState } from 'react'; export function ScrollToTopButton() { const [visible, setVisible] = useState(false); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ setVisible(window.scrollY > 200); }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsx("button", { className: `scroll-to-top-btn${visible ? ' visible' : ''}`, "aria-label": "Наверх", onClick: ()=>window.scrollTo({ top: 0, behavior: 'smooth' }), children: /*#__PURE__*/ _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /*#__PURE__*/ _jsx("path", { d: "M10 16V4M10 4L4 10M10 4L16 10", stroke: "white", strokeWidth: "2.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }); } z71118undefined120163undefined165171undefined237244(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined309317(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined570573(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined833836(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined10431046(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined, /***/ 30460: , /***/ 32948: /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollToTopButton: () => (/* binding */ ScrollToTopButton) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); )// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const ScrollToTopButton = registerClientReference( function() { throw new Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx", "ScrollToTopButton", );61134undefined136142undefined169191(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined, /***/ 33506: __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NotFound) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3498); /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(next_link__WEBPACK_IMPORTED_MODULE_1__); import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import Link from 'next/link'; export default function NotFound() { return /*#__PURE__*/ _jsx("div", { className: "min-h-screen flex items-center justify-center text-center px-4", children: /*#__PURE__*/ _jsxs("div", { children: [ /*#__PURE__*/ _jsx("h1", { className: "text-8xl font-bold text-blue-600 mb-4", children: "404" }), /*#__PURE__*/ _jsx("p", { className: "text-xl text-gray-700 mb-6", children: "Η σελίδα δεν βρέθηκε" }), /*#__PURE__*/ _jsx(Link, { href: "/", className: "bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700", children: "Επιστροφή στην Αρχική" }) ] }) }); } 062undefined6492undefined94108undefined156159(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined287291(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined356359(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined527530(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined703706(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined708711(next_link__WEBPACK_IMPORTED_MODULE_1___default())undefined, /***/ 39348: /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Footer: () => (/* binding */ Footer) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); // This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Footer = registerClientReference( function() { throw new Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Footer.tsx", "Footer", );61134undefined136142undefined158180(0,react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__.registerClientReference)undefined, /***/ 47570: __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ RootLayout), /* harmony export */ generateMetadata: () => (/* binding */ generateMetadata) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5939); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var next_headers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(56057); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14276); /* harmony import */ var _globals_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_globals_css__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _components_Header__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(67674); /* harmony import */ var _components_Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39348); /* harmony import */ var _context_locale__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(20138); /* harmony import */ var _context_location__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1697); /* harmony import */ var _components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32948); import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { cookies, headers } from 'next/headers'; import './globals.css'; import { Header } from '@/components/Header'; import { Footer } from '@/components/Footer'; import { LocaleProvider } from '@/context/locale'; import { LocationProvider } from '@/context/location'; import { ScrollToTopButton } from '@/components/ScrollToTopButton'; async function fetchSeoSettings() { try { const apiBase = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; const res = await fetch(`${apiBase}/api/admin/seo-public`, { next: { revalidate: 60 } }); if (!res.ok) return {}; return res.json(); } catch { return {}; } } export async function generateMetadata() { const seo = await fetchSeoSettings(); return { title: seo['seo.siteTitle'] || 'CanHelp — Βρες ειδικό για κάθε δουλειά', description: seo['seo.siteDescription'] || 'Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.', keywords: 'εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά', robots: seo['seo.indexingEnabled'] === 'false' ? 'noindex, nofollow' : undefined }; } export default async function RootLayout({ children }) { const cookieStore = await cookies(); const headerStore = await headers(); const pathname = headerStore.get('x-pathname') ?? ''; const isStandalone = pathname.startsWith('/site/'); const rawLocale = cookieStore.get('canhelp_locale')?.value; const locales = [ 'el', 'en', 'ru' ]; const initialLocale = locales.includes(rawLocale) ? rawLocale : 'el'; const initialLocation = decodeURIComponent(cookieStore.get('canhelp_location')?.value ?? ''); const seo = await fetchSeoSettings(); const headScripts = seo['seo.headScripts'] ?? ''; const parsedScripts = []; if (headScripts.trim()) { const re = /]*)>([\s\S]*?)<\/script>|]*)\/>/gi; let m; while((m = re.exec(headScripts)) !== null){ const attrs = m[1] ?? m[3] ?? ''; const inline = (m[2] ?? '').trim(); const srcMatch = attrs.match(/src=["']([^"']+)["']/); parsedScripts.push({ src: srcMatch?.[1], async: /\basync\b/i.test(attrs), defer: /\bdefer\b/i.test(attrs), inline: inline || undefined }); } } return /*#__PURE__*/ _jsxs("html", { lang: initialLocale, children: [ /*#__PURE__*/ _jsx("head", { children: parsedScripts.map((s, i)=>{ if (s.src) return /*#__PURE__*/ _jsx("script", { src: s.src, async: s.async, defer: s.defer }, i); if (s.inline) return /*#__PURE__*/ _jsx("script", { dangerouslySetInnerHTML: { __html: s.inline } }, i); return null; }) }), /*#__PURE__*/ _jsx("body", { children: /*#__PURE__*/ _jsx(LocaleProvider, { initialLocale: initialLocale, children: /*#__PURE__*/ _jsxs(LocationProvider, { initialSlug: initialLocation, children: [ !isStandalone && /*#__PURE__*/ _jsx(Header, {}), /*#__PURE__*/ _jsx("main", { className: "min-h-screen", children: children }), !isStandalone && /*#__PURE__*/ _jsx(ScrollToTopButton, {}), !isStandalone && /*#__PURE__*/ _jsx(Footer, {}) ] }) }) }) ] }); } 062undefined64111undefined113135undefined137181undefined183227undefined229278undefined280333undefined335401undefined473503"https://api.canhelp.gr"undefined5085300undefined780786undefined13121326undefined13991405(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .cookies */ .UL)undefined14401446(0,next_headers__WEBPACK_IMPORTED_MODULE_1__/* .headers */ .b3)undefined26002604(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined26912694(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined28122815(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined30263029(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined32863289(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33413344(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined33463359_context_locale__WEBPACK_IMPORTED_MODULE_5__.LocaleProviderundefined34583462(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)undefined34643479_context_location__WEBPACK_IMPORTED_MODULE_6__.LocationProviderundefined36333636(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined36383643_components_Header__WEBPACK_IMPORTED_MODULE_3__.Headerundefined36933696(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined39093912(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined39143930_components_ScrollToTopButton__WEBPACK_IMPORTED_MODULE_7__.ScrollToTopButtonundefined39974000(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined40024007_components_Footer__WEBPACK_IMPORTED_MODULE_4__.Footerundefined  , /***/ 48178: /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ E: () => (/* binding */ shortName), /* harmony export */ H: () => (/* binding */ formatShortName) /* harmony export */ }); $/** * Shortens the last name to first letter + period. * "Иван Петров" → "Иван П." * Works with a pre-composed full name string. */ export function shortName(fullName) { if (!fullName?.trim()) return '—'; const parts = fullName.trim().split(/\s+/); if (parts.length < 2 || !parts[1]) return parts[0]; return `${parts[0]} ${parts[1][0].toUpperCase()}.`; } /** * Formats separate firstName + lastName fields, shortening the last name. * Falls back to parsing fullName if firstName is not available. */ export function formatShortName(firstName, lastName, fallbackName) { if (firstName?.trim()) { const l = lastName?.trim(); return l ? `${firstName.trim()} ${l[0].toUpperCase()}.` : firstName.trim(); } return shortName(fallbackName); } 136142undefined523529undefined, /***/ 49046: V/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { import(/* webpackMode: "eager", webpackExports: ["__esModule","default"] */ "/opt/canhelp/node_modules/next/dist/client/app-dir/link.js"); s0136Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 94496, 23))undefined, /***/ 56003: 9/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LocationProvider: () => (/* binding */ LocationProvider), /* harmony export */ z: () => (/* binding */ useLocation) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78157); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31768); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(91864); B /* __next_internal_client_entry_do_not_use__ LocationProvider,useLocation auto */ import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { getLocations } from '@/lib/api'; const LocationContext = /*#__PURE__*/ createContext({ locationSlug: '', locationTree: [], locationLoading: true, setLocation: ()=>{}, getLabel: ()=>'' }); function readCookieLocation() { if (typeof document === 'undefined') return ''; const match = document.cookie.match(/(?:^|;\s*)canhelp_location=([^;]+)/); return match?.[1] ? decodeURIComponent(match[1]) : ''; } export function LocationProvider({ children, initialSlug = '' }) { const [locationSlug, setLocationSlug] = useState(initialSlug); const [locationTree, setLocationTree] = useState([]); const [locationLoading, setLocationLoading] = useState(true); // Sync from cookie on client mount process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const cookieSlug = readCookieLocation(); setLocationSlug(cookieSlug); }, []); // Load location tree once process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ getLocations().then((tree)=>setLocationTree(tree)).catch(()=>{}).finally(()=>setLocationLoading(false)); }, []); const setLocation = useCallback((slug)=>{ setLocationSlug(slug); const encoded = encodeURIComponent(slug); document.cookie = `canhelp_location=${encoded}; path=/; max-age=31536000; SameSite=Lax`; }, []); const getLabel = useCallback((locale)=>{ if (!locationSlug) return ''; for (const city of locationTree){ if (city.slug === locationSlug) return city.names[locale] ?? city.names.el; for (const d of city.children ?? []){ if (d.slug === locationSlug) return d.names[locale] ?? d.names.el; } } return locationSlug; }, [ locationSlug, locationTree ]); return /*#__PURE__*/ _jsx(LocationContext.Provider, { value: { locationSlug, locationTree, locationLoading, setLocation, getLabel }, children: children }); } export function useLocation() { return useContext(LocationContext); } +82129undefined131214undefined216256undefined296308(0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)undefined657663undefined768775(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined835842(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined899906(0,react__WEBPACK_IMPORTED_MODULE_1__.useState)undefined10101018(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined12101218(0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)undefined12341245(0,_lib_api__WEBPACK_IMPORTED_MODULE_2__/* .getLocations */ .Vs)undefined13751385(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined16081618(0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)undefined20712074(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)undefined22962302undefined23392348(0,react__WEBPACK_IMPORTED_MODULE_1__.useContext)undefined, /***/ 58719: ||N // EXPORTS __webpack_require__.d(__webpack_exports__, { Header: () => (/* binding */ Header) }); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime.js var react_jsx_runtime = __webpack_require__(78157); // EXTERNAL MODULE: ../../node_modules/next/dist/client/app-dir/link.js var app_dir_link = __webpack_require__(94496); var link_default = /*#__PURE__*/__webpack_require__.n(app_dir_link); // EXTERNAL MODULE: ../../node_modules/next/dist/api/navigation.js var navigation = __webpack_require__(71159); // EXTERNAL MODULE: ./src/lib/auth.ts var auth = __webpack_require__(13260); // EXTERNAL MODULE: ./src/context/locale.tsx var context_locale = __webpack_require__(96484); // EXTERNAL MODULE: ./src/lib/formatName.ts var formatName = __webpack_require__(48178); // EXTERNAL MODULE: ../../node_modules/next/dist/server/route-modules/app-page/vendored/ssr/react.js var react = __webpack_require__(31768); // EXTERNAL MODULE: ./src/lib/translations.ts var translations = __webpack_require__(12998); ;// ./src/components/LanguageSwitcher.tsx }]/* __next_internal_client_entry_do_not_use__ LanguageSwitcher auto */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useRef, useEffect } from 'react'; import { useLocale } from '@/context/locale'; import { LOCALES } from '@/lib/translations'; export function LanguageSwitcher() { const { locale, setLocale } = useLocale(); const [open, setOpen] = useState(false); const ref = useRef(null); const current = LOCALES.find((l)=>l.code === locale) ?? LOCALES[0]; // Close on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); return /*#__PURE__*/ _jsxs("div", { ref: ref, className: "relative", children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setOpen(!open), className: "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700", "aria-label": "Change language", children: [ /*#__PURE__*/ _jsx("span", { children: current.code.toUpperCase() }), /*#__PURE__*/ _jsx("svg", { className: `w-3.5 h-3.5 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), open && /*#__PURE__*/ _jsx("div", { className: "absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden", children: LOCALES.map((loc)=>/*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setLocale(loc.code); setOpen(false); }, className: `w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${locale === loc.code ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-700'}`, children: [ /*#__PURE__*/ _jsx("span", { children: loc.label }), locale === loc.code && /*#__PURE__*/ _jsx("svg", { className: "w-3.5 h-3.5 ml-auto text-blue-600", fill: "currentColor", viewBox: "0 0 20 20", children: /*#__PURE__*/ _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) ] }, loc.code)) }) ] }); } r70132undefined134185undefined187231undefined233277undefined279285undefined350358__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined391398__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined424429__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined458464__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined498504__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_asiSafe1__._undefined595603__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined908912__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined10181022__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined13801383__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined15141517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined18611864__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined21472150__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined23182324__WEBPACK_MODULE_REFERENCE__7_5b224c4f43414c4553225d_call_asiSafe1__._undefined23512355__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined28092812__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined29732976__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined32313234__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined138224(0,context_locale/* useLocale */.Y)undefined257341(0,react.useState)undefined367447(0,react.useRef)undefined476545translations/* LOCALES */.YZundefined579643translations/* LOCALES */.YZundefined734820(0,react.useEffect)undefined11251201(0,react_jsx_runtime.jsxs)undefined13071383(0,react_jsx_runtime.jsxs)undefined17411815(0,react_jsx_runtime.jsx)undefined19462020(0,react_jsx_runtime.jsx)undefined23642438(0,react_jsx_runtime.jsx)undefined27212795(0,react_jsx_runtime.jsx)undefined29633032translations/* LOCALES */.YZundefined30593135(0,react_jsx_runtime.jsxs)undefined35893663(0,react_jsx_runtime.jsx)undefined38243898(0,react_jsx_runtime.jsx)undefined41534227(0,react_jsx_runtime.jsx)undefinedRawSource // EXTERNAL MODULE: ./src/lib/api.ts var api = __webpack_require__(91864); // EXTERNAL MODULE: ../../node_modules/socket.io-client/build/esm-debug/index.js + 30 modules var esm_debug = __webpack_require__(44826); ;// ./src/components/Header.tsx y"(/* __next_internal_client_entry_do_not_use__ Header auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import Link from 'next/link'; import { useRouter, usePathname } from 'next/navigation'; import { useSession, signOut } from '@/lib/auth'; import { useLocale } from '@/context/locale'; import { formatShortName } from '@/lib/formatName'; import { LanguageSwitcher } from './LanguageSwitcher'; import { useState, useRef, useEffect } from 'react'; import { getUnreadCount, getMyDashboard } from '@/lib/api'; import { io } from 'socket.io-client'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export function Header() { const router = useRouter(); const pathname = usePathname(); const { data: session } = useSession(); const { t, locale } = useLocale(); const [menuOpen, setMenuOpen] = useState(false); const [profileOpen, setProfileOpen] = useState(false); const [unreadNotif, setUnreadNotif] = useState(0); const [unreadChat, setUnreadChat] = useState(0); const [msgToast, setMsgToast] = useState(null); const [planTier, setPlanTier] = useState(null); const profileRef = useRef(null); const headerRef = useRef(null); const toastTimer = useRef(null); // Close dropdowns on outside click process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } document.addEventListener('mousedown', handleClick); return ()=>document.removeEventListener('mousedown', handleClick); }, []); const isAdmin = session?.user?.role === 'admin'; const isSpecialist = session?.user?.role === 'specialist'; // Reset chat badge when entering chat process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (pathname === '/chat') setUnreadChat(0); }, [ pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) return; const socket = io(API_URL, { withCredentials: true, transports: [ 'websocket', 'polling' ] }); socket.on('new_message', (msg)=>{ if (pathname === '/chat') return; setUnreadChat((c)=>c + 1); if (toastTimer.current) clearTimeout(toastTimer.current); setMsgToast(msg); toastTimer.current = setTimeout(()=>setMsgToast(null), 5000); }); return ()=>{ socket.disconnect(); if (toastTimer.current) clearTimeout(toastTimer.current); }; }, [ session, pathname ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setUnreadNotif(0); return; } const fetch = ()=>getUnreadCount().then((r)=>setUnreadNotif(r.count)).catch(()=>{}); fetch(); const timer = setInterval(fetch, 30000); return ()=>clearInterval(timer); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ if (!session) { setPlanTier(null); return; } getMyDashboard().then((d)=>setPlanTier(d.plan?.tier ?? null)).catch(()=>{}); }, [ session ]); process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{ const onScroll = ()=>{ if (!headerRef.current) return; if (window.scrollY > 40) { headerRef.current.classList.add('header-shrink'); } else { headerRef.current.classList.remove('header-shrink'); } }; window.addEventListener('scroll', onScroll); return ()=>window.removeEventListener('scroll', onScroll); }, []); return /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx("header", { ref: headerRef, className: "header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300", children: /*#__PURE__*/ _jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [ /*#__PURE__*/ _jsxs("div", { className: "flex items-center justify-between h-16 header-content transition-all duration-300", children: [ /*#__PURE__*/ _jsx(Link, { href: "/", className: "flex items-center shrink-0", children: /*#__PURE__*/ _jsx("span", { className: "logo-text text-2xl font-bold text-blue-600 transition-all duration-300", children: "CanHelp" }) }), /*#__PURE__*/ _jsxs("nav", { className: "hidden md:flex items-center gap-5 ml-auto", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.find_tasks') }), /*#__PURE__*/ _jsx(Link, { href: "/dashboard", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.dashboard') }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/tasks/new", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('dashboard.new_task') }), /*#__PURE__*/ _jsx(Link, { href: "/specialists", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.specialists') }) ] }), /*#__PURE__*/ _jsx(Link, { href: "/pricing", className: `font-medium text-sm transition ${pathname === '/pricing' ? 'text-blue-600' : 'text-gray-600 hover:text-blue-600'}`, children: t('nav.pricing', 'Pricing') }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadNotif > 0 ? 'text-orange-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "relative text-gray-600 hover:text-gray-900 flex items-center", children: [ /*#__PURE__*/ _jsx("svg", { className: `w-5 h-5 ${unreadChat > 0 ? 'text-green-500' : ''}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }), /*#__PURE__*/ _jsxs("div", { className: "relative", ref: profileRef, children: [ /*#__PURE__*/ _jsxs("button", { onClick: ()=>setProfileOpen(!profileOpen), className: "flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600", children: [ /*#__PURE__*/ _jsx("span", { className: "truncate max-w-[100px]", children: formatShortName(session.user.firstName, session.user.lastName, session.user.name) }), planTier === 'pro' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none", children: "Pro" }), planTier === 'ultimate' && /*#__PURE__*/ _jsx("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none", children: "★" }), /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) ] }), profileOpen && /*#__PURE__*/ _jsxs("div", { className: "absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 shrink-0 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none", children: unreadChat > 99 ? '99+' : unreadChat }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", onClick: ()=>setProfileOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), /*#__PURE__*/ _jsx("hr", { className: "my-1 border-gray-100" }), /*#__PURE__*/ _jsxs("button", { className: "w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50", onClick: ()=>{ setProfileOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-600 hover:text-blue-600 font-medium text-sm", children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm", children: t('nav.register') }) ] }), /*#__PURE__*/ _jsx(LanguageSwitcher, {}) ] }), /*#__PURE__*/ _jsxs("div", { className: "md:hidden flex items-center gap-2", children: [ /*#__PURE__*/ _jsx(LanguageSwitcher, {}), /*#__PURE__*/ _jsx("button", { className: "p-2", onClick: ()=>setMenuOpen(!menuOpen), "aria-label": "Toggle menu", children: /*#__PURE__*/ _jsx("svg", { className: "w-5 h-5 text-gray-600", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: menuOpen ? /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) : /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h16M4 18h16" }) }) }) ] }) ] }), menuOpen && /*#__PURE__*/ _jsxs("div", { className: "md:hidden py-4 border-t border-gray-100 flex flex-col gap-3", children: [ isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), t('nav.find_tasks') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }), session ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/chat", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadChat > 0 ? 'text-green-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" }) }), t('nav.chat'), unreadChat > 0 && /*#__PURE__*/ _jsx("span", { className: "ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full", children: unreadChat }) ] }), isSpecialist ? /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/tasks/new", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }), t('nav.new_task') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/specialists", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" }) }), t('nav.specialists') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsxs(Link, { href: "/notifications", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: `w-4 h-4 ${unreadNotif > 0 ? 'text-orange-500' : 'text-gray-400'}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }), /*#__PURE__*/ _jsxs("span", { className: "flex items-center gap-1.5", children: [ t('nav.notifications'), unreadNotif > 0 && /*#__PURE__*/ _jsx("span", { className: "px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full", children: unreadNotif > 99 ? '99+' : unreadNotif }) ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/dashboard", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" }) }), t('nav.dashboard') ] }) ] }), /*#__PURE__*/ _jsxs(Link, { href: "/favorites", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }), t('nav.favorites') ] }), (isSpecialist || isAdmin) && /*#__PURE__*/ _jsxs(Link, { href: "/schedule", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), t('nav.schedule') ] }), isAdmin && /*#__PURE__*/ _jsxs(Link, { href: "/admin", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsxs("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: [ /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" }), /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" }) ] }), t('nav.admin') ] }), /*#__PURE__*/ _jsxs(Link, { href: "/profile", className: "flex items-center gap-2 text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }), t('nav.profile') ] }), /*#__PURE__*/ _jsxs("button", { onClick: ()=>{ setMenuOpen(false); signOut().then(()=>{ window.location.href = '/'; }); }, className: "flex items-center gap-2 text-left text-red-500 py-1 font-medium", children: [ /*#__PURE__*/ _jsx("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /*#__PURE__*/ _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" }) }), t('nav.logout') ] }) ] }) : /*#__PURE__*/ _jsxs(_Fragment, { children: [ /*#__PURE__*/ _jsx(Link, { href: "/login", className: "text-gray-700 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.login') }), /*#__PURE__*/ _jsx(Link, { href: "/register", className: "text-blue-600 font-medium py-1", onClick: ()=>setMenuOpen(false), children: t('nav.register') }) ] }) ] }) ] }) }), msgToast && /*#__PURE__*/ _jsx("div", { className: "fixed bottom-5 right-5 z-[200] max-w-sm w-full", children: /*#__PURE__*/ _jsxs("div", { className: "bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in", children: [ /*#__PURE__*/ _jsx("span", { className: "text-2xl shrink-0", children: "\uD83D\uDCAC" }), /*#__PURE__*/ _jsxs("div", { className: "flex-1 min-w-0", children: [ /*#__PURE__*/ _jsx("p", { className: "font-semibold text-gray-900 text-sm", children: t('chat.toast_title') }), /*#__PURE__*/ _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: msgToast.body }) ] }), /*#__PURE__*/ _jsxs("div", { className: "flex flex-col items-end gap-2 shrink-0", children: [ /*#__PURE__*/ _jsx("button", { onClick: ()=>setMsgToast(null), className: "text-gray-400 hover:text-gray-600 text-lg leading-none", "aria-label": "close", children: "\xd7" }), /*#__PURE__*/ _jsx(Link, { href: `/chat?room=${msgToast.roomId}`, onClick: ()=>setMsgToast(null), className: "text-xs text-blue-600 hover:underline font-medium", children: t('chat.toast_open') }) ] }) ] }) }) ] }); } PT60145undefined147175undefined177233undefined235283undefined285329undefined331381undefined383436undefined438489undefined491549undefined551588undefined606636"https://api.canhelp.gr"undefined6416630undefined666672undefined712720__WEBPACK_MODULE_REFERENCE__2_5b22757365526f75746572225d_call_directImport_asiSafe1__._undefined746756__WEBPACK_MODULE_REFERENCE__2_5b22757365506174686e616d65225d_call_directImport_asiSafe1__._undefined791800__WEBPACK_MODULE_REFERENCE__3_5b2275736553657373696f6e225d_call_directImport_asiSafe1__._undefined831839__WEBPACK_MODULE_REFERENCE__4_5b227573654c6f63616c65225d_call_directImport_asiSafe1__._undefined880887__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined939946__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined9981005__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined10511058__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11001107__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11521159__WEBPACK_MODULE_REFERENCE__6_5b227573655374617465225d_call_directImport_asiSafe1__._undefined11911196__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12271232__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined12641269__WEBPACK_MODULE_REFERENCE__6_5b22757365526566225d_call_directImport_asiSafe1__._undefined13731381__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined19281936__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined20852093__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined21542155__WEBPACK_MODULE_REFERENCE__10_5b22696f225d_call_directImport_asiSafe1__._undefined28642872__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined29913004__WEBPACK_MODULE_REFERENCE__9_5b22676574556e72656164436f756e74225d_call_directImport_asiSafe1__._undefined32533261__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined33623375__WEBPACK_MODULE_REFERENCE__9_5b226765744d7944617368626f617264225d_call_directImport_asiSafe1__._undefined35273535__WEBPACK_MODULE_REFERENCE__6_5b22757365456666656374225d_call_directImport_asiSafe1__._undefined39953999__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined40014009__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined40604063__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined42714275__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined44294433__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined46544657__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined46594662__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined48514854__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined51725176__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined53965400__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined54025410__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined55335536__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined55385541__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined59305933__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined59355938__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined63726376__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined63786386__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined65096512__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined65146517__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined69146917__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined69196922__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined73997402__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined74047407__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined78367840__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined78427850__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined79737977__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined79797982__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined83248327__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined88668869__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined95499552__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1013010134__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1013610139__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1047210475__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1101211015__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1164211645__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1222312227__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1251612520__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1294112944__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1313913153__WEBPACK_MODULE_REFERENCE__5_5b22666f726d617453686f72744e616d65225d_call_directImport_asiSafe1__._undefined1338913392__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1385613859__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1437214375__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1492514928__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1557015574__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1591415918__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1592015928__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined1609916103__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1610516108__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1666816671__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1733317336__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1819018194__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined1819618199__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined1876118764__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined1942619429__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2053920543__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2054520553__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined2072420728__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2073020733__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2129721300__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2200522008__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2281322817__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2328223285__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2412824132__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2413424137__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2469224695__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2539825401__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2615426158__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2661326616__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2745927463__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2746527468__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined2802828031__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2869328696__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined2982129825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined2982729830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3034630349__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3096330966__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3180831812__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3181431817__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3233632339__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3295332956__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3382133825__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3382733830__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3434634350__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3504635049__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3602936032__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3692336927__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3692936932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3745037453__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3806738070__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined3890438908__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined3891038913__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined3943339436__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4005040053__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4094540948__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4120641210__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4163641642__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined4207442077__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4267742680__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4378743791__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4379343801__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4392443927__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4392943932__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4431644319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4432144324__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4482344826__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4482844843__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4497044974__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4517145174__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4517645191__WEBPACK_MODULE_REFERENCE__8_5b224c616e67756167655377697463686572225d_directImport_asiSafe1__._undefined4525345256__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4555445557__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4600346006__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4631646319__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4688746891__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4710547109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4711147119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined4722647230__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4723247235__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4760847611__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4807248075__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4867248676__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined4867848681__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined4905849061__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined4952249525__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5025650260__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5026250270__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5037750381__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5038350386__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5076350766__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5122751230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5179651800__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5180251805__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5218452187__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5264852651__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5348253486__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5348853496__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5360353607__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5360953612__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5398453987__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5448954492__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5513455137__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5557655580__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5558255590__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5571355717__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5571955722__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5613956142__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5665156654__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5729257296__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5729857301__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5772057723__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5823258235__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined5910559109__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5911159119__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined5924259246__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined5924859251__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined5967259675__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6022760230__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6089160895__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6126461267__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6190561909__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6191161914__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6233162334__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6284362846__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6369663700__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6370263705__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6408264085__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6454664549__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6525465258__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6526065263__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6563965642__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6610366106__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6675566759__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6676166764__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6713767141__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6766067663__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6852368526__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined6917769181__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined6918369186__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined6956169564__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7002570028__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7064670650__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7083970845__WEBPACK_MODULE_REFERENCE__3_5b227369676e4f7574225d_call_directImport_asiSafe1__._undefined7127971282__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7172971732__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7240572409__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7241172419__WEBPACK_MODULE_REFERENCE__0_5b22467261676d656e74225d_directImport_asiSafe1__._undefined7252672529__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7253172534__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7293272935__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7293772940__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined7351473517__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7364573649__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7386073863__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7405474058__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7421274215__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7446074463__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7475174755__WEBPACK_MODULE_REFERENCE__0_5b226a737873225d_call_directImport_asiSafe1__._undefined7493374936__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7531775320__WEBPACK_MODULE_REFERENCE__0_5b226a7378225d_call_directImport_asiSafe1__._undefined7532275325__WEBPACK_MODULE_REFERENCE__1_5b2264656661756c74225d_directImport_asiSafe1__._undefined`$156242(0,navigation.useRouter)undefined268358(0,navigation.usePathname)undefined393481(0,auth/* useSession */.wV)undefined512598(0,context_locale/* useLocale */.Y)undefined639723(0,react.useState)undefined775859(0,react.useState)undefined911995(0,react.useState)undefined10411125(0,react.useState)undefined11671251(0,react.useState)undefined12961380(0,react.useState)undefined14121492(0,react.useRef)undefined15231603(0,react.useRef)undefined16351715(0,react.useRef)undefined18191905(0,react.useEffect)undefined24522538(0,react.useEffect)undefined26872773(0,react.useEffect)undefined28342907(0,esm_debug.io)undefined36163702(0,react.useEffect)undefined38213917(0,api/* getUnreadCount */.$M)undefined41664252(0,react.useEffect)undefined43534449(0,api/* getMyDashboard */.H)undefined46014687(0,react.useEffect)undefined51475223(0,react_jsx_runtime.jsxs)undefined52255304react_jsx_runtime.Fragmentundefined53555429(0,react_jsx_runtime.jsx)undefined56375713(0,react_jsx_runtime.jsxs)undefined58675943(0,react_jsx_runtime.jsxs)undefined61646238(0,react_jsx_runtime.jsx)undefined62406317(link_default())undefined65066580(0,react_jsx_runtime.jsx)undefined68986974(0,react_jsx_runtime.jsxs)undefined71947270(0,react_jsx_runtime.jsxs)undefined72727351react_jsx_runtime.Fragmentundefined74747548(0,react_jsx_runtime.jsx)undefined75507627(link_default())undefined80168090(0,react_jsx_runtime.jsx)undefined80928169(link_default())undefined86038679(0,react_jsx_runtime.jsxs)undefined86818760react_jsx_runtime.Fragmentundefined88838957(0,react_jsx_runtime.jsx)undefined89599036(link_default())undefined94339507(0,react_jsx_runtime.jsx)undefined95099586(link_default())undefined1006310137(0,react_jsx_runtime.jsx)undefined1013910216(link_default())undefined1064510721(0,react_jsx_runtime.jsxs)undefined1072310802react_jsx_runtime.Fragmentundefined1092511001(0,react_jsx_runtime.jsxs)undefined1100311080(link_default())undefined1142211496(0,react_jsx_runtime.jsx)undefined1203512109(0,react_jsx_runtime.jsx)undefined1278912863(0,react_jsx_runtime.jsx)undefined1344113517(0,react_jsx_runtime.jsxs)undefined1351913596(link_default())undefined1392914003(0,react_jsx_runtime.jsx)undefined1454014614(0,react_jsx_runtime.jsx)undefined1524115315(0,react_jsx_runtime.jsx)undefined1589315969(0,react_jsx_runtime.jsxs)undefined1625816334(0,react_jsx_runtime.jsxs)undefined1675516829(0,react_jsx_runtime.jsx)undefined1702417122(0,formatName/* formatShortName */.H)undefined1735817432(0,react_jsx_runtime.jsx)undefined1789617970(0,react_jsx_runtime.jsx)undefined1848318557(0,react_jsx_runtime.jsx)undefined1910719181(0,react_jsx_runtime.jsx)undefined1982319899(0,react_jsx_runtime.jsxs)undefined2023920315(0,react_jsx_runtime.jsxs)undefined2031720396react_jsx_runtime.Fragmentundefined2056720643(0,react_jsx_runtime.jsxs)undefined2064520722(link_default())undefined2128221356(0,react_jsx_runtime.jsx)undefined2201822092(0,react_jsx_runtime.jsx)undefined2294623022(0,react_jsx_runtime.jsxs)undefined2302423101(link_default())undefined2366323737(0,react_jsx_runtime.jsx)undefined2439924473(0,react_jsx_runtime.jsx)undefined2558325659(0,react_jsx_runtime.jsxs)undefined2566125740react_jsx_runtime.Fragmentundefined2591125987(0,react_jsx_runtime.jsxs)undefined2598926066(link_default())undefined2663026704(0,react_jsx_runtime.jsx)undefined2740927483(0,react_jsx_runtime.jsx)undefined2828828364(0,react_jsx_runtime.jsxs)undefined2882928903(0,react_jsx_runtime.jsx)undefined2974629822(0,react_jsx_runtime.jsxs)undefined2982429901(link_default())undefined3045630530(0,react_jsx_runtime.jsx)undefined3123331307(0,react_jsx_runtime.jsx)undefined3206032136(0,react_jsx_runtime.jsxs)undefined3259132665(0,react_jsx_runtime.jsx)undefined3350833584(0,react_jsx_runtime.jsxs)undefined3358633663(link_default())undefined3422334297(0,react_jsx_runtime.jsx)undefined3495935033(0,react_jsx_runtime.jsx)undefined3615836234(0,react_jsx_runtime.jsxs)undefined3623636313(link_default())undefined3682936903(0,react_jsx_runtime.jsx)undefined3751737591(0,react_jsx_runtime.jsx)undefined3843338509(0,react_jsx_runtime.jsxs)undefined3851138588(link_default())undefined3910739181(0,react_jsx_runtime.jsx)undefined3979539869(0,react_jsx_runtime.jsx)undefined4073440810(0,react_jsx_runtime.jsxs)undefined4081240889(link_default())undefined4140541481(0,react_jsx_runtime.jsxs)undefined4217742251(0,react_jsx_runtime.jsx)undefined4323143305(0,react_jsx_runtime.jsx)undefined4419644272(0,react_jsx_runtime.jsxs)undefined4427444351(link_default())undefined4486944943(0,react_jsx_runtime.jsx)undefined4555745631(0,react_jsx_runtime.jsx)undefined4646546541(0,react_jsx_runtime.jsxs)undefined4654346620(link_default())undefined4714047214(0,react_jsx_runtime.jsx)undefined4782847902(0,react_jsx_runtime.jsx)undefined4879448868(0,react_jsx_runtime.jsx)undefined4912649202(0,react_jsx_runtime.jsxs)undefined4962849710(0,auth/* signOut */.CI)undefined5014250216(0,react_jsx_runtime.jsx)undefined5081650890(0,react_jsx_runtime.jsx)undefined5199752073(0,react_jsx_runtime.jsxs)undefined5207552154react_jsx_runtime.Fragmentundefined5227752351(0,react_jsx_runtime.jsx)undefined5235352430(link_default())undefined5281452888(0,react_jsx_runtime.jsx)undefined5289052967(link_default())undefined5346653540(0,react_jsx_runtime.jsx)undefined5354253637LanguageSwitcherundefined5376453840(0,react_jsx_runtime.jsxs)undefined5403754111(0,react_jsx_runtime.jsx)undefined5411354208LanguageSwitcherundefined5427054344(0,react_jsx_runtime.jsx)undefined5464254716(0,react_jsx_runtime.jsx)undefined5516255236(0,react_jsx_runtime.jsx)undefined5554655620(0,react_jsx_runtime.jsx)undefined5618856264(0,react_jsx_runtime.jsxs)undefined5647856554(0,react_jsx_runtime.jsxs)undefined5655656635react_jsx_runtime.Fragmentundefined5674256818(0,react_jsx_runtime.jsxs)undefined5682056897(link_default())undefined5727057344(0,react_jsx_runtime.jsx)undefined5780557879(0,react_jsx_runtime.jsx)undefined5847658552(0,react_jsx_runtime.jsxs)undefined5855458631(link_default())undefined5900859082(0,react_jsx_runtime.jsx)undefined5954359617(0,react_jsx_runtime.jsx)undefined6034860424(0,react_jsx_runtime.jsxs)undefined6042660505react_jsx_runtime.Fragmentundefined6061260688(0,react_jsx_runtime.jsxs)undefined6069060767(link_default())undefined6114461218(0,react_jsx_runtime.jsx)undefined6167961753(0,react_jsx_runtime.jsx)undefined6231962395(0,react_jsx_runtime.jsxs)undefined6239762474(link_default())undefined6285362927(0,react_jsx_runtime.jsx)undefined6338863462(0,react_jsx_runtime.jsx)undefined6429364369(0,react_jsx_runtime.jsxs)undefined6437164450react_jsx_runtime.Fragmentundefined6455764633(0,react_jsx_runtime.jsxs)undefined6463564712(link_default())undefined6508465158(0,react_jsx_runtime.jsx)undefined6566065734(0,react_jsx_runtime.jsx)undefined6637666450(0,react_jsx_runtime.jsx)undefined6688966965(0,react_jsx_runtime.jsxs)undefined6696767046react_jsx_runtime.Fragmentundefined6716967245(0,react_jsx_runtime.jsxs)undefined6724767324(link_default())undefined6774167815(0,react_jsx_runtime.jsx)undefined6832468398(0,react_jsx_runtime.jsx)undefined6903669112(0,react_jsx_runtime.jsxs)undefined6911469191(link_default())undefined6961069684(0,react_jsx_runtime.jsx)undefined7019370267(0,react_jsx_runtime.jsx)undefined7113771213(0,react_jsx_runtime.jsxs)undefined7121571294react_jsx_runtime.Fragmentundefined7141771493(0,react_jsx_runtime.jsxs)undefined7149571572(link_default())undefined7199372067(0,react_jsx_runtime.jsx)undefined7261972693(0,react_jsx_runtime.jsx)undefined7335473430(0,react_jsx_runtime.jsxs)undefined7379973873(0,react_jsx_runtime.jsx)undefined7451174587(0,react_jsx_runtime.jsxs)undefined7458974666(link_default())undefined7508375157(0,react_jsx_runtime.jsx)undefined7566675740(0,react_jsx_runtime.jsx)undefined7659076666(0,react_jsx_runtime.jsxs)undefined7666876745(link_default())undefined7712277196(0,react_jsx_runtime.jsx)undefined7765777731(0,react_jsx_runtime.jsx)undefined7843678512(0,react_jsx_runtime.jsxs)undefined7851478591(link_default())undefined7896779041(0,react_jsx_runtime.jsx)undefined7950279576(0,react_jsx_runtime.jsx)undefined8022580301(0,react_jsx_runtime.jsxs)undefined8030380380(link_default())undefined8075380829(0,react_jsx_runtime.jsxs)undefined8134881422(0,react_jsx_runtime.jsx)undefined8228282356(0,react_jsx_runtime.jsx)undefined8300783083(0,react_jsx_runtime.jsxs)undefined8308583162(link_default())undefined8353783611(0,react_jsx_runtime.jsx)undefined8407284146(0,react_jsx_runtime.jsx)undefined8476484840(0,react_jsx_runtime.jsxs)undefined8502985111(0,auth/* signOut */.CI)undefined8554585619(0,react_jsx_runtime.jsx)undefined8606686140(0,react_jsx_runtime.jsx)undefined8681386889(0,react_jsx_runtime.jsxs)undefined8689186970react_jsx_runtime.Fragmentundefined8707787151(0,react_jsx_runtime.jsx)undefined8715387230(link_default())undefined8762887702(0,react_jsx_runtime.jsx)undefined8770487781(link_default())undefined8835588429(0,react_jsx_runtime.jsx)undefined8855788633(0,react_jsx_runtime.jsxs)undefined8884488918(0,react_jsx_runtime.jsx)undefined8910989185(0,react_jsx_runtime.jsxs)undefined8933989413(0,react_jsx_runtime.jsx)undefined8965889732(0,react_jsx_runtime.jsx)undefined9002090096(0,react_jsx_runtime.jsxs)undefined9027490348(0,react_jsx_runtime.jsx)undefined9072990803(0,react_jsx_runtime.jsx)undefined9080590882(link_default())undefined, /***/ 64271: suimport(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/builtin/global-error.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-page.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/client-segment.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/http-access-fallback/error-boundary.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/layout-router.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/metadata/async-metadata.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/client/components/render-from-template-context.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/framework/boundary-components.js"); ; import(/* webpackMode: "eager" */ "/opt/canhelp/node_modules/next/dist/lib/metadata/generate/icon-mark.js"); 0113Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 58671, 23))undefined118222Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56542, 23))undefined227334Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 88248, 23))undefined339467Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 49743, 23))undefined472578Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 96231, 23))undefined583699Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 10959, 23))undefined704825Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 72041, 23))undefined830938Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 95094, 23))undefined9431049Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67487, 23))undefined, /***/ 67674: pp/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Header: () => (/* binding */ Header) /* harmony export */ }); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25459); /* harmony import */ var react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_server_dom_webpack_server__WEBPACK_IMPORTED_MODULE_0__); q// This file is generated by the Webpack next-flight-loader. import { registerClientReference } from "react-server-dom-webpack/server"; export const Header = registerClientReference( function() { throw new Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); }, "/opt/canhelp/apps/web/src/components/Header.tsx", "Header", );, /***/ 72088: m, /***/ 72519: ln0113Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 48365, 23))undefined118222Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 64596, 23))undefined227334Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56186, 23))undefined339467Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 67805, 23))undefined472578Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 27561, 23))undefined583699Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 47569, 23))undefined704825Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 42747, 23))undefined830938Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 56676, 23))undefined9431049Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 97225))undefined, /***/ 85105: jlfimport(/* webpackMode: "eager", webpackExports: ["Footer"] */ "/opt/canhelp/apps/web/src/components/Footer.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["Header"] */ "/opt/canhelp/apps/web/src/components/Header.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["ScrollToTopButton"] */ "/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocaleProvider"] */ "/opt/canhelp/apps/web/src/context/locale.tsx"); ; import(/* webpackMode: "eager", webpackExports: ["LocationProvider"] */ "/opt/canhelp/apps/web/src/context/location.tsx"); )0111Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 15043))undefined116227Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 58719))undefined232365Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 21046))undefined370486Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 96484))undefined491611Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 56003))undefined, /***/ 85998: giimport(/* webpackMode: "eager", webpackExports: ["__esModule","default"] */ "/opt/canhelp/node_modules/next/dist/client/app-dir/link.js"); r0136Promise.resolve(/* import() eager */).then(__webpack_require__.t.bind(__webpack_require__, 3498, 23))undefined, /***/ 91864: ddfBv, /***/ 91946: cc __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43560); /* harmony import */ var next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__); dZ import { fillMetadataSegment } from 'next/dist/lib/metadata/get-metadata-route' export default async (props) => { const imageData = {"type":"image/svg+xml","sizes":"any"} const imageUrl = fillMetadataSegment(".", await props.params, "icon.svg") return [{ ...imageData, url: imageUrl + "?71a523b2dd824001", }] }280undefined8599/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (undefined8599undefined201219(0,next_dist_lib_metadata_get_metadata_route__WEBPACK_IMPORTED_MODULE_0__.fillMetadataSegment)undefined346345.5);undefined, /***/ 94833: _a(0111Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 39348))undefined116227Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 67674))undefined232365Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 32948))undefined370486Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 20138))undefined491611Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1697))undefined, /***/ 96484: ]]_ }; ; {webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceW"use strict"; exports.id = 902; exports.ids = [902]; exports.modules = { /***/ 59902: webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource  webpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { webpack/lib/util/registerExternalSerializerwebpack-sources/CachedSource  bwebpack/lib/util/registerExternalSerializerwebpack-sources/ConcatSourcewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceX /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSourcefQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); _X[aX^ :@7_=L R E K  R X k q > D v | g_mkq06sy<B_e=Cdj &_>D5;PV CI<Bkq_  D!J!!"V"\"$$%%'$'j'p''(>(D(((W)])*_*I*O***R+X+,,B,H,,,-"---h.n./%///\0b081>111113_344:44444;5A555b6h666+717888889a9g9::P;V;;;<_<==T=Z===>>>>??@ @@@-A3AtAzABB^BdBCCdCjCCCJDHPDDD;EAE|EEOFUF true"https://api.canhelp.gr"00truebuffersourcesizemapshashW/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); {"finalSource":true}mapbufferedMap ConcatSourceRawSourceX /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ ReplaceSourceRawSourcefQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); Q 164190 trueundefined226256"https://api.canhelp.gr"undefined2612830undefined2873440undefined347353undefined437463trueundefined11121118undefined12501256undefined14111417undefined15051511undefined15571563undefined17151721undefined17961802undefined18501856undefined19711977undefined21032109undefined22042210undefined23802386undefined24522458undefined25062512undefined26292635undefined27282734undefined28292835undefined28982904undefined30543060undefined31793185undefined32553261undefined33903396undefined34463452undefined35283534undefined36073613undefined36873693undefined39473953undefined40814087undefined41444150undefined42114217undefined43124318undefined44124418undefined45174523undefined47034709undefined48494855undefined49254931undefined50855091undefined52205226undefined53535359undefined54085414undefined55105516undefined56175623undefined56945700undefined58305836undefined61296135undefined61976203undefined63336339undefined64806486undefined66656671undefined67236729undefined69726978undefined70837089undefined71907196undefined73617367undefined74267432undefined75317537undefined76957701undefined78387844undefined79577963undefined82148220undefined83228328undefined84248430undefined85168522undefined86998705undefined87908796undefined92389244undefined96239629undefined1001410020undefined1009010096undefined1023610242undefined1030210308undefined1043710443undefined1058310589undefined1076710773undefined1082510831undefined1095210958undefined1109011096undefined1126611272undefined1133011336undefined1146811474undefined1154811554undefined1171311719undefined1188011886undefined1206312069undefined1216712173undefined1238012386undefined1260012606undefined1273212738undefined1279212798undefined1321913225undefined1336413370undefined1346813474undefined1355413560undefined1362713633undefined1376913775undefined1392213928undefined1403414040undefined1412314129undefined1435614362undefined1452214528undefined1458914595undefined1468914695undefined1502215028undefined1518415190undefined1535215358undefined1552415530undefined1564015646undefined1570015706undefined1576415770undefined1606216068undefined1612016126undefined1631716323undefined1638716393undefined1661016616undefined1668516691undefined1675616762undefined1691116917undefined1699016996undefined1717317179undefined1725217258undefined1737017376undefined1748217488undefined1764717653undefined1772317729undefined1778817794undefined1799918005undefined /***/ }) buffersourcesizemapshashX/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); /***/ }) {"finalSource":true}mapbufferedMap  ConcatSourceRawSourceQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { X /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ ReplaceSourceRawSourcefQ// SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = "undefined" === 'undefined' ? process.env.INTERNAL_API_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000' : process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'; export async function request(path, init) { const url = `${BASE}/api${path}`; if ("undefined" === 'undefined') console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── export const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; export const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; export const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); export const getMyTasks = ()=>request('/tasks/my'); export const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; export const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); export const getTask = (id)=>request(`/tasks/${id}`); export const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); export const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); export const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── export const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); export const getMyOffers = ()=>request('/offers/my'); export const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); export const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); export const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); export const getUserProfile = (id)=>request(`/users/${id}/profile`); export const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; export const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); export const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); export const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── export const getChatRooms = ()=>request('/chat/rooms'); export const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); export const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); export const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); export const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── export const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); export const getNotifications = ()=>request('/notifications'); export const getUnreadCount = ()=>request('/notifications/count'); export const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); export const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); export const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); export const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── export const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── export const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); export const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── export const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── export const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── export const getFavorites = ()=>request('/favorites'); export const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); export const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); export const getSpecialistFavorites = ()=>request('/favorites/specialists'); export const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); export const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── export const getAdminCategories = ()=>request('/admin/categories'); export const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); export const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── export const getAdminStats = ()=>request('/admin/stats'); export const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; export const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); export const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); export const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); export const getAdminUser = (id)=>request(`/admin/users/${id}`); export const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); export const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); export const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; export const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); export const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); export const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); export const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); export const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); export const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; export const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; export const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; export const getAdminNotifStats = ()=>request('/admin/notification-stats'); export const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── export const getAdminLocations = ()=>request('/admin/locations'); export const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); export const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── export const getAdminPlans = ()=>request('/admin/plans'); export const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); export const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── export const getAdminSettings = ()=>request('/admin/settings'); export const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); export const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); export const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); export const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); export const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── export const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); export const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); export const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); export const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); export const getMyPortfolio = ()=>request('/portfolio/my'); export const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); export const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); export const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); export const getMySpecialistCards = ()=>request('/specialist-cards/my'); export const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); export const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); export const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); export const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); export const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; export const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); export const getPaymentHistory = ()=>request('/payments/history'); export const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); export const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; export const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); export const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); export const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); export const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; export const getMyDashboard = ()=>request('/dashboard/me'); export const getDailyUsage = ()=>request('/plans/daily-usage'); export const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── export const getMyStatuses = ()=>request('/statuses/me'); export const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); export const getAutoResponseSettings = ()=>request('/auto-response'); export const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── export const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); export const getCustomerFomoDashboard = ()=>request('/fomo/customer'); export const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── export const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); export const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── export const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); export const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); export const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); export const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── export const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); export const getSiteStats = ()=>request('/users/me/site-stats'); export const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── export const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); Q 164190 trueundefined226256"https://api.canhelp.gr"undefined2612830undefined2873440undefined347353undefined437463trueundefined11121118undefined12501256undefined14111417undefined15051511undefined15571563undefined17151721undefined17961802undefined18501856undefined19711977undefined21032109undefined22042210undefined23802386undefined24522458undefined25062512undefined26292635undefined27282734undefined28292835undefined28982904undefined30543060undefined31793185undefined32553261undefined33903396undefined34463452undefined35283534undefined36073613undefined36873693undefined39473953undefined40814087undefined41444150undefined42114217undefined43124318undefined44124418undefined45174523undefined47034709undefined48494855undefined49254931undefined50855091undefined52205226undefined53535359undefined54085414undefined55105516undefined56175623undefined56945700undefined58305836undefined61296135undefined61976203undefined63336339undefined64806486undefined66656671undefined67236729undefined69726978undefined70837089undefined71907196undefined73617367undefined74267432undefined75317537undefined76957701undefined78387844undefined79577963undefined82148220undefined83228328undefined84248430undefined85168522undefined86998705undefined87908796undefined92389244undefined96239629undefined1001410020undefined1009010096undefined1023610242undefined1030210308undefined1043710443undefined1058310589undefined1076710773undefined1082510831undefined1095210958undefined1109011096undefined1126611272undefined1133011336undefined1146811474undefined1154811554undefined1171311719undefined1188011886undefined1206312069undefined1216712173undefined1238012386undefined1260012606undefined1273212738undefined1279212798undefined1321913225undefined1336413370undefined1346813474undefined1355413560undefined1362713633undefined1376913775undefined1392213928undefined1403414040undefined1412314129undefined1435614362undefined1452214528undefined1458914595undefined1468914695undefined1502215028undefined1518415190undefined1535215358undefined1552415530undefined1564015646undefined1570015706undefined1576415770undefined1606216068undefined1612016126undefined1631716323undefined1638716393undefined1661016616undefined1668516691undefined1675616762undefined1691116917undefined1699016996undefined1717317179undefined1725217258undefined1737017376undefined1748217488undefined1764717653undefined1772317729undefined1778817794undefined1799918005undefined RawSource /***/ }) }; ;  QzX"use strict"; exports.id = 902; exports.ids = [902]; exports.modules = { /***/ 59902: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CC: () => (/* binding */ getTaskBudgetRange), /* harmony export */ F7: () => (/* binding */ getSpecialists), /* harmony export */ Vs: () => (/* binding */ getLocations), /* harmony export */ bW: () => (/* binding */ getCategories), /* harmony export */ gg: () => (/* binding */ getTask) /* harmony export */ }); /* unused harmony exports request, getTasks, searchTasks, getMyTasks, getTasksForSpecialist, getTaskCountsByCategory, createTask, updateTask, completeTask, cancelTask, getOffers, getMyOffers, createOffer, acceptOffer, declineOffer, getUserProfile, createReview, getTaskReviews, getMyReviews, getChatRooms, getOrCreateDirectRoom, getCanMessage, getMessages, sendMessage, updateNotifSettings, getNotifications, getUnreadCount, markRead, markAllRead, getTaskInvite, dismissNotification, getMyReferralInfo, getUserReviews, getUserRating, getFavorites, addFavorite, removeFavorite, getSpecialistFavorites, addSpecialistFavorite, removeSpecialistFavorite, getAdminCategories, createCategory, updateCategory, deleteCategory, getAdminStats, getAdminUsers, deactivateUser, activateUser, changeUserRole, getAdminUser, getAdminUserSpecialistCards, adminUpdateSpecialistCard, updateAdminUser, verifyAdminUserEmail, getAdminTasks, cancelTaskAdmin, deleteTaskAdmin, getAdminReports, updateReportStatus, getAdminAiLogs, getAdminActivityLogs, getAdminMailLogs, getAdminNotifLogs, getAdminNotifStats, getAdminMailStats, getAdminLocations, createLocation, updateLocation, deleteLocation, getAdminPlans, createPlan, updatePlan, deletePlan, getAdminSettings, updateAdminSettings, getAdminEmailTemplates, updateAdminEmailTemplate, translateAdminEmailTemplate, sendTestEmail, getMyAvailability, setAvailability, setAvailabilityRange, getSpecialistAvailability, getMyPortfolio, addPortfolioItem, updatePortfolioItem, deletePortfolioItem, getSpecialistPortfolio, getMySpecialistCards, createSpecialistCard, updateSpecialistCard, deleteSpecialistCard, getSpecialistCards, getSkillSuggestions, initiateTopUp, getPaymentHistory, getBalanceHistory, getAdminBalanceHistory, adminTopUpUserBalance, adminWithdrawUserBalance, previewPlanChange, getPlans, getMyDashboard, getDailyUsage, purchasePlan, getMyStatuses, toggleStatus, getAutoResponseSettings, updateAutoResponseSettings, getSpecialistFomoDashboard, getCustomerFomoDashboard, getFomoRecommendations, getAutoMatchResults, runAutoMatch, getGoogleCalendarStatus, disconnectGoogleCalendar, importFromGoogleCalendar, getGoogleCalendarConnectUrl, getPublicSiteProfile, getSiteStats, trackSiteMessage, getTaskStats */ // SSR: use INTERNAL_API_URL (http://localhost:4000) to avoid external DNS/SSL round-trip // Browser: use NEXT_PUBLIC_API_URL (https://api.canhelp.gr) const BASE = true ? process.env.INTERNAL_API_URL || "https://api.canhelp.gr" || 0 : 0; async function request(path, init) { const url = `${BASE}/api${path}`; if (true) console.log('[api] SSR fetch', url); const res = await fetch(url, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); const msg = typeof err.error === 'string' ? err.error : typeof err.message === 'string' ? err.message : res.statusText || 'Request failed'; throw new Error(msg); } return res.json(); } // ─── Tasks ──────────────────────────────────────────────────────────────── const getTasks = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks${qs}`); }; const getTaskBudgetRange = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/budget-range${qs}`); }; const searchTasks = (params)=>request(`/tasks/search?${new URLSearchParams(params)}`); const getMyTasks = ()=>request('/tasks/my'); const getTasksForSpecialist = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/tasks/for-me${qs}`); }; const getTaskCountsByCategory = ()=>request('/tasks/counts-by-category'); const getTask = (id)=>request(`/tasks/${id}`); const createTask = (data)=>request('/tasks', { method: 'POST', body: JSON.stringify(data) }); const updateTask = (id, data)=>request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const completeTask = (id)=>request(`/tasks/${id}/complete`, { method: 'PATCH' }); const cancelTask = (id)=>request(`/tasks/${id}/cancel`, { method: 'PATCH' }); // ─── Offers ──────────────────────────────────────────────────────────────── const getOffers = (taskId)=>request(`/offers?taskId=${taskId}`); const getMyOffers = ()=>request('/offers/my'); const createOffer = (data)=>request('/offers', { method: 'POST', body: JSON.stringify(data) }); const acceptOffer = (id)=>request(`/offers/${id}/accept`, { method: 'PATCH' }); const declineOffer = (id)=>request(`/offers/${id}/decline`, { method: 'PATCH' }); const getUserProfile = (id)=>request(`/users/${id}/profile`); const getSpecialists = (params)=>{ const qs = params ? '?' + new URLSearchParams(params) : ''; return request(`/users/specialists${qs}`); }; const createReview = (data)=>request('/reviews', { method: 'POST', body: JSON.stringify(data) }); const getTaskReviews = (taskId)=>request(`/reviews/task/${taskId}`); const getMyReviews = ()=>request('/reviews/my'); // ─── Chat ────────────────────────────────────────────────────────────────── const getChatRooms = ()=>request('/chat/rooms'); const getOrCreateDirectRoom = (userId)=>request(`/chat/direct/${userId}`); const getCanMessage = (userId)=>request(`/chat/can-message/${userId}`); const getMessages = (roomId)=>request(`/chat/rooms/${roomId}/messages`); const sendMessage = (roomId, body)=>request('/chat/messages', { method: 'POST', body: JSON.stringify({ roomId, body }) }); // ─── Notifications ──────────────────────────────────────────────────────── const updateNotifSettings = (data)=>request('/users/me', { method: 'PATCH', body: JSON.stringify(data) }); const getNotifications = ()=>request('/notifications'); const getUnreadCount = ()=>request('/notifications/count'); const markRead = (id)=>request(`/notifications/${id}/read`, { method: 'PATCH' }); const markAllRead = ()=>request('/notifications/read-all', { method: 'PATCH' }); const getTaskInvite = (taskId)=>request(`/notifications?type=task_invite&referenceId=${taskId}`); const dismissNotification = (id)=>request(`/notifications/${id}`, { method: 'DELETE' }); // ─── Referral ───────────────────────────────────────────────────────────── const getMyReferralInfo = ()=>request('/users/me/referral'); // ─── Reviews ────────────────────────────────────────────────────────────── const getUserReviews = (userId)=>request(`/reviews/user/${userId}`); const getUserRating = (userId)=>request(`/reviews/user/${userId}/rating`); // ─── Categories ─────────────────────────────────────────────────────────── const getCategories = ()=>request('/categories'); // ─── Locations ──────────────────────────────────────────────────────────── const getLocations = ()=>request('/locations'); // ─── Favorites ──────────────────────────────────────────────────────────── const getFavorites = ()=>request('/favorites'); const addFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'POST' }); const removeFavorite = (taskId)=>request(`/favorites/${taskId}`, { method: 'DELETE' }); const getSpecialistFavorites = ()=>request('/favorites/specialists'); const addSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'POST' }); const removeSpecialistFavorite = (specialistId)=>request(`/favorites/specialists/${specialistId}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── // ─── Admin Categories ────────────────────────────────────────────────────── const getAdminCategories = ()=>request('/admin/categories'); const createCategory = (data)=>request('/admin/categories', { method: 'POST', body: JSON.stringify(data) }); const updateCategory = (id, data)=>request(`/admin/categories/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteCategory = (id)=>request(`/admin/categories/${id}`, { method: 'DELETE' }); // ─── Admin ───────────────────────────────────────────────────────────────── const getAdminStats = ()=>request('/admin/stats'); const getAdminUsers = (page = 1, q, role)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (role) p.set('role', role); return request(`/admin/users?${p}`); }; const deactivateUser = (id)=>request(`/admin/users/${id}/deactivate`, { method: 'PATCH' }); const activateUser = (id)=>request(`/admin/users/${id}/activate`, { method: 'PATCH' }); const changeUserRole = (id, role)=>request(`/admin/users/${id}/role`, { method: 'PATCH', body: JSON.stringify({ role }) }); const getAdminUser = (id)=>request(`/admin/users/${id}`); const getAdminUserSpecialistCards = (userId)=>request(`/admin/users/${userId}/specialist-cards`); const adminUpdateSpecialistCard = (id, data)=>request(`/admin/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const updateAdminUser = (id, data)=>request(`/admin/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const verifyAdminUserEmail = (id)=>request(`/admin/users/${id}/verify-email`, { method: 'PATCH' }); const getAdminTasks = (page = 1, q, status)=>{ const p = new URLSearchParams({ page: String(page), limit: '20' }); if (q) p.set('q', q); if (status) p.set('status', status); return request(`/admin/tasks?${p}`); }; const cancelTaskAdmin = (id)=>request(`/admin/tasks/${id}/cancel`, { method: 'PATCH' }); const deleteTaskAdmin = (id)=>request(`/admin/tasks/${id}`, { method: 'DELETE' }); const getAdminReports = (page = 1)=>request(`/admin/reports?page=${page}&limit=20`); const updateReportStatus = (id, status)=>request(`/admin/reports/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }) }); const getAdminAiLogs = (page = 1)=>request(`/admin/ai-logs?page=${page}&limit=50`); const getAdminActivityLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.userId) p.set('userId', params.userId); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/activity-logs?${p}`); }; const getAdminMailLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.event) p.set('event', params.event); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/mail-logs?${p}`); }; const getAdminNotifLogs = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.type) p.set('type', params.type); if (params.dateFrom) p.set('dateFrom', params.dateFrom); if (params.dateTo) p.set('dateTo', params.dateTo); p.set('limit', '50'); return request(`/admin/notification-logs?${p}`); }; const getAdminNotifStats = ()=>request('/admin/notification-stats'); const getAdminMailStats = ()=>request('/admin/mail-stats'); // ─── Admin Locations ─────────────────────────────────────────────────────── const getAdminLocations = ()=>request('/admin/locations'); const createLocation = (data)=>request('/admin/locations', { method: 'POST', body: JSON.stringify(data) }); const updateLocation = (id, data)=>request(`/admin/locations/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteLocation = (id)=>request(`/admin/locations/${id}`, { method: 'DELETE' }); // ─── Admin Plans ─────────────────────────────────────────────────────────── const getAdminPlans = ()=>request('/admin/plans'); const createPlan = (data)=>request('/admin/plans', { method: 'POST', body: JSON.stringify(data) }); const updatePlan = (id, data)=>request(`/admin/plans/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePlan = (id)=>request(`/admin/plans/${id}`, { method: 'DELETE' }); // ─── Admin Settings ──────────────────────────────────────────────────────── const getAdminSettings = ()=>request('/admin/settings'); const updateAdminSettings = (data)=>request('/admin/settings', { method: 'PUT', body: JSON.stringify(data) }); const getAdminEmailTemplates = ()=>request('/admin/settings/templates'); const updateAdminEmailTemplate = (key, data)=>request(`/admin/settings/templates/${key}`, { method: 'PUT', body: JSON.stringify(data) }); const translateAdminEmailTemplate = (data)=>request('/admin/settings/templates/translate', { method: 'POST', body: JSON.stringify(data) }); const sendTestEmail = ()=>request('/admin/settings/test-email', { method: 'POST' }); // ─── Availability ────────────────────────────────────────────────────────── const getMyAvailability = (month)=>request(`/availability/my${month ? `?month=${month}` : ''}`); const setAvailability = (date, status, note)=>request('/availability/set', { method: 'POST', body: JSON.stringify({ date, status, note }) }); const setAvailabilityRange = (from, to, status)=>request('/availability/set-range', { method: 'POST', body: JSON.stringify({ from, to, status }) }); const getSpecialistAvailability = (userId, month)=>request(`/availability/user/${userId}${month ? `?month=${month}` : ''}`); const getMyPortfolio = ()=>request('/portfolio/my'); const addPortfolioItem = (formData)=>fetch(`${BASE}/api/portfolio`, { method: 'POST', credentials: 'include', body: formData }).then(async (res)=>{ if (!res.ok) { const err = await res.json().catch(()=>({ error: res.statusText })); throw new Error(err.error || 'Upload failed'); } return res.json(); }); const updatePortfolioItem = (id, data)=>request(`/portfolio/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deletePortfolioItem = (id)=>request(`/portfolio/${id}`, { method: 'DELETE' }); const getSpecialistPortfolio = (userId)=>request(`/portfolio/user/${userId}`); const getMySpecialistCards = ()=>request('/specialist-cards/my'); const createSpecialistCard = (data)=>request('/specialist-cards', { method: 'POST', body: JSON.stringify(data) }); const updateSpecialistCard = (id, data)=>request(`/specialist-cards/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); const deleteSpecialistCard = (id)=>request(`/specialist-cards/${id}`, { method: 'DELETE' }); const getSpecialistCards = (userId)=>request(`/specialist-cards/user/${userId}`); const getSkillSuggestions = (categorySlugs)=>{ const params = categorySlugs?.length ? '?' + categorySlugs.map((s)=>`category=${encodeURIComponent(s)}`).join('&') : ''; return request(`/skill-suggestions${params}`); }; const initiateTopUp = (amount)=>request('/payments/topup/init', { method: 'POST', body: JSON.stringify({ amount }) }); const getPaymentHistory = ()=>request('/payments/history'); const getBalanceHistory = (limit = 50)=>request(`/payments/balance-history?limit=${limit}`); const getAdminBalanceHistory = (params = {})=>{ const p = new URLSearchParams(); if (params.page) p.set('page', String(params.page)); if (params.userId) p.set('userId', params.userId); if (params.kind) p.set('kind', params.kind); p.set('limit', '50'); return request(`/admin/balance-history?${p}`); }; const adminTopUpUserBalance = (id, data)=>request(`/admin/users/${id}/balance/topup`, { method: 'POST', body: JSON.stringify(data) }); const adminWithdrawUserBalance = (id, data)=>request(`/admin/users/${id}/balance/withdraw`, { method: 'POST', body: JSON.stringify(data) }); const previewPlanChange = (planId)=>request('/payments/plan/preview', { method: 'POST', body: JSON.stringify({ planId }) }); const getPlans = (role)=>{ const qs = role ? `?role=${role}` : ''; return request(`/plans${qs}`); }; const getMyDashboard = ()=>request('/dashboard/me'); const getDailyUsage = ()=>request('/plans/daily-usage'); const purchasePlan = (planId, payFromBalance = true)=>request('/payments/plan/purchase', { method: 'POST', body: JSON.stringify({ planId, payFromBalance }) }); // ─── Statuses ────────────────────────────────────────────────────────────── const getMyStatuses = ()=>request('/statuses/me'); const toggleStatus = (statusType, active)=>request('/statuses/toggle', { method: 'POST', body: JSON.stringify({ statusType, active }) }); const getAutoResponseSettings = ()=>request('/auto-response'); const updateAutoResponseSettings = (data)=>request('/auto-response', { method: 'PUT', body: JSON.stringify(data) }); // ─── FOMO ────────────────────────────────────────────────────────────────── const getSpecialistFomoDashboard = ()=>request('/fomo/specialist'); const getCustomerFomoDashboard = ()=>request('/fomo/customer'); const getFomoRecommendations = ()=>request('/fomo/recommendations'); // ─── Auto-match ──────────────────────────────────────────────────────────── const getAutoMatchResults = (taskId)=>request(`/auto-match/${taskId}`); const runAutoMatch = (taskId)=>request(`/auto-match/${taskId}`, { method: 'POST' }); // ─── Google Calendar ─────────────────────────────────────────────────────── const getGoogleCalendarStatus = ()=>request('/google/calendar/status'); const disconnectGoogleCalendar = ()=>request('/google/calendar/disconnect', { method: 'DELETE' }); const importFromGoogleCalendar = ()=>request('/google/calendar/import', { method: 'POST' }); const getGoogleCalendarConnectUrl = ()=>`${BASE}/api/google/calendar/connect`; // ─── Personal site ───────────────────────────────────────────────────────── const getPublicSiteProfile = (slug)=>request(`/users/site/${slug}`); const getSiteStats = ()=>request('/users/me/site-stats'); const trackSiteMessage = (slug)=>request(`/users/site/${slug}/track-message`, { method: 'POST' }).catch(()=>{}); // ─── Task stats (FOMO) ───────────────────────────────────────────────────── const getTaskStats = (taskId)=>request(`/tasks/${taskId}/stats`); /***/ }) }; ; t U  ` VW"use strict"; exports.id = 902; exports.ids = [902]; exports.modules = { /***/ 59902: UQ/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { TeV2fv F +(()=>{var a={};a.id=784,a.ids=[784],a.modules={261:a=>{"use strict";a.exports=require("next/dist/shared/lib/router/utils/app-paths")},3295:a=>{"use strict";a.exports=require("next/dist/server/app-render/after-task-async-storage.external.js")},10846:a=>{"use strict";a.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},14691:(a,b)=>{"use strict";function c(a){return Array.isArray(a)?a:[a]}function d(a){if(null!=a)return c(a)}function e(a){let b;if("string"==typeof a)try{b=(a=new URL(a)).origin}catch{}return b}Object.defineProperty(b,"__esModule",{value:!0}),!function(a,b){for(var c in b)Object.defineProperty(a,c,{enumerable:!0,get:b[c]})}(b,{getOrigin:function(){return e},resolveArray:function(){return c},resolveAsArrayOrUndefined:function(){return d}})},14905:(a,b,c)=>{"use strict";c.r(b),c.d(b,{handler:()=>C,patchFetch:()=>B,routeModule:()=>x,serverHooks:()=>A,workAsyncStorage:()=>y,workUnitAsyncStorage:()=>z});var d={};c.r(d),c.d(d,{GET:()=>w});var e=c(26421),f=c(97714),g=c(85681),h=c(22369),i=c(37587),j=c(261),k=c(46537),l=c(3463),m=c(1889),n=c(85250),o=c(23620),p=c(29790),q=c(67876),r=c(57749),s=c(86439),t=c(40139),u=c(53444),v=c(23757);async function w(){let a=await {rules:{userAgent:"*",allow:"/",disallow:["/admin/","/dashboard/","/profile/","/chat/","/notifications/","/favorites/","/schedule/","/payment/"]},sitemap:"http://canhelp.gr/sitemap.xml"},b=(0,v.resolveRouteData)(a,"robots");return new u.NextResponse(b,{headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=0, must-revalidate"}})}let x=new e.AppRouteRouteModule({definition:{kind:f.RouteKind.APP_ROUTE,page:"/robots.txt/route",pathname:"/robots.txt",filename:"robots",bundlePath:"app/robots.txt/route"},distDir:".next",relativeProjectDir:"",resolvedPagePath:"next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Frobots.ts&isDynamicRouteExtension=1!?__next_metadata_route__",nextConfigOutput:"",userland:d}),{workAsyncStorage:y,workUnitAsyncStorage:z,serverHooks:A}=x;function B(){return(0,g.patchFetch)({workAsyncStorage:y,workUnitAsyncStorage:z})}async function C(a,b,c){var d;let e="/robots.txt/route";"/index"===e&&(e="/");let g=await x.prepare(a,b,{srcPage:e,multiZoneDraftMode:!1});if(!g)return b.statusCode=400,b.end("Bad Request"),null==c.waitUntil||c.waitUntil.call(c,Promise.resolve()),null;let{buildId:u,params:v,nextConfig:w,isDraftMode:y,prerenderManifest:z,routerServerContext:A,isOnDemandRevalidate:B,revalidateOnlyGenerated:C,resolvedPathname:D}=g,E=(0,j.normalizeAppPath)(e),F=!!(z.dynamicRoutes[E]||z.routes[D]);if(F&&!y){let a=!!z.routes[D],b=z.dynamicRoutes[E];if(b&&!1===b.fallback&&!a)throw new s.NoFallbackError}let G=null;!F||x.isDev||y||(G="/index"===(G=D)?"/":G);let H=!0===x.isDev||!F,I=F&&!H,J=a.method||"GET",K=(0,i.getTracer)(),L=K.getActiveScopeSpan(),M={params:v,prerenderManifest:z,renderOpts:{experimental:{cacheComponents:!!w.experimental.cacheComponents,authInterrupts:!!w.experimental.authInterrupts},supportsDynamicResponse:H,incrementalCache:(0,h.getRequestMeta)(a,"incrementalCache"),cacheLifeProfiles:null==(d=w.experimental)?void 0:d.cacheLife,isRevalidate:I,waitUntil:c.waitUntil,onClose:a=>{b.on("close",a)},onAfterTaskError:void 0,onInstrumentationRequestError:(b,c,d)=>x.onRequestError(a,b,d,A)},sharedContext:{buildId:u}},N=new k.NodeNextRequest(a),O=new k.NodeNextResponse(b),P=l.NextRequestAdapter.fromNodeNextRequest(N,(0,l.signalFromNodeResponse)(b));try{let d=async c=>x.handle(P,M).finally(()=>{if(!c)return;c.setAttributes({"http.status_code":b.statusCode,"next.rsc":!1});let d=K.getRootSpanAttributes();if(!d)return;if(d.get("next.span_type")!==m.BaseServerSpan.handleRequest)return void console.warn(`Unexpected root span type '${d.get("next.span_type")}'. Please report this Next.js issue https://github.com/vercel/next.js`);let e=d.get("next.route");if(e){let a=`${J} ${e}`;c.setAttributes({"next.route":e,"http.route":e,"next.span_name":a}),c.updateName(a)}else c.updateName(`${J} ${a.url}`)}),g=async g=>{var i,j;let k=async({previousCacheEntry:f})=>{try{if(!(0,h.getRequestMeta)(a,"minimalMode")&&B&&C&&!f)return b.statusCode=404,b.setHeader("x-nextjs-cache","REVALIDATED"),b.end("This page could not be found"),null;let e=await d(g);a.fetchMetrics=M.renderOpts.fetchMetrics;let i=M.renderOpts.pendingWaitUntil;i&&c.waitUntil&&(c.waitUntil(i),i=void 0);let j=M.renderOpts.collectedTags;if(!F)return await (0,o.I)(N,O,e,M.renderOpts.pendingWaitUntil),null;{let a=await e.blob(),b=(0,p.toNodeOutgoingHttpHeaders)(e.headers);j&&(b[r.NEXT_CACHE_TAGS_HEADER]=j),!b["content-type"]&&a.type&&(b["content-type"]=a.type);let c=void 0!==M.renderOpts.collectedRevalidate&&!(M.renderOpts.collectedRevalidate>=r.INFINITE_CACHE)&&M.renderOpts.collectedRevalidate,d=void 0===M.renderOpts.collectedExpire||M.renderOpts.collectedExpire>=r.INFINITE_CACHE?void 0:M.renderOpts.collectedExpire;return{value:{kind:t.CachedRouteKind.APP_ROUTE,status:e.status,body:Buffer.from(await a.arrayBuffer()),headers:b},cacheControl:{revalidate:c,expire:d}}}}catch(b){throw(null==f?void 0:f.isStale)&&await x.onRequestError(a,b,{routerKind:"App Router",routePath:e,routeType:"route",revalidateReason:(0,n.c)({isRevalidate:I,isOnDemandRevalidate:B})},A),b}},l=await x.handleResponse({req:a,nextConfig:w,cacheKey:G,routeKind:f.RouteKind.APP_ROUTE,isFallback:!1,prerenderManifest:z,isRoutePPREnabled:!1,isOnDemandRevalidate:B,revalidateOnlyGenerated:C,responseGenerator:k,waitUntil:c.waitUntil});if(!F)return null;if((null==l||null==(i=l.value)?void 0:i.kind)!==t.CachedRouteKind.APP_ROUTE)throw Object.defineProperty(Error(`Invariant: app-route received invalid cache entry ${null==l||null==(j=l.value)?void 0:j.kind}`),"__NEXT_ERROR_CODE",{value:"E701",enumerable:!1,configurable:!0});(0,h.getRequestMeta)(a,"minimalMode")||b.setHeader("x-nextjs-cache",B?"REVALIDATED":l.isMiss?"MISS":l.isStale?"STALE":"HIT"),y&&b.setHeader("Cache-Control","private, no-cache, no-store, max-age=0, must-revalidate");let m=(0,p.fromNodeOutgoingHttpHeaders)(l.value.headers);return(0,h.getRequestMeta)(a,"minimalMode")&&F||m.delete(r.NEXT_CACHE_TAGS_HEADER),!l.cacheControl||b.getHeader("Cache-Control")||m.get("Cache-Control")||m.set("Cache-Control",(0,q.getCacheControlHeader)(l.cacheControl)),await (0,o.I)(N,O,new Response(l.value.body,{headers:m,status:l.value.status||200})),null};L?await g(L):await K.withPropagatedContext(a.headers,()=>K.trace(m.BaseServerSpan.handleRequest,{spanName:`${J} ${a.url}`,kind:i.SpanKind.SERVER,attributes:{"http.method":J,"http.target":a.url}},g))}catch(b){if(b instanceof s.NoFallbackError||await x.onRequestError(a,b,{routerKind:"App Router",routePath:E,routeType:"route",revalidateReason:(0,n.c)({isRevalidate:I,isOnDemandRevalidate:B})}),F)throw b;return await (0,o.I)(N,O,new Response(null,{status:500})),null}}},19121:a=>{"use strict";a.exports=require("next/dist/server/app-render/action-async-storage.external.js")},23757:(a,b,c)=>{"use strict";Object.defineProperty(b,"__esModule",{value:!0}),!function(a,b){for(var c in b)Object.defineProperty(a,c,{enumerable:!0,get:b[c]})}(b,{resolveManifest:function(){return g},resolveRobots:function(){return e},resolveRouteData:function(){return h},resolveSitemap:function(){return f}});let d=c(14691);function e(a){let b="";for(let c of Array.isArray(a.rules)?a.rules:[a.rules]){for(let a of(0,d.resolveArray)(c.userAgent||["*"]))b+=`User-Agent: ${a} `;if(c.allow)for(let a of(0,d.resolveArray)(c.allow))b+=`Allow: ${a} `;if(c.disallow)for(let a of(0,d.resolveArray)(c.disallow))b+=`Disallow: ${a} `;c.crawlDelay&&(b+=`Crawl-delay: ${c.crawlDelay} `),b+="\n"}return a.host&&(b+=`Host: ${a.host} `),a.sitemap&&(0,d.resolveArray)(a.sitemap).forEach(a=>{b+=`Sitemap: ${a} `}),b}function f(a){let b=a.some(a=>Object.keys(a.alternates??{}).length>0),c=a.some(a=>{var b;return!!(null==(b=a.images)?void 0:b.length)}),d=a.some(a=>{var b;return!!(null==(b=a.videos)?void 0:b.length)}),e="";for(let i of(e+='\n',e+='${i.url} `;let a=null==(f=i.alternates)?void 0:f.languages;if(a&&Object.keys(a).length)for(let b in a)e+=` `;if(null==(g=i.images)?void 0:g.length)for(let a of i.images)e+=` ${a} `;if(null==(h=i.videos)?void 0:h.length)for(let a of i.videos)e+=["",`${a.title}`,`${a.thumbnail_loc}`,`${a.description}`,a.content_loc&&`${a.content_loc}`,a.player_loc&&`${a.player_loc}`,a.duration&&`${a.duration}`,a.view_count&&`${a.view_count}`,a.tag&&`${a.tag}`,a.rating&&`${a.rating}`,a.expiration_date&&`${a.expiration_date}`,a.publication_date&&`${a.publication_date}`,a.family_friendly&&`${a.family_friendly}`,a.requires_subscription&&`${a.requires_subscription}`,a.live&&`${a.live}`,a.restriction&&`${a.restriction.content}`,a.platform&&`${a.platform.content}`,a.uploader&&`${a.uploader.content}`,` `].filter(Boolean).join("\n");if(i.lastModified){let a=i.lastModified instanceof Date?i.lastModified.toISOString():i.lastModified;e+=`${a} `}i.changeFrequency&&(e+=`${i.changeFrequency} `),"number"==typeof i.priority&&(e+=`${i.priority} `),e+="\n"}return e+"\n"}function g(a){return JSON.stringify(a)}function h(a,b){return"robots"===b?e(a):"sitemap"===b?f(a):"manifest"===b?g(a):""}},29294:a=>{"use strict";a.exports=require("next/dist/server/app-render/work-async-storage.external.js")},44870:a=>{"use strict";a.exports=require("next/dist/compiled/next-server/app-route.runtime.prod.js")},63033:a=>{"use strict";a.exports=require("next/dist/server/app-render/work-unit-async-storage.external.js")},80408:()=>{},86439:a=>{"use strict";a.exports=require("next/dist/shared/lib/no-fallback-error.external")},87032:()=>{}};var b=require("../../webpack-runtime.js");b.C(a);var c=b.X(0,[901,825],()=>b(b.s=14905));module.exports=c})();  Cy0(()=>{var a={};a.id=475,a.ids=[475],a.modules={261:a=>{"use strict";a.exports=require("next/dist/shared/lib/router/utils/app-paths")},3295:a=>{"use strict";a.exports=require("next/dist/server/app-render/after-task-async-storage.external.js")},10846:a=>{"use strict";a.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},14691:(a,b)=>{"use strict";function c(a){return Array.isArray(a)?a:[a]}function d(a){if(null!=a)return c(a)}function e(a){let b;if("string"==typeof a)try{b=(a=new URL(a)).origin}catch{}return b}Object.defineProperty(b,"__esModule",{value:!0}),!function(a,b){for(var c in b)Object.defineProperty(a,c,{enumerable:!0,get:b[c]})}(b,{getOrigin:function(){return e},resolveArray:function(){return c},resolveAsArrayOrUndefined:function(){return d}})},19121:a=>{"use strict";a.exports=require("next/dist/server/app-render/action-async-storage.external.js")},23757:(a,b,c)=>{"use strict";Object.defineProperty(b,"__esModule",{value:!0}),!function(a,b){for(var c in b)Object.defineProperty(a,c,{enumerable:!0,get:b[c]})}(b,{resolveManifest:function(){return g},resolveRobots:function(){return e},resolveRouteData:function(){return h},resolveSitemap:function(){return f}});let d=c(14691);function e(a){let b="";for(let c of Array.isArray(a.rules)?a.rules:[a.rules]){for(let a of(0,d.resolveArray)(c.userAgent||["*"]))b+=`User-Agent: ${a} `;if(c.allow)for(let a of(0,d.resolveArray)(c.allow))b+=`Allow: ${a} `;if(c.disallow)for(let a of(0,d.resolveArray)(c.disallow))b+=`Disallow: ${a} `;c.crawlDelay&&(b+=`Crawl-delay: ${c.crawlDelay} `),b+="\n"}return a.host&&(b+=`Host: ${a.host} `),a.sitemap&&(0,d.resolveArray)(a.sitemap).forEach(a=>{b+=`Sitemap: ${a} `}),b}function f(a){let b=a.some(a=>Object.keys(a.alternates??{}).length>0),c=a.some(a=>{var b;return!!(null==(b=a.images)?void 0:b.length)}),d=a.some(a=>{var b;return!!(null==(b=a.videos)?void 0:b.length)}),e="";for(let i of(e+='\n',e+='${i.url} `;let a=null==(f=i.alternates)?void 0:f.languages;if(a&&Object.keys(a).length)for(let b in a)e+=` `;if(null==(g=i.images)?void 0:g.length)for(let a of i.images)e+=` ${a} `;if(null==(h=i.videos)?void 0:h.length)for(let a of i.videos)e+=["",`${a.title}`,`${a.thumbnail_loc}`,`${a.description}`,a.content_loc&&`${a.content_loc}`,a.player_loc&&`${a.player_loc}`,a.duration&&`${a.duration}`,a.view_count&&`${a.view_count}`,a.tag&&`${a.tag}`,a.rating&&`${a.rating}`,a.expiration_date&&`${a.expiration_date}`,a.publication_date&&`${a.publication_date}`,a.family_friendly&&`${a.family_friendly}`,a.requires_subscription&&`${a.requires_subscription}`,a.live&&`${a.live}`,a.restriction&&`${a.restriction.content}`,a.platform&&`${a.platform.content}`,a.uploader&&`${a.uploader.content}`,` `].filter(Boolean).join("\n");if(i.lastModified){let a=i.lastModified instanceof Date?i.lastModified.toISOString():i.lastModified;e+=`${a} `}i.changeFrequency&&(e+=`${i.changeFrequency} `),"number"==typeof i.priority&&(e+=`${i.priority} `),e+="\n"}return e+"\n"}function g(a){return JSON.stringify(a)}function h(a,b){return"robots"===b?e(a):"sitemap"===b?f(a):"manifest"===b?g(a):""}},29294:a=>{"use strict";a.exports=require("next/dist/server/app-render/work-async-storage.external.js")},44870:a=>{"use strict";a.exports=require("next/dist/compiled/next-server/app-route.runtime.prod.js")},63033:a=>{"use strict";a.exports=require("next/dist/server/app-render/work-unit-async-storage.external.js")},80408:()=>{},83019:(a,b,c)=>{"use strict";c.r(b),c.d(b,{handler:()=>K,patchFetch:()=>J,routeModule:()=>F,serverHooks:()=>I,workAsyncStorage:()=>G,workUnitAsyncStorage:()=>H});var d={};c.r(d),c.d(d,{default:()=>B});var e={};c.r(e),c.d(e,{GET:()=>E});var f=c(26421),g=c(97714),h=c(85681),i=c(22369),j=c(37587),k=c(261),l=c(46537),m=c(3463),n=c(1889),o=c(85250),p=c(23620),q=c(29790),r=c(67876),s=c(57749),t=c(86439),u=c(40139),v=c(53444);let w="http://canhelp.gr",x="https://api.canhelp.gr",y=[{url:`${w}/`,changeFrequency:"daily",priority:1},{url:`${w}/tasks`,changeFrequency:"hourly",priority:.9},{url:`${w}/specialists`,changeFrequency:"hourly",priority:.9},{url:`${w}/pricing`,changeFrequency:"weekly",priority:.6},{url:`${w}/become-specialist`,changeFrequency:"monthly",priority:.7}];async function z(){let a=[],b=1;try{for(;;){let c=await fetch(`${x}/api/tasks?page=${b}&limit=100&status=open`,{next:{revalidate:3600}});if(!c.ok)break;let d=await c.json(),e=d.data??[];for(let{task:b}of e)a.push({url:`${w}/tasks/${b.id}`,lastModified:b.updatedAt?new Date(b.updatedAt):void 0,changeFrequency:"daily",priority:.8});if(a.length>=d.total||e.length<100)break;b++}}catch{}return a}async function A(){let a=[],b=1;try{for(;;){let c=await fetch(`${x}/api/users/specialists?page=${b}&limit=100`,{next:{revalidate:3600}});if(!c.ok)break;let d=await c.json(),e=d.data??[];for(let b of e)a.push({url:`${w}/users/${b.id}`,lastModified:b.updatedAt?new Date(b.updatedAt):void 0,changeFrequency:"weekly",priority:.75});if(a.length>=d.total||e.length<100)break;b++}}catch{}return a}async function B(){let[a,b]=await Promise.all([z(),A()]);return[...y,...a,...b]}var C=c(23757);let D={...d}.default;if("function"!=typeof D)throw Error('Default export is missing in "/opt/canhelp/apps/web/src/app/sitemap.ts"');async function E(a,b){let{__metadata_id__:c,...d}=await b.params||{},e=!!c&&c.endsWith(".xml");if(c&&!e)return new v.NextResponse("Not Found",{status:404});let f=c&&e?c.slice(0,-4):void 0,g=await D({id:f}),h=(0,C.resolveRouteData)(g,"sitemap");return new v.NextResponse(h,{headers:{"Content-Type":"application/xml","Cache-Control":"public, max-age=0, must-revalidate"}})}let F=new f.AppRouteRouteModule({definition:{kind:g.RouteKind.APP_ROUTE,page:"/sitemap.xml/route",pathname:"/sitemap.xml",filename:"sitemap",bundlePath:"app/sitemap.xml/route"},distDir:".next",relativeProjectDir:"",resolvedPagePath:"next-metadata-route-loader?filePath=%2Fopt%2Fcanhelp%2Fapps%2Fweb%2Fsrc%2Fapp%2Fsitemap.ts&isDynamicRouteExtension=1!?__next_metadata_route__",nextConfigOutput:"",userland:e}),{workAsyncStorage:G,workUnitAsyncStorage:H,serverHooks:I}=F;function J(){return(0,h.patchFetch)({workAsyncStorage:G,workUnitAsyncStorage:H})}async function K(a,b,c){var d;let e="/sitemap.xml/route";"/index"===e&&(e="/");let f=await F.prepare(a,b,{srcPage:e,multiZoneDraftMode:!1});if(!f)return b.statusCode=400,b.end("Bad Request"),null==c.waitUntil||c.waitUntil.call(c,Promise.resolve()),null;let{buildId:h,params:v,nextConfig:w,isDraftMode:x,prerenderManifest:y,routerServerContext:z,isOnDemandRevalidate:A,revalidateOnlyGenerated:B,resolvedPathname:C}=f,D=(0,k.normalizeAppPath)(e),E=!!(y.dynamicRoutes[D]||y.routes[C]);if(E&&!x){let a=!!y.routes[C],b=y.dynamicRoutes[D];if(b&&!1===b.fallback&&!a)throw new t.NoFallbackError}let G=null;!E||F.isDev||x||(G="/index"===(G=C)?"/":G);let H=!0===F.isDev||!E,I=E&&!H,J=a.method||"GET",K=(0,j.getTracer)(),L=K.getActiveScopeSpan(),M={params:v,prerenderManifest:y,renderOpts:{experimental:{cacheComponents:!!w.experimental.cacheComponents,authInterrupts:!!w.experimental.authInterrupts},supportsDynamicResponse:H,incrementalCache:(0,i.getRequestMeta)(a,"incrementalCache"),cacheLifeProfiles:null==(d=w.experimental)?void 0:d.cacheLife,isRevalidate:I,waitUntil:c.waitUntil,onClose:a=>{b.on("close",a)},onAfterTaskError:void 0,onInstrumentationRequestError:(b,c,d)=>F.onRequestError(a,b,d,z)},sharedContext:{buildId:h}},N=new l.NodeNextRequest(a),O=new l.NodeNextResponse(b),P=m.NextRequestAdapter.fromNodeNextRequest(N,(0,m.signalFromNodeResponse)(b));try{let d=async c=>F.handle(P,M).finally(()=>{if(!c)return;c.setAttributes({"http.status_code":b.statusCode,"next.rsc":!1});let d=K.getRootSpanAttributes();if(!d)return;if(d.get("next.span_type")!==n.BaseServerSpan.handleRequest)return void console.warn(`Unexpected root span type '${d.get("next.span_type")}'. Please report this Next.js issue https://github.com/vercel/next.js`);let e=d.get("next.route");if(e){let a=`${J} ${e}`;c.setAttributes({"next.route":e,"http.route":e,"next.span_name":a}),c.updateName(a)}else c.updateName(`${J} ${a.url}`)}),f=async f=>{var h,j;let k=async({previousCacheEntry:g})=>{try{if(!(0,i.getRequestMeta)(a,"minimalMode")&&A&&B&&!g)return b.statusCode=404,b.setHeader("x-nextjs-cache","REVALIDATED"),b.end("This page could not be found"),null;let e=await d(f);a.fetchMetrics=M.renderOpts.fetchMetrics;let h=M.renderOpts.pendingWaitUntil;h&&c.waitUntil&&(c.waitUntil(h),h=void 0);let j=M.renderOpts.collectedTags;if(!E)return await (0,p.I)(N,O,e,M.renderOpts.pendingWaitUntil),null;{let a=await e.blob(),b=(0,q.toNodeOutgoingHttpHeaders)(e.headers);j&&(b[s.NEXT_CACHE_TAGS_HEADER]=j),!b["content-type"]&&a.type&&(b["content-type"]=a.type);let c=void 0!==M.renderOpts.collectedRevalidate&&!(M.renderOpts.collectedRevalidate>=s.INFINITE_CACHE)&&M.renderOpts.collectedRevalidate,d=void 0===M.renderOpts.collectedExpire||M.renderOpts.collectedExpire>=s.INFINITE_CACHE?void 0:M.renderOpts.collectedExpire;return{value:{kind:u.CachedRouteKind.APP_ROUTE,status:e.status,body:Buffer.from(await a.arrayBuffer()),headers:b},cacheControl:{revalidate:c,expire:d}}}}catch(b){throw(null==g?void 0:g.isStale)&&await F.onRequestError(a,b,{routerKind:"App Router",routePath:e,routeType:"route",revalidateReason:(0,o.c)({isRevalidate:I,isOnDemandRevalidate:A})},z),b}},l=await F.handleResponse({req:a,nextConfig:w,cacheKey:G,routeKind:g.RouteKind.APP_ROUTE,isFallback:!1,prerenderManifest:y,isRoutePPREnabled:!1,isOnDemandRevalidate:A,revalidateOnlyGenerated:B,responseGenerator:k,waitUntil:c.waitUntil});if(!E)return null;if((null==l||null==(h=l.value)?void 0:h.kind)!==u.CachedRouteKind.APP_ROUTE)throw Object.defineProperty(Error(`Invariant: app-route received invalid cache entry ${null==l||null==(j=l.value)?void 0:j.kind}`),"__NEXT_ERROR_CODE",{value:"E701",enumerable:!1,configurable:!0});(0,i.getRequestMeta)(a,"minimalMode")||b.setHeader("x-nextjs-cache",A?"REVALIDATED":l.isMiss?"MISS":l.isStale?"STALE":"HIT"),x&&b.setHeader("Cache-Control","private, no-cache, no-store, max-age=0, must-revalidate");let m=(0,q.fromNodeOutgoingHttpHeaders)(l.value.headers);return(0,i.getRequestMeta)(a,"minimalMode")&&E||m.delete(s.NEXT_CACHE_TAGS_HEADER),!l.cacheControl||b.getHeader("Cache-Control")||m.get("Cache-Control")||m.set("Cache-Control",(0,r.getCacheControlHeader)(l.cacheControl)),await (0,p.I)(N,O,new Response(l.value.body,{headers:m,status:l.value.status||200})),null};L?await f(L):await K.withPropagatedContext(a.headers,()=>K.trace(n.BaseServerSpan.handleRequest,{spanName:`${J} ${a.url}`,kind:j.SpanKind.SERVER,attributes:{"http.method":J,"http.target":a.url}},f))}catch(b){if(b instanceof t.NoFallbackError||await F.onRequestError(a,b,{routerKind:"App Router",routePath:D,routeType:"route",revalidateReason:(0,o.c)({isRevalidate:I,isOnDemandRevalidate:A})}),E)throw b;return await (0,p.I)(N,O,new Response(null,{status:500})),null}}},86439:a=>{"use strict";a.exports=require("next/dist/shared/lib/no-fallback-error.external")},87032:()=>{}};var b=require("../../webpack-runtime.js");b.C(a);var c=b.X(0,[901,825],()=>b(b.s=83019));module.exports=c})();  @@exports.id=892,exports.ids=[892],exports.modules={1241:()=>{},1697:(a,b,c)=>{"use strict";c.d(b,{LocationProvider:()=>e});var d=c(25459);let e=(0,d.registerClientReference)(function(){throw Error("Attempted to call LocationProvider() from the server but LocationProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/opt/canhelp/apps/web/src/context/location.tsx","LocationProvider");(0,d.registerClientReference)(function(){throw Error("Attempted to call useLocation() from the server but useLocation is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/opt/canhelp/apps/web/src/context/location.tsx","useLocation")},12998:(a,b,c)=>{"use strict";c.d(b,{$:()=>f,YZ:()=>d});let d=[{code:"el",label:"Ελληνικά",flag:"\uD83C\uDDEC\uD83C\uDDF7"},{code:"en",label:"English",flag:"\uD83C\uDDEC\uD83C\uDDE7"},{code:"ru",label:"Русский",flag:"\uD83C\uDDF7\uD83C\uDDFA"}],e={el:{"footer.slogan":"Η εργασία σου — η φροντίδα μας! Λύνουμε κάθε ζήτημα γρήγορα και εύκολα.","footer.links":"Σύνδεσμοι","footer.socials":"Στα κοινωνικά δίκτυα","nav.home":"Αρχική","nav.tasks":"Εργασίες","nav.post":"+ Δημοσίευση","nav.dashboard":"Πίνακας","nav.chat":"Μηνύματα","nav.notifications":"Ειδοποιήσεις","nav.profile":"Προφίλ","nav.admin":"Διαχείριση","nav.specialists":"Ειδικοί","nav.new_task":"Νέα εργασία","nav.login":"Σύνδεση","nav.register":"Εγγραφή","nav.logout":"Έξοδος","hero.title":"Βρες ειδικό για κάθε δουλειά","hero.subtitle":"Δημοσίευσε εργασία, λάβε προσφορές και επίλεξε τον καλύτερο επαγγελματία","hero.cta.post":"Δημοσίευσε εργασία","hero.cta.browse":"Γίνε ειδικός","hero.search.placeholder":"Τι χρειάζεσαι; π.χ. ηλεκτρολόγος, καθαρισμός...","stats.specialists":"ειδικοί","stats.tasks":"εργασίες","stats.categories":"κατηγορίες","stats.free":"δωρεάν εγγραφή","section.categories":"Δημιούργησε εργασία σε οποιαδήποτε κατηγορία","section.how":"Πώς λειτουργεί","section.recent":"Πρόσφατες εργασίες","section.all":"Δες όλες →","section.more":"ακόμα","section.cities":"Πόλεις & Περιοχές","section.community":"Ένα κοινοτικό έργο για όλους","community.subtitle":"Το CanHelp δεν είναι απλώς μια αγορά — είναι μια κοινότητα αμοιβαίας βοήθειας. Οποιοσδήποτε έχει γνώση ή δεξιότητα μπορεί να βρει έναν πελάτη. Οποιοσδήποτε έχει ένα πρόβλημα μπορεί να βρει έναν ειδικό.","community.point1.title":"Είσαι ειδικός σε κάτι;","community.point1.desc":"Επισκευές, μαθήματα, σχεδιασμός, μεταφράσεις, φροντίδα — κάθε δεξιότητα αξίζει. Δημιούργησε προφίλ και βρες πελάτες κοντά σου.","community.point2.title":"Χρειάζεσαι βοήθεια;","community.point2.desc":"Δημοσίευσε εργασία σε λιγότερο από ένα λεπτό και λάβε προσφορές από επαληθευμένους ειδικούς στην πόλη σου.","community.point3.title":"Βοήθησε το έργο να αναπτυχθεί","community.point3.desc":"Το CanHelp αναπτύσσεται χάρη στις κοινότητες. Μοιράσου το σύνδεσμο με φίλους και γνωστούς — μαζί χτίζουμε κάτι χρήσιμο για όλους.","community.share":"Μοιράσου με φίλους","community.share.copied":"Σύνδεσμος αντιγράφηκε!","section.referral":"Πρόγραμμα παραπομπών","referral.home.subtitle":"Μοιράσου τον σύνδεσμό σου — κάθε νέος χρήστης που εγγράφεται μέσα από αυτόν σου αποφέρει ανταμοιβή.","referral.home.step1.title":"Εγγραφείσε και λάβε σύνδεσμο","referral.home.step1.desc":"Δημιούργησε λογαριασμό και βρες τον μοναδικό σου σύνδεσμο παραπομπής στο προφίλ σου.","referral.home.step2.title":"Μοιράσου με φίλους","referral.home.step2.desc":"Στείλε τον σύνδεσμο σε φίλους, γνωστούς ή δημοσίευσέ τον στα social media.","referral.home.step3.title":"Κέρδισε ανταμοιβές","referral.home.step3.desc":"Μόλις ο φίλος σου επαληθεύσει το email του, λαμβάνεις αυτόματα την ανταμοιβή σου.","referral.home.cta":"Πάρε τον σύνδεσμό σου","referral.home.badge":"Πρόγραμμα παραπομπών","section.faq":"Συχνές Ερωτήσεις","faq.q1":"Πώς λειτουργεί το CanHelp;","faq.a1":"Δημοσίευσε μια εργασία, λάβε προσφορές από ειδικούς, επέλεξε τον καλύτερο και ξεκίνα τη συνεργασία. Είναι γρήγορο, απλό και δωρεάν για πελάτες.","faq.q2":"Πόσο κοστίζει η χρήση της πλατφόρμας;","faq.a2":"Η εγγραφή και η δημοσίευση εργασιών είναι εντελώς δωρεάν για πελάτες. Οι ειδικοί έχουν στη διάθεσή τους δωρεάν πλάνο καθώς και premium επιλογές.","faq.q3":"Πώς μπορώ να γίνω ειδικός;","faq.a3":"Κάνε εγγραφή, πήγαινε στο \xabΓίνε Ειδικός\xbb, συμπλήρωσε το προφίλ σου με δεξιότητες και κατηγορίες και αρχίνισε να λαμβάνεις εργασίες.","faq.q4":"Πώς επιλέγω τον κατάλληλο ειδικό;","faq.a4":"Δες τις αξιολογήσεις, την εμπειρία, τις δεξιότητες και το χαρτοφυλάκιο κάθε ειδικού. Επικοινώνησε μαζί του μέσω chat και συζήτα τις λεπτομέρειες πριν αποφασίσεις.","faq.q5":"Τι γίνεται αν δεν είμαι ικανοποιημένος;","faq.a5":"Μπορείς να αφήσεις αξιολόγηση για τον ειδικό και να τον βαθμολογήσεις από 1 έως 5 αστέρια. Οι αξιολογήσεις βοηθούν άλλους χρήστες να επιλέξουν έμπιστους επαγγελματίες.","faq.q6":"Μπορώ να επικοινωνήσω με τον ειδικό πριν την αποδοχή;","faq.a6":"Ναι. Μόλις λάβεις μια προσφορά, μπορείς να ανοίξεις chat με τον ειδικό, να κάνεις ερωτήσεις και να συντονίσεις τις λεπτομέρειες πριν αποφασίσεις.","faq.q7":"Πόσος χρόνος χρειάζεται για να λάβω προσφορές;","faq.a7":"Συνήθως μέσα σε λίγες ώρες. Οι ειδικοί λαμβάνουν ειδοποίηση για νέες εργασίες και μπορούν να απαντήσουν γρήγορα.","faq.q8":"Μπορώ να δημοσιεύσω εργασία σε οποιαδήποτε πόλη της Ελλάδας;","faq.a8":"Ναι! Το CanHelp καλύπτει όλη την Ελλάδα. Μπορείς να βρεις ειδικούς στην Αθήνα, στη Θεσσαλονίκη, στην Πάτρα και αλλού.","faq.q9":"Τι είδη εργασιών μπορώ να βρω στο CanHelp;","faq.a9":"Επισκευές, καθαρισμό, ηλεκτρολόγους, μαθήματα, σχεδιασμό, IT, μετακομίσεις, ομορφιά και πολλά άλλα. Οι κατηγορίες αυξάνονται συνεχώς.","faq.q10":"Υπάρχει εφαρμογή για κινητό;","faq.a10":"Ναι! Το CanHelp διατίθεται για Android και iOS. Κατέβασε την εφαρμογή και διαχειρίσου τα πάντα από το τηλέφωνό σου.","how.step1.title":"Δημοσίευσε εργασία","how.step1.desc":"Περίγραψε τι χρειάζεσαι και ορίζε τον προϋπολογισμό σου","how.step2.title":"Λάβε προσφορές","how.step2.desc":"Ειδικοί θα σου στείλουν προσφορές με τιμή και χρόνο","how.step3.title":"Επίλεξε & ξεκίνα","how.step3.desc":"Επέλεξε τον καλύτερο επαγγελματία και ξεκίνα τη συνεργασία","tasks.title":"εργασίες","tasks.filters":"Φίλτρα","tasks.search":"Αναζήτηση","tasks.search.placeholder":"Τίτλος ή λέξη κλειδί...","tasks.search.btn":"Αναζήτηση","tasks.publish":"Δημοσίευση","tasks.category.all":"Όλες","tasks.category.all_in":"Όλα στην","tasks.category.label":"Κατηγορία","tasks.location.label":"Πόλη","tasks.location.placeholder":"π.χ. Αθήνα","tasks.empty":"Δεν βρέθηκαν εργασίες","tasks.empty.cta":"Δημοσίευσε την πρώτη","task.status.open":"Ανοιχτή","task.status.in_progress":"Σε εξέλιξη","task.status.completed":"Ολοκληρωμένη","task.status.cancelled":"Ακυρωμένη","task.status.draft":"Πρόχειρο","task.budget":"Προϋπολογισμός","task.location":"Τοποθεσία","task.deadline":"Ημερομηνία έναρξης","task.created_at":"Δημιουργήθηκε","task.customer":"Πελάτης","task.offer.btn":"Υποβολή προσφοράς","task.invite.banner_title":"Σας προσκαλούν σε αυτήν την εργασία","task.invite.banner_hint":"Ο πελάτης σας πρόσκαλεσε προσωπικά","task.invite.accept":"Αποστολή προσφοράς","task.invite.decline":"Άρνηση","offer.accept":"Αποδοχή","offer.decline":"Απόρριψη","task.complete":"Ολοκλήρωση εργασίας","task.complete.confirm":"Να ολοκληρωθεί η εργασία;","task.edit":"Επεξεργασία","task.status_label":"Κατάσταση","task.yours":"Η εργασία σου","task.offer.yours":"Η προσφορά σου","review.leave":"Άφησε αξιολόγηση","review.rating":"Βαθμολογία","review.comment":"Σχόλιο","review.comment.placeholder":"Πες μας για την εμπειρία σου...","review.submit":"Υποβολή αξιολόγησης","review.submitting":"Αποστολή...","review.done":"Η αξιολόγηση καταχωρήθηκε!","profile.reviews":"Αξιολογήσεις","profile.no_reviews":"Δεν υπάρχουν αξιολογήσεις ακόμα","profile.rating":"Βαθμολογία","profile.skills.label":"Δεξιότητες","profile.member_since":"Μέλος από","task.offers":"Προσφορές","task.offers.none":"Δεν υπάρχουν ακόμα προσφορές","create.title":"Δημοσίευση εργασίας","create.field.title":"Τίτλος","create.field.description":"Περιγραφή","create.field.category":"Κατηγορία","create.field.category.select":"Επιλέξτε...","create.field.location":"Τοποθεσία","create.field.location.any":"Οπουδήποτε","create.field.location.all":"Ολόκληρη η πόλη","create.field.budget":"Προϋπολογισμός (€)","create.field.deadline":"Ημερομηνία έναρξης","create.field.budget_negotiable":"Η τιμή είναι διαπραγματεύσιμη","create.field.time_slot":"Χρόνος εκτέλεσης","create.field.time_slot.any":"Οποιαδήποτε","create.field.time_slot.morning":"Πρωινό (08:00–13:00)","create.field.time_slot.afternoon":"Μεσημέρι (13:00–18:00)","create.field.time_slot.evening":"Βράδυ (18:00–22:00)","create.field.time_slot.weekend":"Σαββατοκύριακο","create.field.address":"Διεύθυνση (προαιρετικά)","create.field.address.district":"Συνοικία","create.field.address.street":"Οδός","create.field.address.house":"Αριθμός","create.field.confidential":"Εμπιστευτική σημείωση","create.field.confidential.placeholder":"Λεπτομέρειες που θα δει μόνο ο αναδοχόμενος...","create.field.confidential.hint":"Δεν εμφανίζεται δημόσια","create.field.photos":"Φωτογραφίες","create.field.photos.add":"Προσθήκη φωτογραφίας","create.field.photos.uploading":"Ανέβασμα...","task.budget_negotiable":"Τιμή διαπραγματεύσιμη","task.time_slot":"Χρόνος","task.confidential":"Εμπιστευτική σημείωση","create.field.title.placeholder":"π.χ. Καθαρισμός διαμερίσματος 80τμ","create.field.description.placeholder":"Περίγραψε λεπτομερώς τι χρειάζεσαι...","create.field.location.placeholder":"π.χ. Αθήνα, Κολωνάκι","create.field.budget.placeholder":"π.χ. 100","create.submit":"Δημοσίευση εργασίας","create.submitting":"Δημοσίευση...","login.title":"Καλωσόρισες","login.subtitle":"Σύνδεση στο CanHelp","login.email":"Email","login.password":"Κωδικός","login.submit":"Σύνδεση","login.submitting":"Σύνδεση...","login.error":"Λάθος email ή κωδικός","login.unverified.title":"Επιβεβαιώστε το email σας","login.unverified.desc":"Στείλαμε σύνδεσμο επαλήθευσης στο email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε το σύνδεσμο.","login.unverified.resend":"Αποστολή νέου email επαλήθευσης","login.unverified.sending":"Αποστολή...","login.unverified.sent":"✓ Εστάλη — ελέγξτε τα εισερχόμενα","profile.email.verified":"Email επαληθεύτηκε","profile.email.not_verified":"Email δεν επαληθεύτηκε","login.no_account":"Δεν έχεις λογαριασμό;","login.register_link":"Εγγραφή","login.forgot_password":"Ξέχασα τον κωδικό","login.or_continue_with":"ή συνεχίστε με","login.continue_google":"Σύνδεση με Google","forgot.title":"Ξέχασα τον κωδικό","forgot.subtitle":"Εισάγετε το email σας για να λάβετε σύνδεσμο ανάκτησης","forgot.email":"Email","forgot.submit":"Αποστολή","forgot.submitting":"Αποστολή...","forgot.sent.title":"Ελέγξτε τα εισερχόμενά σας","forgot.sent.desc":"Αν υπάρχει λογαριασμός με αυτό το email, θα σας στείλουμε σύνδεσμο ανάκτησης κωδικού.","forgot.back_to_login":"Επιστροφή στη σύνδεση","forgot.error":"Αποτυχία αποστολής. Ελέγξτε το email σας ή δοκιμάστε ξανά.","forgot.error.not_found":"Δεν βρέθηκε λογαριασμός με αυτό το email.","forgot.error.send_failed":"Αποτυχία αποστολής email. Δοκιμάστε ξανά αργότερα","reset.title":"Νέος κωδικός","reset.subtitle":"Εισάγετε τον νέο σας κωδικό","reset.password":"Νέος κωδικός","reset.confirm":"Επιβεβαίωση κωδικού","reset.submit":"Αλλαγή κωδικού","reset.submitting":"Αποθήκευση...","reset.success":"Ο κωδικός άλλαξε επιτυχώς. Ανακατεύθυνση στη σύνδεση...","reset.back_to_login":"Επιστροφή στη σύνδεση","reset.error.mismatch":"Οι κωδικοί δεν ταιριάζουν","reset.error.invalid":"Μη έγκυρος σύνδεσμος. Παρακαλώ ζητήστε νέο.","register.title":"Εγγραφή","register.subtitle":"Δημιουργία λογαριασμού στο CanHelp","register.first_name":"Όνομα","register.last_name":"Επώνυμο","register.email":"Email","register.password":"Κωδικός (min 8 χαρακτήρες)","register.role":"Ρόλος","register.role.customer":"Χρήστης","register.role.customer.desc":"Δημοσιεύω εργασίες","register.role.specialist":"Ειδικός","register.role.specialist.desc":"Αναλαμβάνω εργασίες","register.submit":"Δημιουργία λογαριασμού","register.submitting":"Εγγραφή...","register.has_account":"Έχεις ήδη λογαριασμό;","register.login_link":"Σύνδεση","register.continue_google":"Εγγραφή με Google","register.check_email.title":"Ελέγξτε το email σας","register.check_email.desc":"Στείλαμε σύνδεσμο επαλήθευσης στη διεύθυνση email σας. Ελέγξτε τα εισερχόμενα (ή spam) και πατήστε τον σύνδεσμο.","register.check_email.login":"Επιστροφή στη σύνδεση","dashboard.title":"Πίνακας ελέγχου","dashboard.new_task":"+ Νέα εργασία","dashboard.my_tasks":"Οι εργασίες μου","dashboard.my_offers":"Οι προσφορές μου","dashboard.invitations":"Προσκλήσεις για εργασία","dashboard.offers_count":"προσφορές","dashboard.declined_count":"απορρίφθηκαν","dashboard.completed_tasks":"Ολοκληρωμένες εργασίες","dashboard.completed_offers":"Ολοκληρωμένες προσφορές","dashboard.review_pending":"Η αξιολόγηση δεν έχει υποβληθεί ακόμα","tasks.new.top_specialists":"Κορυφαίοι ειδικοί","tasks.new.select_category":"Επιλέξτε κατηγορία για να δείτε ειδικούς","tasks.new.invite":"Πρόσκληση","tasks.new.invited":"Επιλέχθηκε ✓","reviews.count":"αξιολογήσεις","filter.location":"Τοποθεσία","filter.language":"Γλώσσες","filter.language.any":"Οποιαδήποτε γλώσσα","filter.category.all":"Όλες οι κατηγορίες","user.categories":"Κατηγορίες","user.work_area":"Περιοχή εργασίας","dashboard.tasks.empty":"Δεν έχεις δημοσιεύσει εργασίες","dashboard.tasks.empty.cta":"Δημοσίευσε την πρώτη σου","dashboard.tasks.add_new":"Πρόσθεσε νέα εργασία","dashboard.offers.empty":"Δεν έχεις υποβάλλει προσφορές","dashboard.offers.empty.cta":"Βρες εργασίες","dashboard.customer.specialists_title":"Ψάχνεις εκτελεστή;","dashboard.customer.specialists_hint":"Δες προφίλ ειδικών, διάβασε αξιολογήσεις και κάλεσέ τους στις εργασίες σου","dashboard.customer.specialists_cta":"Βρες ειδικό","dashboard.customer.how_title":"Πώς λειτουργεί","dashboard.customer.step1":"Δημιούργησε εργασία με περιγραφή και προϋπολογισμό","dashboard.customer.step2":"Οι ειδικοί θα στείλουν προσφορές με τιμή και χρόνο","dashboard.customer.step3":"Επίλεξε τον κατάλληλο και ξεκίνα τη συνεργασία","notif.title":"Ειδοποιήσεις","notif.mark_all":"Σήμανση όλων ως αναγνωσμένα","notif.empty":"Δεν υπάρχουν ειδοποιήσεις","notif.type.new_offer":"Νέα προσφορά","notif.type.offer_accepted":"Η προσφορά σας έγινε δεκτή","notif.type.offer_declined":"Η προσφορά σας απορρίφθηκε","notif.type.task_completed":"Η εργασία ολοκληρώθηκε","notif.type.task_cancelled":"Η εργασία ακυρώθηκε","notif.type.new_message":"Νέο μήνυμα","notif.type.new_review":"Νέα αξιολόγηση","notif.type.task_invite":"Πρόσκληση σε εργασία","notif.body.new_offer":"Νέα προσφορά για \xab{title}\xbb","notif.body.offer_accepted":"Η προσφορά σας για \xab{title}\xbb έγινε δεκτή","notif.body.offer_declined":"Η προσφορά σας για \xab{title}\xbb απορρίφθηκε","notif.body.task_invite":"Σας προσκαλούν για \xab{title}\xbb","notif.body.new_review":"Λάβατε αξιολόγηση {rating}★","offer.status.pending":"Εκκρεμεί","offer.status.accepted":"Αποδεκτή","offer.status.declined":"Απορρίφθηκε","offer.status.withdrawn":"Αποσύρθηκε","offer.status.other_accepted":"Επιλέχθηκε άλλος ειδικός","common.loading":"Φόρτωση...","common.error":"Σφάλμα","common.save":"Αποθήκευση","common.saving":"Αποθήκευση...","common.cancel":"Ακύρωση","common.add":"Προσθήκη","common.close":"Κλείσιμο","common.edit":"Επεξεργασία","common.delete":"Διαγραφή","common.from":"από","common.currency":"€","common.greece":"Ελλάδα","chat.connected":"Συνδεδεμένος","chat.disconnected":"Αποσυνδεδεμένος","chat.no_rooms":"Δεν υπάρχουν συνομιλίες ακόμα","chat.task_fallback":"Εργασία","chat.select":"Επίλεξε συνομιλία","chat.no_messages":"Δεν υπάρχουν μηνύματα","chat.placeholder":"Γράψε μήνυμα... (Enter για αποστολή)","chat.conversation_fallback":"Συνομιλία","chat.direct_chat":"Απευθείας συνομιλία","chat.linked_task":"Συνδεδεμένη εργασία","chat.write_btn":"Μήνυμα","chat.just_now":"μόλις τώρα","chat.min_ago":"λ","chat.write_specialist":"Γράψε στον ειδικό","chat.write_customer":"Γράψε στον πελάτη","chat.notif_settings":"Ρυθμίσεις ειδοποιήσεων","chat.notif_messages":"Ειδοποιήσεις για νέα μηνύματα","chat.toast_title":"Νέο μήνυμα","chat.toast_open":"Άνοιγμα συνομιλίας","offer.price":"Τιμή","offer.price.placeholder":"π.χ. 80","offer.customer_budget":"Προϋπολογισμός πελάτη","offer.message":"Μήνυμα","offer.optional":"προαιρετικό","offer.message.placeholder":"Παρουσίασε τον εαυτό σου, την εμπειρία σου και γιατί είσαι η καλύτερη επιλογή...","offer.submitting":"Αποστολή...","profile.photo":"Φωτογραφία προφίλ","profile.photo.change":"Αλλαγή φωτογραφίας","profile.photo.hint":"JPEG, PNG, WebP \xb7 έως 5MB","profile.basic_info":"Βασικά στοιχεία","profile.phone":"Τηλέφωνο","profile.phone.placeholder":"+30 6901234567","profile.bio":"Σύντομη περιγραφή","profile.bio.placeholder":"Πες μας λίγα λόγια για εσένα...","profile.language":"Γλώσσα","profile.language.hint":"Γλώσσα διεπαφής και email ειδοποιήσεων","profile.languages":"Γλώσσες επικοινωνίας","profile.languages.hint":"Επιλέξτε όλες τις γλώσσες που μιλάτε","profile.skills":"Δεξιότητες","profile.skills.subtitle":"Προσθέσε τις υπηρεσίες που προσφέρεις","profile.skills.placeholder":"π.χ. Καθαρισμός, IT, Μαθήματα...","profile.role":"Ρόλος λογαριασμού","profile.role.specialist":"\uD83D\uDD27 Ειδικός","profile.role.admin":"\uD83D\uDC51 Admin","profile.role.customer":"\uD83D\uDC64 Χρήστης","profile.role.change":"Για αλλαγή ρόλου επικοινωνήστε με την υποστήριξη.","profile.become_specialist":"Γίνε Ειδικός","profile.become_specialist.desc":"Αναβαθμίσου σε Ειδικό για να δέχεσαι εργασίες και να δημιουργήσεις το προφίλ σου.","become_specialist.hero.title":"Κέρδισε χρήματα κάνοντας αυτό που ξέρεις","become_specialist.hero.subtitle":"Δημιούργησε προφίλ ειδικού και λάβε παραγγελίες από πελάτες σε όλη την Ελλάδα","become_specialist.how.title":"Πώς λειτουργεί","become_specialist.step1.title":"Δημιούργησε κάρτα ειδικού","become_specialist.step1.desc":"Δήλωσε κατηγορίες, δεξιότητες και περιοχές κάλυψης — το σύστημα θα βρει τις κατάλληλες εργασίες για σένα αυτόματα","become_specialist.step2.title":"Βρες εργασίες","become_specialist.step2.desc":"Ανακάλυψε εργασίες στις κατηγορίες σου στην ενότητα \xabΑναζήτηση εργασιών\xbb","become_specialist.step3.title":"Στείλε προσφορά & κέρδισε","become_specialist.step3.desc":"Υποβάλε προσφορές με τιμή και χρόνο, επικοινωνήσε με πελάτες και ολοκλήρωσε εργασίες","become_specialist.benefits.title":"Πλεονεκτήματα προφίλ ειδικού","become_specialist.benefit1":"Αναζήτηση εργασιών ανά κατηγορία και τοποθεσία","become_specialist.benefit2":"Δημόσιο προφίλ με αξιολογήσεις πελατών","become_specialist.benefit3":"Πρόγραμμα διαθεσιμότητας ορατό στους πελάτες","become_specialist.benefit4":"Προσθήκη σε αγαπημένα από πελάτες","become_specialist.cta":"Περισσότερα","become_specialist.free_badge":"Δωρεάν εγγραφή","profile.tab.notifications":"Ειδοποιήσεις","profile.tab.reviews":"Αξιολογήσεις","profile.tab.referral":"Παραπομπές","profile.tab.auto_response":"Αυτόματη απάντηση","profile.tab.site":"Site","profile.site.title":"Προσωπική σελίδα","profile.site.url_label":"Προσωπικό site","profile.site.copy":"Αντιγραφή","profile.site.copied":"Αντιγράφηκε","profile.site.visible_title":"Τι εμφανίζεται στη σελίδα σας","profile.site.visible.name":"Όνομα και φωτογραφία","profile.site.visible.bio":"Βιογραφικό","profile.site.visible.rating":"Αξιολόγηση και κριτικές","profile.site.visible.portfolio":"Χαρτοφυλάκιο / Κάρτες","profile.site.visible.contacts":"Στοιχεία επικοινωνίας","profile.site.visible.full_last_name":"Πλήρες επώνυμο","profile.site.visible.services":"Κάρτες υπηρεσιών","profile.site.visible.reviews":"Ενότητα κριτικών","profile.site.visible.status":"Κατάσταση \xabΈτοιμος να βοηθήσω\xbb","profile.site.theme":"Θέμα εμφάνισης","profile.site.theme.dark":"Σκοτεινό","profile.site.theme.light":"Φωτεινό","profile.site.slug_taken":"Αυτή η διεύθυνση είναι ήδη κατειλημμένη","profile.site.stats.title":"Στατιστικά επισκεψιμότητας","profile.site.stats.days":"τελευταίες 30 ημέρες","profile.site.stats.views":"Προβολές","profile.site.stats.unique":"Μοναδικοί επισκέπτες","profile.site.stats.messages":"Μηνύματα","profile.site.stats.total_views":"Συνολικές προβολές","profile.site.stats.total_unique":"Μοναδικοί επισκέπτες","profile.site.stats.total_messages":"Μηνύματα","profile.site.stats.empty":"Δεν υπάρχουν δεδομένα ακόμη","profile.site.stats.loading":"Φόρτωση στατιστικών...","profile.site.stats.no_slug":"Ορίστε τη διεύθυνση του site για να δείτε στατιστικά","profile.site.edit_bio_hint":"Το βιογραφικό και η φωτογραφία ρυθμίζονται στην καρτέλα \xabΒασικά\xbb.","status.can_help_now_hint":"Η κάρτα σου εμφανίζεται ψηλότερα","status.need_help_hint":"Οι ειδικοί μπορούν να σε βοηθήσουν","profile.referral.title":"Πρόγραμμα παραπομπών","profile.referral.desc":"Μοιράσου τον σύνδεσμο σου και κέρδισε ανταμοιβές για κάθε νέο χρήστη.","profile.referral.link_label":"Ο σύνδεσμος παραπομπής σου","profile.referral.copy":"Αντιγραφή","profile.referral.copied":"Αντιγράφηκε!","profile.referral.invited_count":"επιτυχείς παραπομπές","profile.referral.no_code":"Ο κωδικός παραπομπής δεν είναι διαθέσιμος.","notifications.title":"Ρυθμίσεις ειδοποιήσεων","notifications.email.new_tasks":"Email για νέες εργασίες","notifications.email.new_tasks.desc":"Λάβε email όταν δημοσιευτεί νέα εργασία στις κατηγορίες σου","notifications.messages.desc":"Λαμβάνεις ειδοποίηση όταν έρθει νέο μήνυμα","notifications.saved":"Ρυθμίσεις αποθηκεύτηκαν","notifications.plan_required":"Συνδρομή απαιτείται για αυτή τη λειτουργία","profile.tab.info":"Βασικά στοιχεία","profile.tab.finance":"Οικονομικά","profile.tab.skills":"Δεξιότητες","profile.tab.categories":"Κατηγορίες","profile.tab.geography":"Γεωγραφία","profile.specialist.categories":"Κατηγορίες εργασιών","profile.specialist.categories.desc":"Επίλεξε τις κατηγορίες στις οποίες εργάζεσαι","profile.specialist.geography":"Περιοχές κάλυψης","profile.specialist.geography.desc":"Επίλεξε τις πόλεις / περιοχές όπου δραστηριοποιείσαι","profile.saving":"Αποθήκευση...","profile.upload.error":"Σφάλμα κατά την αναφόρτωση","profile.saved":"Αποθηκεύτηκε","profile.tab.cards":"Χαρτοφυλάκιο","profile.cards.count":"Χαρτοφυλάκια","profile.cards.add":"Νέο χαρτοφυλάκιο","profile.cards.new_title":"Τίτλος νέου χαρτοφυλακίου","profile.cards.placeholder":"π.χ. Υδραυλικά","profile.cards.create":"Δημιουργία","profile.cards.cancel":"Ακύρωση","profile.cards.empty":"Δεν έχετε χαρτοφυλάκιο","profile.cards.create_first":"Δημιουργήστε το πρώτο σας χαρτοφυλάκιο","profile.cards.delete_confirm":"Διαγραφή χαρτοφυλακίου;","profile.card.tab.main":"Γενικά","profile.card.tab.skills":"Δεξιότητες","profile.card.tab.categories":"Κατηγορίες","profile.card.tab.geography":"Γεωγραφία","profile.card.tab.portfolio":"Γκαλερί","profile.card.active":"Ενεργή","profile.card.save":"Αποθήκευση","profile.card.saved":"Αποθηκεύτηκε","profile.card.delete":"Διαγραφή","profile.card.skill.add":"Προσθήκη δεξιότητας","profile.card.photo.add":"Προσθήκη φωτογραφίας","profile.card.photo.uploading":"Μεταφόρτωση...","profile.card.photo.empty":"Δεν υπάρχουν φωτογραφίες","profile.card.item.title":"Τίτλος","profile.card.item.desc":"Περιγραφή","profile.card.item.save":"Αποθήκευση","profile.card.item.cancel":"Ακύρωση","profile.card.item.edit":"Επεξεργασία","profile.upgrade.cards_limit":"Όριο χαρτοφυλακίων εξαντλήθηκε","profile.upgrade.plan":"Τρέχον πλάνο:","profile.upgrade.contact":"Επικοινωνήστε με τον διαχειριστή για αλλαγή πλάνου","profile.upgrade.ok":"Εντάξει","profile.plan.title":"Πλάνο συνδρομής","profile.balance":"Υπόλοιπο","profile.balance.topup":"Αναπλήρωση υπολοίπου","profile.balance.topup.title":"Αναπλήρωση υπολοίπου","profile.balance.topup.amount":"Ποσό (σε EUR)","profile.balance.topup.hint":"Επιλέξτε ποσό ή εισαγάγετε μανούαλα","profile.balance.topup.submit":"Πληρωμή","profile.balance.topup.loading":"Ρεδιρεκτάρισμα...","profile.balance.topup.error":"Σφάλμα μετάβασης στην πληρωμή. Προσπαθήστε ξανά.","payment.success.title":"Πληρωμή επιτυχής!","payment.success.desc":"Το υπόλοιπό σας ενημερώθηκε.","payment.cancelled.title":"Ακύρωση πληρωμής","payment.cancelled.desc":"Η πληρωμή ακυρώθηκε. Κανένα χρήμα δεν χρεώθηκε.","payment.pending.title":"Σε εξέλιξη...","payment.pending.desc":"Επεξεργαζόμαστε την πληρωμή σας.","payment.back_to_profile":"Επιστροφή στο προφίλ","profile.plan.basic":"Βασικό (δωρεάν)","profile.plan.contact_upgrade":"Επικοινωνήστε με τον διαχειριστή για αναβάθμιση","profile.plan.cards_up_to":"Χαρτοφυλάκια: έως","profile.plan.cards_unlimited":"Χαρτοφυλάκια: απεριόριστα","profile.plan.tasks_up_to":"Εργασίες: έως","profile.plan.offers_up_to":"Προσφορές: έως","profile.plan.valid_until":"Ισχύει έως","profile.plan.no_expiry":"Δεν λήγει","create.error":"Σφάλμα κατά τη δημοσίευση","tasks.category.general":"Γενικά","tasks.budget.range":"Εύρος:","tasks.budget.from":"από","tasks.budget.to":"έως","tasks.filter.reset":"Εκκαθάριση φίλτρων","tasks.load_more":"Φόρτωση ακόμα","tasks.showing":"Αποτελέσματα:","tasks.field.budget":"Προϋπολογισμός, €","admin.title":"Πίνακας Διαχείρισης","admin.tab.stats":"Στατιστικά","admin.tab.users":"Χρήστες","admin.tab.tasks":"Εργασίες","admin.tab.reports":"Αναφορές","admin.stats.users":"Χρήστες","admin.stats.tasks":"Εργασίες","admin.stats.offers":"Προσφορές","admin.stats.reviews":"Αξιολογήσεις","admin.tasks.by_status":"Εργασίες ανά κατάσταση","admin.col.user":"Χρήστης","admin.col.email":"Email","admin.col.role":"Ρόλος","admin.col.registered":"Εγγραφή","admin.col.status":"Κατάσταση","admin.col.title":"Τίτλος","admin.col.budget":"Προϋπολογισμός","admin.col.created":"Δημιουργία","admin.users.active":"Ενεργός","admin.users.inactive":"Ανενεργός","admin.users.deactivate":"Απενεργοποίηση","admin.users.activate":"Ενεργοποίηση","admin.tasks.cancel":"Ακύρωση","admin.reports.none":"Δεν υπάρχουν αναφορές","admin.reports.reviewed":"Αναθεωρήθηκε","admin.reports.dismiss":"Απόρριψη","admin.pagination.total":"Σύνολο","admin.users.role.change":"Αλλαγή ρόλου","admin.users.search.placeholder":"Αναζήτηση ονόματος ή email...","admin.tasks.delete":"Διαγραφή","admin.tasks.delete.confirm":"Διαγραφή αυτής της εργασίας μόνιμα;","admin.tasks.search.placeholder":"Αναζήτηση τίτλου...","admin.col.customer":"Πελάτης","admin.col.reporter":"Καταγγέλλων","admin.col.target":"Στόχος","admin.filter.all_roles":"Όλοι οι ρόλοι","admin.filter.all_statuses":"Όλες οι καταστάσεις","admin.reports.target.task":"Εργασία","admin.reports.target.user":"Χρήστης","admin.tab.categories":"Κατηγορίες","admin.tab.locations":"Πόλεις & Περιοχές","admin.tab.logs":"Αρχεία","admin.tab.plans":"Πακέτα","admin.tab.settings":"Ρυθμίσεις","admin.logs.subtab.ai":"AI Logs","admin.logs.subtab.activity":"Δραστηριότητα","admin.logs.subtab.mail":"Mail","admin.logs.subtab.notifications":"Ειδοποιήσεις","admin.notif_logs.type":"Τύπος","admin.notif_logs.title":"Τίτλος","admin.notif_logs.read":"Διαβασμένο","admin.notif_logs.empty":"Δεν υπάρχουν αρχεία ειδοποιήσεων","admin.stats.notif_chart_title":"Ειδοποιήσεις ανά ημέρα","admin.stats.notif_label":"Ειδοποιήσεις","admin.stats.mail_chart_title":"Emails ανά ημέρα","admin.stats.mail_label":"Emails","admin.filter.all":"Όλα","admin.stats.specialists":"Ειδικοί","admin.col.plan":"Πακέτο","admin.back_home":"Αρχική","admin.plans.title":"Πακέτα συνδρομής","admin.plans.add":"+ Νέο πακέτο","admin.plans.empty":"Δεν υπάρχουν πακέτα","admin.plans.form.new":"Νέο πακέτο","admin.plans.form.edit":"Επεξεργασία πακέτου","admin.plans.form.name":"Όνομα","admin.plans.form.price":"Τιμή (EUR)","admin.plans.form.old_price":"Παλιά τιμή (EUR, προαιρετικό)","admin.plans.form.max_offers":"Μέγ. προσφορές (κενό = χωρίς όριο)","admin.plans.form.max_cards":"Μέγ. χαρτοφυλάκιο (κενό = χωρίς όριο)","admin.plans.form.duration_days":"Διάρκεια (ημέρες, κενό = χωρίς λήξη)","admin.plans.form.description":"Περιγραφή","admin.plans.form.features":"Δυνατότητες (μία ανά γραμμή)","admin.plans.form.notify":"Ειδοποιήσεις νέων εργασιών","admin.plans.form.default":"Προεπιλογή","admin.plans.form.active":"Ενεργό","admin.plans.form.order":"Σειρά","admin.plans.form.role":"Ρόλος","admin.plans.form.tier":"Επίπεδο","admin.plans.form.role.customer":"Πελάτης","admin.plans.form.role.specialist":"Ειδικός","admin.plans.form.tier.free":"Δωρεάν","admin.plans.form.tier.pro":"Pro","admin.plans.form.tier.ultimate":"Ultimate","admin.plans.form.section.limits":"Όρια (κενό = χωρίς όριο)","admin.plans.form.max_messages_day":"Μέγ. μηνύματα/ημέρα","admin.plans.form.max_orders_day":"Μέγ. παραγγελίες/ημέρα","admin.plans.form.max_skills":"Μέγ. δεξιότητες","admin.plans.form.max_profiles":"Μέγ. προφίλ","admin.plans.form.max_portfolio":"Μέγ. στοιχεία χαρτοφυλακίου","admin.plans.form.section.boost":"Πολλαπλασιαστές & Ενίσχυση","admin.plans.form.search_boost":"Ενίσχυση αναζήτησης","admin.plans.form.offers_multiplier":"Πολλαπλασιαστής προσφορών","admin.plans.form.section.contact":"Δικαιώματα επικοινωνίας","admin.plans.form.can_contact_free":"Επικοινωνία με δωρεάν χρήστες","admin.plans.form.can_contact_pro":"Επικοινωνία με Pro χρήστες","admin.plans.form.can_contact_all":"Επικοινωνία με όλους","admin.plans.form.can_show_contact":"Εμφάνιση στοιχείων επικοινωνίας","admin.plans.form.can_view_phone":"Προβολή τηλεφώνου","admin.plans.form.section.features":"Λειτουργίες","admin.plans.form.upload_video":"Μεταφόρτωση βίντεο","admin.plans.form.favorites":"Αγαπημένα","admin.plans.form.google_calendar":"Google Calendar","admin.plans.form.verified_badge":"Σήμα επαλήθευσης","admin.plans.form.highlighted_reviews":"Προβεβλημένες κριτικές","admin.plans.form.personal_site":"Προσωπική σελίδα","admin.plans.form.can_help_now":"Κατάσταση \xabΜπορώ να βοηθήσω\xbb","admin.plans.form.need_help":"Κατάσταση \xabΧρειάζομαι βοήθεια\xbb","admin.plans.form.auto_response":"Αυτόματη απάντηση","admin.plans.form.auto_match":"Αυτόματη αντιστοίχιση","admin.plans.form.instant_dispatch_free":"Άμεση αποστολή (δωρεάν)","admin.plans.form.instant_dispatch_pro":"Άμεση αποστολή (Pro)","admin.plans.badge.default":"Προεπιλογή","admin.plans.badge.inactive":"Ανενεργό","admin.plans.make_default":"Ορισμός ως προεπιλογή","admin.plans.tasks":"Εργασίες","admin.plans.offers":"Προσφορές","admin.plans.cards":"Χαρτοφυλάκιο","admin.plans.notify_tasks":"Ειδοποιήσεις εργασιών","admin.plans.delete.confirm":"Διαγραφή πακέτου","admin.activity.title":"Αρχείο δραστηριότητας","admin.activity.event":"Γεγονός","admin.activity.all_events":"Όλα τα γεγονότα","admin.activity.from":"Από","admin.activity.to":"Έως","admin.activity.reset":"Επαναφορά","admin.activity.total":"Σύνολο","admin.activity.empty":"Δεν υπάρχουν εγγραφές","admin.mail.event":"Συμβάν email","admin.mail.all_events":"Όλα τα email συμβάντα","admin.mail.from":"Από","admin.mail.to":"Έως","admin.mail.reset":"Επαναφορά","admin.mail.total":"Σύνολο","admin.mail.empty":"Δεν υπάρχουν email logs","admin.mail.recipient":"Παραλήπτης","admin.mail.provider":"Πάροχος","admin.mail.details":"Λεπτομέρειες","admin.mail.status":"Κατάσταση","admin.mail.success":"Επιτυχία","admin.mail.failed":"Σφάλμα","admin.event.email_sent":"Email sent","admin.event.email_failed":"Email failed","admin.event.email_dev":"Email DEV fallback","admin.event.admin_email_test_sent":"Admin test email sent","admin.event.admin_email_test_failed":"Admin test email failed","admin.logs.empty":"Δεν υπάρχουν εγγραφές","admin.logs.date":"Ημερομηνία","admin.logs.provider":"Πάροχος","admin.logs.model":"Μοντέλο","admin.logs.action":"Ενέργεια","admin.logs.langs":"Γλώσσες","admin.logs.in":"Είσοδος","admin.logs.out":"Έξοδος","admin.logs.total":"Σύνολο","admin.logs.ms":"ms","admin.logs.status":"Κατάσταση","admin.stats.activity_30d":"Δραστηριότητα 30 ημερών","admin.stats.tasks_label":"Εργασίες","admin.stats.users_label":"Χρήστες","admin.stats.specialists_label":"Ειδικοί","admin.stats.tokens_title":"Χρήση tokens (ανά μήνα)","admin.stats.tokens_out":"Εξερχόμενα","admin.stats.tokens_in":"Εισερχόμενα","admin.stats.tokens_out_label":"Εξερχόμενα tokens","admin.stats.tokens_in_label":"Εισερχόμενα tokens","admin.stats.cost_label":"Κόστος (USD)","admin.stats.tasks_by_status":"Εργασίες ανά κατάσταση","admin.task_status.open":"Ανοιχτές","admin.task_status.in_progress":"Σε εξέλιξη","admin.task_status.completed":"Ολοκληρωμένες","admin.task_status.cancelled":"Ακυρωμένες","admin.task_status.draft":"Προσχέδια","admin.settings.tab.general":"Γενικά","admin.settings.tab.smtp":"E-Mail","admin.settings.tab.notifications":"Ειδοποιήσεις","admin.settings.tab.payment":"Πληρωμή","admin.settings.tab.referral":"Παραπομπές","admin.settings.tab.seo":"SEO","admin.settings.tab.socials":"Κοινωνικά δίκτυα","admin.settings.socials.title":"Σύνδεσμοι κοινωνικών δικτύων","admin.settings.socials.hint":"Συμπληρωμένες εγγραφές εμφανίζονται στο υπόγειο","admin.settings.seo.maintenance_label":"Λειτουργία συντήρησης","admin.settings.seo.maintenance_hint":"Εμφάνιση σελίδας συντήρησης σε όλους τους επισκέπτες","admin.settings.seo.indexing_label":"Ευρετηρίαση από μηχανές αναζήτησης","admin.settings.seo.indexing_hint":"Επιτρέπει στις μηχανές αναζήτησης να ευρετηριάσουν τον ιστότοπο","admin.settings.seo.head_scripts_label":"Scripts στο (JS)","admin.settings.seo.head_scripts_hint":"Εκτελείται σε κάθε σελίδα (Google Tag Manager, analytics κ.λπ.)","admin.settings.seo.site_title_label":"Τίτλος ιστότοπου","admin.settings.seo.site_description_label":"Περιγραφή ιστότοπου (meta description)","admin.settings.referral.title":"Πρόγραμμα παραπομπών","admin.settings.referral.hint":"Επιβράβευσε χρήστες που φέρνουν νέους εγγεγραμμένους.","admin.settings.referral.enabled_label":"Ενεργό","admin.settings.referral.enabled_hint":"Ενεργοποίηση / απενεργοποίηση εφαρμογής ανταμοιβών","admin.settings.referral.customer_section":"Για πελάτες","admin.settings.referral.specialist_section":"Για ειδικούς","admin.settings.referral.plan_label":"Πλάνο ανταμοιβής","admin.settings.referral.no_plan":"— χωρίς πλάνο —","admin.settings.referral.plan_hint":"Αυτό το πλάνο θα ανατεθεί στον χρήστη που έφερε νέους. Εάν το τρέχον πλάνο του είναι υψηλότερο, θα προστεθούν μόνο οι μέρες.","admin.settings.referral.days_label":"Ημέρες ανταμοιβής","admin.settings.referral.days_hint":"Αριθμός ημερών που θα προστεθούν στη λήξη του πλάνου.","admin.settings.general.title":"Γενικές ρυθμίσεις","admin.settings.general.site_name":"Όνομα ιστότοπου","admin.settings.general.site_url":"URL ιστότοπου","admin.settings.general.contact_email":"Email επικοινωνίας","admin.settings.general.support_phone":"Τηλέφωνο υποστήριξης","admin.settings.smtp.title":"Ρυθμίσεις SMTP","admin.settings.smtp.hint":"Χρησιμοποιείται για αποστολή ειδοποιήσεων email.","admin.settings.smtp.host":"SMTP Host","admin.settings.smtp.port":"Θύρα","admin.settings.smtp.encryption":"Κρυπτογράφηση","admin.settings.smtp.enc.none":"Χωρίς","admin.settings.smtp.enc.tls":"STARTTLS (θύρα 587)","admin.settings.smtp.enc.ssl":"SSL/TLS (θύρα 465)","admin.settings.smtp.username":"Όνομα χρήστη","admin.settings.smtp.password":"Κωδικός / App Password","admin.settings.smtp.from_name":"Όνομα αποστολέα","admin.settings.smtp.from_email":"Email αποστολέα","admin.settings.smtp.test":"Αποστολή δοκιμαστικού email","admin.settings.smtp.sending":"Αποστολή...","admin.settings.payment.hint":"Τα στοιχεία για ePay Piraeus Bank.","admin.settings.env.test":"Δοκιμαστικό (sandbox)","admin.settings.env.prod":"Παραγωγή","admin.settings.env.label":"Περιβάλλον","admin.settings.merchant_id":"Merchant ID","admin.settings.api_user":"API User","admin.settings.api_password":"API Password","admin.settings.confirm_url":"Confirmation URL (webhook)","admin.settings.cancel_url":"Cancel URL","admin.settings.active":"Ενεργό","admin.settings.saving":"Αποθήκευση...","admin.settings.saved":"✓ Αποθηκεύτηκε","admin.notif.vars_hint":"Διαθέσιμες μεταβλητές στα πρότυπα","admin.notif.tmpl.not_set":"Πρότυπο δεν έχει οριστεί","admin.notif.tmpl.subject_label":"Θέμα email","admin.notif.tmpl.body_label":"Κείμενο email (HTML)","admin.notif.tmpl.save":"Αποθήκευση","admin.notif.tmpl.close":"Κλείσιμο","admin.notif.tmpl.translate":"Αυτόματη μετάφραση","admin.notif.tmpl.translating":"Μετάφραση...","admin.notif.tmpl.saving":"Αποθήκευση...","admin.notif.email_verification":"Επαλήθευση email","admin.notif.registration_success":"Επιτυχής εγγραφή","admin.notif.password_reset":"Επαναφορά κωδικού","admin.notif.new_offer":"Νέα προσφορά","admin.notif.new_task":"Νέα εργασία","admin.notif.offer_accepted":"Προσφορά αποδεκτή","admin.notif.new_message":"Νέο μήνυμα","admin.notif.offer_declined":"Απόρριψη προσφοράς","admin.notif.offer_other_accepted":"Επιλέχθηκε άλλος ειδικός","admin.notif.task_updated":"Ενημέρωση εργασίας","admin.notif.deadline_reminder":"Υπενθύμιση προθεσμίας","admin.notif.task_archived":"Αυτόματη απόσυρση εργασίας","admin.notif.referral_reward":"Ανταμοιβή παραπομπής","admin.email_template.plan_activated":"Τιμολόγιο — ενεργοποίηση πλάνου","admin.email_template.plan_upgraded":"Τιμολόγιο — αναβάθμιση πλάνου","admin.email_template.plan_downgrade_scheduled":"Τιμολόγιο — προγραμματισμένη υποβάθμιση","admin.email_template.plan_downgrade_applied":"Τιμολόγιο — εφαρμογή υποβάθμισης","admin.email_template.plan_renewal_reminder":"Τιμολόγιο — υπενθύμιση ανανέωσης","admin.email_template.plan_insufficient_funds":"Τιμολόγιο — ανεπαρκές υπόλοιπο","pricing.confirm.title":"Επιβεβαίωση επιλογής πλάνου","pricing.confirm.plan":"Πλάνο","pricing.confirm.prorated":"Αναλογική έκπτωση","pricing.confirm.effective_price":"Προς πληρωμή","pricing.confirm.your_balance":"Το υπόλοιπό σας","pricing.confirm.downgrade_info":"Η μετάβαση στο νέο πλάνο θα γίνει αυτόματα μετά τη λήξη της τρέχουσας περιόδου.","pricing.confirm.insufficient":"Ανεπαρκές υπόλοιπο.","pricing.confirm.top_up":"Ανανέωση","pricing.confirm.schedule_downgrade":"Προγραμματισμός μετάβασης","pricing.confirm.pay":"Πληρωμή","admin.user_edit.title":"Επεξεργασία χρήστη","admin.user_edit.email":"Email","admin.user_edit.email_verified":"Διευθυνση email επαληθεύτηκε","admin.user_edit.email_not_verified":"Email δεν έχει επαληθευτεί","admin.user_edit.verify_email_btn":"Χειροκίνητη επαλήθευση","admin.user_edit.verify_email_done":"Email επαληθεύτηκε!","admin.user_edit.id":"ID","admin.user_edit.registered":"Εγγραφή","admin.user_edit.last_seen":"Τελευταία σύνδεση","admin.user_edit.lang":"Γλώσσα","admin.user_edit.first_name":"Όνομα","admin.user_edit.last_name":"Επώνυμο","admin.user_edit.phone":"Τηλέφωνο","admin.user_edit.bio":"Βιογραφικό","admin.user_edit.role":"Ρόλος","admin.user_edit.plan":"Πακέτο","admin.user_edit.no_plan":"— Χωρίς πακέτο —","admin.user_edit.active":"Ενεργός λογαριασμός","admin.user_edit.balance":"Υπόλοιπο (EUR)","admin.user_edit.skills":"Δεξιότητες","admin.user_edit.tab.profile":"Προφίλ","admin.user_edit.tab.account":"Λογαριασμός","admin.user_edit.tab.balance":"Υπόλοιπο","admin.user_edit.tab.settings":"Ρυθμίσεις","admin.user_edit.tab.specialist":"Χαρτοφυλάκιο","admin.user_edit.tab.site":"Ιστοσελίδα","admin.user_edit.plan_expires":"Λήξη πλάνου","admin.user_edit.interface_lang":"Γλώσσα διεπαφής","admin.user_edit.comm_languages":"Γλώσσες επικοινωνίας","admin.user_edit.personal_site_slug":"Προσωπική σελίδα","admin.user_edit.show_contact_info":"Εμφάνιση στοιχείων επικοινωνίας","admin.user_edit.show_contact_info.hint":"Ορατό στους πελάτες","admin.user_edit.notify_new_tasks":"Ειδοποίηση για νέες εργασίες","admin.user_edit.notify_new_tasks.hint":"Push και email ειδοποιήσεις","admin.user_edit.notif_messages":"Ειδοποιήσεις μηνυμάτων","admin.user_edit.notif_messages.hint":"Νέα μηνύματα στη συνομιλία","admin.user_edit.site_settings":"Ρυθμίσεις προσωπικής σελίδας","admin.user_edit.categories":"Κατηγορίες υπηρεσιών","admin.user_edit.locations":"Περιοχές εξυπηρέτησης","admin.user_edit.skill_placeholder":"Νέα δεξιότητα...","admin.user_edit.add_category":"— Επιλέξτε κατηγορία —","admin.user_edit.add_location":"— Επιλέξτε περιοχή —","admin.user_edit.specialist_cards":"Χαρτοφυλάκιο ειδικού","admin.user_edit.no_cards":"Δεν βρέθηκαν στοιχεία χαρτοφυλακίου","admin.user_edit.card_title":"Τίτλος χαρτοφυλακίου","admin.user_edit.card_description":"Περιγραφή","admin.balance.topup.btn":"Αναπλήρωση","admin.balance.withdraw.btn":"Αφαίρεση","admin.balance.modal_hint":"Οι αλλαγές ισχύουν άμεσα και καταγράφονται στο ιστορικό","admin.balance.topup.title":"Αναπλήρωση υπολοίπου","admin.balance.topup.amount":"Ποσό","admin.balance.topup.description":"Σχόλιο","admin.balance.topup.description.placeholder":"Για παράδειγμα: bonus ή χειροκίνητη αναπλήρωση","admin.balance.topup.submit":"Αναπλήρωση υπολοίπου","admin.balance.withdraw.title":"Αφαίρεση υπολοίπου","admin.balance.withdraw.amount":"Ποσό","admin.balance.withdraw.description":"Σχόλιο","admin.balance.withdraw.description.placeholder":"Για παράδειγμα: επιστροφή ή χειροκίνητη χρέωση","admin.balance.withdraw.submit":"Αφαίρεση από το υπόλοιπο","admin.user_edit.role.customer":"Πελάτης","admin.user_edit.role.specialist":"Ειδικός","admin.user_edit.role.admin":"Διαχειριστής","common.refresh":"Ανανέωση","common.back_home":"Αρχική","admin.loc.hint":"Διαχείριση πόλεων και συνοικιών","admin.loc.add_city":"Νέα πόλη","admin.loc.add_district":"Προσθήκη συνοικίας","admin.loc.new":"Νέα τοποθεσία","admin.loc.edit":"Επεξεργασία τοποθεσίας","admin.loc.district":"συνοικία","admin.loc.empty":"Δεν υπάρχουν τοποθεσίες","admin.loc.delete.confirm":"Διαγραφή τοποθεσίας; Όλες οι συνοικίες θα διαγραφούν επίσης.","admin.cat.add_root":"Νέα κατηγορία","admin.cat.add_sub":"Υποκατηγορία","admin.cat.edit":"Επεξεργασία","admin.cat.delete":"Διαγραφή","admin.cat.delete.confirm":"Διαγραφή κατηγορίας; Όλες οι υποκατηγορίες θα διαγραφούν επίσης.","admin.cat.slug":"Slug","admin.cat.icon":"Εικονίδιο","admin.cat.name_el":"Ελληνικά","admin.cat.name_en":"Αγγλικά","admin.cat.name_ru":"Ρωσικά","admin.cat.order":"Σειρά","admin.cat.active":"Ενεργή","admin.cat.parent":"Γονική κατηγορία","admin.cat.no_parent":"Κορυφαίο επίπεδο","admin.cat.save":"Αποθήκευση","admin.cat.cancel":"Ακύρωση","admin.cat.empty":"Δεν υπάρχουν κατηγορίες","admin.cat.hint":"Διαχείριση κατηγοριών με πολυεπίπεδη ιεραρχία","admin.cat.new":"Νέα κατηγορία","admin.cat.subcategory":"υποκατηγορία","admin.cat.add_child":"Προσθήκη υποκατηγορίας","admin.cat.inactive":"Ανενεργή","admin.event.user_login":"Σύνδεση","admin.event.user_register":"Εγγραφή","admin.event.admin_user_deactivate":"Αποκλεισμός χρήστη","admin.event.admin_user_activate":"Ενεργοποίηση χρήστη","admin.event.admin_user_role_changed":"Αλλαγή ρόλου","admin.event.admin_task_cancelled":"Ακύρωση εργασίας","admin.event.admin_task_deleted":"Διαγραφή εργασίας","admin.event.admin_report_reviewed":"Αναφορά εξετάστηκε","admin.event.admin_report_dismissed":"Αναφορά απορρίφθηκε","admin.event.task_created":"Δημιουργία εργασίας","user.online":"Σε σύνδεση","user.seen_minutes":"ήταν εδώ πριν {n} λεπτά","user.seen_hours":"ήταν εδώ πριν {n} ώρες","user.seen_yesterday":"ήταν εδώ χθες","user.seen_days":"ήταν εδώ πριν {n} μέρες","specialists.title":"Ειδικοί","specialists.search":"Αναζήτηση ειδικού...","specialists.search.btn":"Αναζήτηση","specialists.empty":"Δεν βρέθηκαν ειδικοί","specialists.no_bio":"Χωρίς περιγραφή","specialists.view":"Προβολή προφίλ","specialists.reviews":"αξιολογήσεις","specialist.favorite":"Προσθήκη στα αγαπημένα","specialist.unfavorite":"Αφαίρεση από αγαπημένα","specialist.site_link":"Προσωπικό site","favorites.specialists.title":"Αγαπημένοι ειδικοί","favorites.specialists.empty":"Δεν έχετε αγαπημένους ειδικούς","nav.favorites":"Αγαπημένα","nav.schedule":"Πρόγραμμα","nav.find_tasks":"Αναζήτηση εργασιών","schedule.title":"Το πρόγραμμά μου","schedule.subtitle":"Σημειώστε τις ημέρες που είστε ελεύθεροι ή απασχολημένοι — οι πελάτες θα δουν τη διαθεσιμότητά σας","schedule.available":"Ελεύθερος","schedule.busy":"Απασχολημένος","schedule.unset":"Μη ορισμένο","schedule.click_hint":"← κλικ για εναλλαγή κατάστασης","schedule.range_mode":"Επιλογή εύρους","schedule.range_from":"Από {date} — επιλέξτε τελική ημερομηνία","schedule.click_to_set":"Κλικ για ορισμό","schedule.free":"ελεύθερα","schedule.busy_count":"απασχολημένα","schedule.free_days":"ελεύθερες ημέρες","schedule.googleCalendar":"Google Calendar","schedule.connectGoogle":"Σύνδεση με Google Calendar","schedule.disconnectGoogle":"Αποσύνδεση","schedule.connectedAs":"Συνδεδεμένο ως","schedule.importFromGoogle":"Συγχρονισμός από Google","schedule.gcalConnected":"✓ Google Calendar συνδέθηκε","schedule.gcalError":"Σφάλμα σύνδεσης Google Calendar","schedule.gcalImportDone":"Εισήχθησαν {n} ημερ. από Google Calendar","schedule.gcalAutoSyncNote":"Οι αλλαγές αποστέλλονται αυτόματα στο Google Calendar","schedule.gcalConnectDesc":"Συνδέστε το Google Calendar για αυτόματο συγχρονισμό","schedule.gcalDisconnectConfirm":"Αποσύνδεση Google Calendar;","find_tasks.title":"Αναζήτηση εργασιών","find_tasks.for_me":"Για μένα","find_tasks.all":"Όλες οι εργασίες","find_tasks.by_category":"Ανά κατηγορία","find_tasks.list":"Λίστα","find_tasks.already_offered":"Προσφορά υποβλήθηκε","find_tasks.offer_now":"Υποβολή προσφοράς","find_tasks.empty_for_me":"Δεν βρέθηκαν εργασίες στις κατηγορίες σας","find_tasks.banner_hint":"Βρείτε εργασίες που ταιριάζουν με το χαρτοφυλάκιό σας","find_tasks.no_cards":"Δημιουργήστε ένα χαρτοφυλάκιο ειδικού για να δείτε εργασίες για εσάς","find_tasks.add_card":"Δημιουργία χαρτοφυλακίου","find_tasks.search":"Αναζήτηση εργασιών...","find_tasks.tasks_count":"εργασίες","footer.tagline":"Η πλατφόρμα εργασιών για την Ελλάδα","footer.rights":"Όλα τα δικαιώματα διατηρούνται.","app.download_title":"Κατεβάστε την εφαρμογή CanHelp","app.download_desc":"Όλο το CanHelp — πάντα μαζί σας. Διαθέσιμο για Android και iOS.","nav.pricing":"Τιμές","pricing.title":"Τιμολόγηση","pricing.subtitle":"Επιλέξτε το κατάλληλο πρόγραμμα","pricing.role.customer":"Πελάτης","pricing.role.specialist":"Ειδικός","pricing.free":"Δωρεάν","pricing.per_month":"μήνα","pricing.duration":"Διάρκεια","pricing.days":"ημ.","pricing.current_plan":"Το πρόγραμμά σας","pricing.popular":"Δημοφιλές","pricing.choose":"Επιλογή","pricing.your_plan":"Ενεργό πρόγραμμα","pricing.free_default":"Προεπιλογή","pricing.compare":"Σύγκριση λειτουργιών","pricing.feature":"Λειτουργία","pricing.faq_note":"Η πληρωμή γίνεται από το υπόλοιπο CanHelp. Ανατροφοδότηση διαθέσιμη στην Πληρωμή.","pricing.feat.messages":"Μηνύματα / ημέρα","pricing.feat.orders":"Παραγγελίες / ημέρα","pricing.feat.contact_all":"Επικοινωνία με όλους","pricing.feat.view_phone":"Εμφάνιση τηλεφώνου","pricing.feat.show_contact":"Εμφάνιση στοιχείων επαφής","pricing.feat.favorites":"Αγαπημένα","pricing.feat.verified_badge":"Επαληθευμένο badge","pricing.feat.google_calendar":"Google Calendar","pricing.feat.personal_site":"Προσωπικό site","pricing.feat.auto_response":"Αυτόματη απάντηση","pricing.feat.auto_match":"Αυτόματη αντιστοίχιση","pricing.feat.highlighted_reviews":"Επισημασμένες αξιολογήσεις","pricing.feat.portfolio":"Στοιχεία χαρτοφυλακίου","pricing.feat.cards":"Κάρτες ειδικού","pricing.feat.notify_tasks":"Ειδοποιήσεις νέων εργασιών","pricing.feat.video":"Βίντεο στο χαρτοφυλάκιο","upgrade.available_in":"Διαθέσιμο στο","upgrade.cta":"Αναβάθμιση","dashboard.plan.title":"Το πρόγραμμά μου","dashboard.plan.expires":"Λήγει σε {n} ημέρες","dashboard.plan.upgrade":"Αναβάθμιση προγράμματος","dashboard.plan.no_plan":"Δωρεάν πρόγραμμα","dashboard.plan.messages":"Μηνύματα σήμερα","dashboard.plan.orders":"Παραγγελίες σήμερα","dashboard.plan.limits":"Ημερήσια όρια","dashboard.plan.features":"Λειτουργίες","dashboard.plan.stats":"Στατιστικά","dashboard.stats.cards":"Χαρτοφυλάκια","dashboard.stats.maxCards":"Μέγ. χαρτοφυλάκια","dashboard.stats.portfolioItems":"Στοιχεία portfolio","dashboard.stats.maxPortfolioItems":"Μέγ. στοιχεία","dashboard.stats.activeOffers":"Ενεργές προσφορές","dashboard.stats.reviewsReceived":"Αξιολογήσεις","dashboard.stats.activeTasks":"Ενεργές εργασίες","dashboard.stats.completedTasks":"Ολοκληρωμένες","status.can_help_now":"Είμαι διαθέσιμος τώρα","status.need_help":"Χρειάζομαι βοήθεια","status.active":"Ενεργό","status.toggle_on":"Ενεργοποίηση","status.toggle_off":"Απενεργοποίηση","fomo.missed_orders":"Χάσατε {n} παραγγελίες","fomo.missed_value":"Αξία €{v}","fomo.upgrade_hint":"Αναβαθμίστε για να λαμβάνετε περισσότερες παραγγελίες","fomo.conversion":"Μετατροπές εργασιών","fomo.active":"Ενεργές","fomo.with_offers":"Με προσφορές","fomo.completed":"Ολοκληρωμένες","fomo.already_offered":"{n} ειδικοί έχουν ήδη απαντήσει","fomo.specialist_missed":"Χάσατε {n} παραγγελίες","fomo.top_categories":"Κατηγορίες","fomo.offers_received":"προσφορές ελήφθησαν","fomo.avg_offers":"Μέσο {n}/εργασία","fomo.completion_rate":"ολοκληρωμένες","task.auto_match":"Αυτόματη αντιστοίχιση","task.auto_match_results":"Κορυφαίοι ειδικοί","task.no_offer_yet":"Δεν έχετε στείλει προσφορά ακόμα","task.make_offer":"Αποστολή προσφοράς","auto_response.title":"Αυτόματη Απάντηση","auto_response.enabled":"Ενεργοποίηση αυτόματης απάντησης","auto_response.min_budget":"Ελάχ. προϋπολογισμός","auto_response.max_budget":"Μέγ. προϋπολογισμός","auto_response.default_price":"Προεπιλεγμένη τιμή","auto_response.default_message":"Προεπιλεγμένο μήνυμα","auto_response.max_per_day":"Μέγ. αυτόματες προσφορές/ημέρα","auto_response.save":"Αποθήκευση","auto_response.saved":"Αποθηκεύτηκε","auto_response.categories":"Κατηγορίες","auto_response.locations":"Τοποθεσίες","profile.personal_site":"Προσωπικό Site","profile.site_slug":"Slug URL","profile.site_slug_hint":"Μόνο λατινικοί χαρακτήρες, αριθμοί, - και _","profile.site_open":"Άνοιγμα site","profile.site_preview":"Το site σας","profile.show_contact":"Εμφάνιση στοιχείων επαφής","profile.show_contact_hint":"Πελάτες με Pro/Ultimate πρόγραμμα θα βλέπουν το τηλέφωνό σας","gcal.upgrade_required":"Το Google Calendar απαιτεί Pro ή Ultimate πρόγραμμα","chat.limit_warning":"Απομένουν {n} μηνύματα σήμερα","chat.limit_reached":"Εξαντλήθηκαν τα μηνύματα. Αναβαθμίστε το πρόγραμμά σας","chat.upgrade":"Αναβάθμιση","site.member_since":"Μαζί μας από","site.rating":"Βαθμολογία","site.completed_tasks":"Ολοκληρώθηκαν","site.languages":"Γλώσσες","site.photos":"φωτ.","site.contact_form":"Επικοινωνία","site.contact_sent":"Το μήνυμα στάλθηκε!","site.contact_sent_desc":"Ο ειδικός θα επικοινωνήσει μαζί σας σύντομα","site.contact_name":"Όνομα","site.contact_name_ph":"Το όνομά σας","site.contact_email_ph":"your@email.com","site.contact_message":"Μήνυμα","site.contact_message_ph":"Περιγράψτε την εργασία σας...","site.contact_send":"Αποστολή","site.share":"Κοινοποίηση","site.speaks_languages":"Μιλάει","site.message_sent":"Το μήνυμα εστάλη!","site.message_sent_desc":"Ο ειδικός θα το λάβει στη συνομιλία","site.message_placeholder":"Γράψτε το μήνυμά σας...","site.write_to_chat":"Γράψτε στο chat","site.auth_required_title":"Απαιτείται σύνδεση","site.auth_required_desc":"Για να γράψετε στο chat, χρειάζεται να συνδεθείτε στο λογαριασμό σας.","site.auth_login_btn":"Σύνδεση","site.auth_contact_form_btn":"Επικοινωνία μέσω φόρμας","specialist.services":"Υπηρεσίες","portfolio.title":"Χαρτοφυλάκιο","common.not_found":"Η σελίδα δεν βρέθηκε","common.anonymous":"Ανώνυμα","specialist_setup.page_title":"Ρύθμιση προφίλ ειδικού","specialist_setup.step_of":"Βήμα {current} από {total}","specialist_setup.next":"Επόμενο","specialist_setup.back":"Πίσω","specialist_setup.skip":"Παράλειψη","specialist_setup.finish":"Ολοκλήρωση","specialist_setup.go_to_profile":"Μεταβείτε στο προφίλ","specialist_setup.browse_tasks":"Εξερεύνηση εργασιών","specialist_setup.step1.title":"Καλωσήλθατε!","specialist_setup.step1.subtitle":"Ας ρυθμίσουμε το προφίλ σας","specialist_setup.step1.desc":"Ένα πλήρες προφίλ σας βοηθά να βρείτε περισσότερους πελάτες. Ακολουθήστε τα βήματα για να δημιουργήσετε το τέλειο προφίλ ειδικού.","specialist_setup.step1.what_next":"Τι θα κάνουμε:","specialist_setup.step1.item1":"Συμπλήρωση βασικών πληροφοριών","specialist_setup.step1.item2":"Δημιουργία κάρτας υπηρεσίας","specialist_setup.step1.item3":"Προσθήκη δεξιοτήτων και κατηγοριών","specialist_setup.step1.item4":"Επιλογή γεωγραφικής περιοχής","specialist_setup.step1.item5":"Μεταφόρτωση φωτογραφιών χαρτοφυλακίου","specialist_setup.step2.title":"Βασικό προφίλ","specialist_setup.step2.subtitle":"Πείτε μας για σας","specialist_setup.step2.bio_label":"Σχετικά με εμένα","specialist_setup.step2.bio_placeholder":"Περιγράψτε την εμπειρία σας, τις υπηρεσίες που προσφέρετε...","specialist_setup.step2.phone_label":"Τηλέφωνο","specialist_setup.step2.phone_placeholder":"+30 6900000000","specialist_setup.step2.photo_label":"Φωτογραφία προφίλ","specialist_setup.step2.photo_btn":"Μεταφόρτωση φωτογραφίας","specialist_setup.step2.photo_uploading":"Μεταφόρτωση...","specialist_setup.step2.photo_hint":"Εμφανίζεται στο προφίλ σας","specialist_setup.step3.title":"Κάρτα υπηρεσίας","specialist_setup.step3.subtitle":"Δημιουργήστε την πρώτη σας κάρτα υπηρεσίας","specialist_setup.step3.title_label":"Τίτλος κάρτας","specialist_setup.step3.title_placeholder":"Π.χ. Υδραυλικός, Ηλεκτρολόγος, Καθαρισμός...","specialist_setup.step3.desc_label":"Περιγραφή","specialist_setup.step3.desc_placeholder":"Περιγράψτε λεπτομερώς τι προσφέρετε, εμπειρία, πλεονεκτήματα...","specialist_setup.step3.title_required":"Απαιτείται τίτλος","specialist_setup.step4.title":"Δεξιότητες & Κατηγορίες","specialist_setup.step4.subtitle":"Προσθέστε δεξιότητες και επιλέξτε κατηγορίες","specialist_setup.step4.skills_label":"Δεξιότητες","specialist_setup.step4.skills_placeholder":"Π.χ. Εγκατάσταση σωληνώσεων...","specialist_setup.step4.skills_add":"Προσθήκη","specialist_setup.step4.categories_label":"Κατηγορίες","specialist_setup.step5.title":"Γεωγραφική περιοχή","specialist_setup.step5.subtitle":"Πού παρέχετε υπηρεσίες;","specialist_setup.step5.hint":"Επιλέξτε πόλεις ή συγκεκριμένες περιοχές","specialist_setup.done.title":"Το προφίλ σας είναι έτοιμο!","specialist_setup.done.subtitle":"Συγχαρητήρια! Το προφίλ σας έχει ρυθμιστεί","specialist_setup.done.desc":"Τώρα μπορείτε να λαμβάνετε παραγγελίες από πελάτες. Αναζητήστε εργασίες που ταιριάζουν με τις δεξιότητές σας."},en:{"footer.slogan":"Your task — our care! We solve any issue quickly and easily.","footer.links":"Links","footer.socials":"Socials","nav.home":"Home","nav.tasks":"Tasks","nav.post":"+ Post task","nav.dashboard":"Dashboard","nav.chat":"Messages","nav.notifications":"Notifications","nav.profile":"Profile","nav.admin":"Admin Panel","nav.specialists":"Specialists","nav.new_task":"New task","nav.login":"Login","nav.register":"Register","nav.logout":"Logout","hero.title":"Find a specialist for any job","hero.subtitle":"Post a task, receive offers and choose the best professional","hero.cta.post":"Post a task","hero.cta.browse":"Become a specialist","hero.search.placeholder":"What do you need? e.g. electrician, cleaning...","stats.specialists":"specialists","stats.tasks":"tasks","stats.categories":"categories","stats.free":"free sign-up","section.categories":"Create a task in any category","section.how":"How it works","section.recent":"Recent tasks","section.all":"See all →","section.more":"more","section.cities":"Cities & Districts","section.community":"A community project for everyone","community.subtitle":"CanHelp is not just a marketplace — it's a community of mutual help. Anyone with knowledge or a skill can find a client. Anyone with a problem can find a specialist.","community.point1.title":"Are you good at something?","community.point1.desc":"Repairs, tutoring, design, translation, care — every skill has value. Create a profile and find clients near you.","community.point2.title":"Need help with something?","community.point2.desc":"Post a task in under a minute and receive offers from verified specialists in your city.","community.point3.title":"Help the project grow","community.point3.desc":"CanHelp grows through communities. Share the link with friends and acquaintances — together we build something useful for everyone.","community.share":"Share with friends","community.share.copied":"Link copied!","section.referral":"Referral Program","referral.home.subtitle":"Share your link — every new user who signs up through it earns you a reward.","referral.home.step1.title":"Sign up and get your link","referral.home.step1.desc":"Create an account and find your unique referral link in your profile.","referral.home.step2.title":"Share with friends","referral.home.step2.desc":"Send the link to friends, acquaintances, or post it on social media.","referral.home.step3.title":"Earn rewards","referral.home.step3.desc":"Once your friend verifies their email, you automatically receive your reward.","referral.home.cta":"Get your link","referral.home.badge":"Referral Program","section.faq":"Frequently Asked Questions","faq.q1":"How does CanHelp work?","faq.a1":"Post a task, receive offers from specialists, choose the best one and start working together. It's fast, simple and free for customers.","faq.q2":"How much does it cost to use the platform?","faq.a2":"Registration and task posting is completely free for customers. Specialists have access to a free plan as well as premium options.","faq.q3":"How can I become a specialist?","faq.a3":"Register, go to \xabBecome a Specialist\xbb, fill in your profile with skills and categories, and start receiving tasks.","faq.q4":"How do I choose the right specialist?","faq.a4":"Check their reviews, experience, skills and portfolio. Chat with them through the platform and discuss the details before deciding.","faq.q5":"What if I am not satisfied?","faq.a5":"You can leave a review about the specialist and rate them from 1 to 5 stars. Reviews help other users find trusted professionals.","faq.q6":"Can I contact a specialist before accepting their offer?","faq.a6":"Yes. Once you receive an offer, you can open a chat with the specialist, ask questions and discuss all the details before making a decision.","faq.q7":"How long does it take to receive offers?","faq.a7":"Usually within a few hours. Specialists get notified about new tasks and can respond quickly.","faq.q8":"Can I post a task in any city in Greece?","faq.a8":"Yes! CanHelp covers all of Greece — Athens, Thessaloniki, Patras and more.","faq.q9":"What types of tasks can I find on CanHelp?","faq.a9":"Repairs, cleaning, electricians, tutoring, design, IT, moving, beauty and much more. Categories are constantly expanding.","faq.q10":"Is there a mobile app?","faq.a10":"Yes! CanHelp is available for Android and iOS. Download the app and manage everything from your phone.","how.step1.title":"Post a task","how.step1.desc":"Describe what you need and set your budget","how.step2.title":"Receive offers","how.step2.desc":"Specialists will send you offers with price and timeline","how.step3.title":"Choose & start","how.step3.desc":"Pick the best professional and start the collaboration","tasks.title":"tasks","tasks.filters":"Filters","tasks.search":"Search","tasks.search.placeholder":"Title or keyword...","tasks.search.btn":"Search","tasks.publish":"Post","tasks.category.all":"All","tasks.category.all_in":"All in","tasks.category.label":"Category","tasks.location.label":"City","tasks.location.placeholder":"e.g. Athens","tasks.empty":"No tasks found","tasks.empty.cta":"Post the first one","task.status.open":"Open","task.status.in_progress":"In progress","task.status.completed":"Completed","task.status.cancelled":"Cancelled","task.status.draft":"Draft","task.budget":"Budget","task.location":"Location","task.deadline":"Start date","task.created_at":"Created","task.customer":"Customer","task.offer.btn":"Submit offer","task.invite.banner_title":"You've been invited to this task","task.invite.banner_hint":"The customer personally invited you","task.invite.accept":"Send offer","task.invite.decline":"Decline","offer.accept":"Accept","offer.decline":"Decline","task.complete":"Complete task","task.complete.confirm":"Mark this task as complete?","task.edit":"Edit","task.status_label":"Status","task.yours":"Your task","task.offer.yours":"Your offer","review.leave":"Leave a review","review.rating":"Rating","review.comment":"Comment","review.comment.placeholder":"Tell us about your experience...","review.submit":"Submit review","review.submitting":"Submitting...","review.done":"Review submitted!","profile.reviews":"Reviews","profile.no_reviews":"No reviews yet","profile.rating":"Rating","profile.skills.label":"Skills","profile.member_since":"Member since","task.offers":"Offers","task.offers.none":"No offers yet","create.title":"Post a task","create.field.title":"Title","create.field.description":"Description","create.field.category":"Category","create.field.category.select":"Select...","create.field.location":"Location","create.field.location.any":"Anywhere","create.field.location.all":"Entire city","create.field.budget":"Budget (€)","create.field.deadline":"Start date","create.field.budget_negotiable":"Price is negotiable","create.field.time_slot":"Time slot","create.field.time_slot.any":"Anytime","create.field.time_slot.morning":"Morning (08:00–13:00)","create.field.time_slot.afternoon":"Afternoon (13:00–18:00)","create.field.time_slot.evening":"Evening (18:00–22:00)","create.field.time_slot.weekend":"Weekend","create.field.address":"Address (optional)","create.field.address.district":"District","create.field.address.street":"Street","create.field.address.house":"Number","create.field.confidential":"Confidential note","create.field.confidential.placeholder":"Details visible only to the assigned specialist...","create.field.confidential.hint":"Not shown publicly","create.field.photos":"Photos","create.field.photos.add":"Add photo","create.field.photos.uploading":"Uploading...","task.budget_negotiable":"Price negotiable","task.time_slot":"Time slot","task.confidential":"Confidential note","create.field.title.placeholder":"e.g. Clean 80sqm apartment","create.field.description.placeholder":"Describe in detail what you need...","create.field.location.placeholder":"e.g. Athens, Kolonaki","create.field.budget.placeholder":"e.g. 100","create.submit":"Post task","create.submitting":"Posting...","login.title":"Welcome back","login.subtitle":"Sign in to CanHelp","login.email":"Email","login.password":"Password","login.submit":"Sign in","login.submitting":"Signing in...","login.error":"Invalid email or password","login.unverified.title":"Verify your email address","login.unverified.desc":"We sent a verification link to your email. Check your inbox (or spam) and click the link.","login.unverified.resend":"Resend verification email","login.unverified.sending":"Sending...","login.unverified.sent":"✓ Sent — check your inbox","profile.email.verified":"Email verified","profile.email.not_verified":"Email not verified","login.no_account":"Don't have an account?","login.register_link":"Register","login.forgot_password":"Forgot password?","login.or_continue_with":"or continue with","login.continue_google":"Continue with Google","forgot.title":"Forgot password","forgot.subtitle":"Enter your email to receive a reset link","forgot.email":"Email","forgot.submit":"Send reset link","forgot.submitting":"Sending...","forgot.sent.title":"Check your inbox","forgot.sent.desc":"If an account exists with that email, we'll send you a password reset link.","forgot.back_to_login":"Back to sign in","forgot.error":"Could not send reset link. Check the email address and try again.","forgot.error.not_found":"No account found with this email address.","forgot.error.send_failed":"Failed to send email. Please try again later.","reset.title":"New password","reset.subtitle":"Enter your new password","reset.password":"New password","reset.confirm":"Confirm password","reset.submit":"Change password","reset.submitting":"Saving...","reset.success":"Password changed successfully. Redirecting to sign in...","reset.back_to_login":"Back to sign in","reset.error.mismatch":"Passwords do not match","reset.error.invalid":"Invalid or expired link. Please request a new one.","register.title":"Register","register.subtitle":"Create a CanHelp account","register.first_name":"First name","register.last_name":"Last name","register.email":"Email","register.password":"Password (min 8 characters)","register.role":"Role","register.role.customer":"User","register.role.customer.desc":"I post tasks","register.role.specialist":"Specialist","register.role.specialist.desc":"I take on tasks","register.submit":"Create account","register.submitting":"Registering...","register.has_account":"Already have an account?","register.login_link":"Sign in","register.continue_google":"Continue with Google","register.check_email.title":"Check your email","register.check_email.desc":"We sent a verification link to your email address. Check your inbox (or spam) and click the link.","register.check_email.login":"Back to sign in","dashboard.title":"Dashboard","dashboard.new_task":"+ New task","dashboard.my_tasks":"My tasks","dashboard.my_offers":"My offers","dashboard.invitations":"Job invitations","dashboard.offers_count":"offers","dashboard.declined_count":"declined","dashboard.completed_tasks":"Completed tasks","dashboard.completed_offers":"Completed offers","dashboard.review_pending":"Review not yet submitted","tasks.new.top_specialists":"Top specialists","tasks.new.select_category":"Select a category to see matching specialists","tasks.new.invite":"Offer work","tasks.new.invited":"Selected ✓","reviews.count":"reviews","filter.location":"Location","filter.language":"Languages","filter.language.any":"Any language","filter.category.all":"All categories","user.categories":"Categories","user.work_area":"Work area","dashboard.tasks.empty":"You haven't posted any tasks","dashboard.tasks.empty.cta":"Post your first one","dashboard.tasks.add_new":"Add a new task","dashboard.offers.empty":"You haven't submitted any offers","dashboard.offers.empty.cta":"Find tasks","dashboard.customer.specialists_title":"Looking for a specialist?","dashboard.customer.specialists_hint":"Browse specialist profiles, read reviews and invite them to your tasks","dashboard.customer.specialists_cta":"Find a specialist","dashboard.customer.how_title":"How it works","dashboard.customer.step1":"Create a task with a description and budget","dashboard.customer.step2":"Specialists will send offers with price and timeline","dashboard.customer.step3":"Choose the right one and start working","notif.title":"Notifications","notif.mark_all":"Mark all as read","notif.empty":"No notifications","notif.type.new_offer":"New offer","notif.type.offer_accepted":"Your offer was accepted","notif.type.offer_declined":"Your offer was declined","notif.type.task_completed":"Task completed","notif.type.task_cancelled":"Task cancelled","notif.type.new_message":"New message","notif.type.new_review":"New review","notif.type.task_invite":"Job invitation","notif.body.new_offer":"New offer for \xab{title}\xbb","notif.body.offer_accepted":"Your offer for \xab{title}\xbb was accepted","notif.body.offer_declined":"Your offer for \xab{title}\xbb was declined","notif.body.task_invite":"You've been invited for \xab{title}\xbb","notif.body.new_review":"You received a {rating}★ review","offer.status.pending":"Pending","offer.status.accepted":"Accepted","offer.status.declined":"Declined","offer.status.withdrawn":"Withdrawn","offer.status.other_accepted":"Another specialist was chosen","common.loading":"Loading...","common.error":"Error","common.save":"Save","common.saving":"Saving...","common.cancel":"Cancel","common.add":"Add","common.close":"Close","common.edit":"Edit","common.delete":"Delete","common.from":"by","common.currency":"€","common.greece":"Greece","chat.connected":"Connected","chat.disconnected":"Disconnected","chat.no_rooms":"No conversations yet","chat.task_fallback":"Task","chat.select":"Select a conversation","chat.no_messages":"No messages yet","chat.placeholder":"Write a message... (Enter to send)","chat.conversation_fallback":"Conversation","chat.direct_chat":"Direct chat","chat.linked_task":"Linked task","chat.write_btn":"Message","chat.just_now":"just now","chat.min_ago":"m","chat.write_specialist":"Write to specialist","chat.write_customer":"Write to customer","chat.notif_settings":"Notification settings","chat.notif_messages":"Notifications for new messages","chat.toast_title":"New message","chat.toast_open":"Open chat","offer.price":"Price","offer.price.placeholder":"e.g. 80","offer.customer_budget":"Client budget","offer.message":"Message","offer.optional":"optional","offer.message.placeholder":"Introduce yourself, your experience and why you are the best choice...","offer.submitting":"Sending...","profile.photo":"Profile photo","profile.photo.change":"Change photo","profile.photo.hint":"JPEG, PNG, WebP \xb7 up to 5MB","profile.basic_info":"Basic info","profile.phone":"Phone","profile.phone.placeholder":"+30 6901234567","profile.bio":"Short bio","profile.bio.placeholder":"Tell us a bit about yourself...","profile.language":"Language","profile.language.hint":"App interface and email notification language","profile.languages":"Languages spoken","profile.languages.hint":"Select all languages you speak","profile.skills":"Skills","profile.skills.subtitle":"Add the services you offer","profile.skills.placeholder":"e.g. Cleaning, IT, Tutoring...","profile.role":"Account role","profile.role.specialist":"\uD83D\uDD27 Specialist","profile.role.admin":"\uD83D\uDC51 Admin","profile.role.customer":"\uD83D\uDC64 User","profile.role.change":"To change your role please contact support.","profile.become_specialist":"Become a Specialist","profile.become_specialist.desc":"Upgrade to Specialist to take on tasks and build your profile.","become_specialist.hero.title":"Earn money doing what you do best","become_specialist.hero.subtitle":"Create a specialist profile and receive orders from clients across Greece","become_specialist.how.title":"How it works","become_specialist.step1.title":"Create a specialist portfolio","become_specialist.step1.desc":"Set your categories, skills and coverage areas — the system will automatically match you with relevant tasks","become_specialist.step2.title":"Find tasks","become_specialist.step2.desc":'Discover tasks in your categories in the "Find Orders" section',"become_specialist.step3.title":"Send an offer & earn","become_specialist.step3.desc":"Submit offers with price and timeline, chat with clients and complete tasks","become_specialist.benefits.title":"Specialist profile advantages","become_specialist.benefit1":"Task search filtered by your categories and location","become_specialist.benefit2":"Public profile with client reviews","become_specialist.benefit3":"Availability schedule visible to clients","become_specialist.benefit4":"Saved to favourites by clients","become_specialist.cta":"Learn more","become_specialist.free_badge":"Free registration","profile.tab.notifications":"Notifications","profile.tab.reviews":"Reviews","profile.tab.referral":"Referrals","profile.tab.auto_response":"Auto-response","profile.tab.site":"Site","profile.site.title":"Personal page","profile.site.url_label":"Personal site","profile.site.copy":"Copy","profile.site.copied":"Copied","profile.site.visible_title":"What's on your page","profile.site.visible.name":"Name and photo","profile.site.visible.bio":"Bio","profile.site.visible.rating":"Rating and reviews","profile.site.visible.portfolio":"Portfolio / Cards","profile.site.visible.contacts":"Contact info","profile.site.visible.full_last_name":"Full last name","profile.site.visible.services":"Service cards","profile.site.visible.reviews":"Reviews section","profile.site.visible.status":'"Ready to help" status',"profile.site.theme":"Appearance theme","profile.site.theme.dark":"Dark","profile.site.theme.light":"Light","profile.site.slug_taken":"This address is already taken","profile.site.stats.title":"Site analytics","profile.site.stats.days":"last 30 days","profile.site.stats.views":"Views","profile.site.stats.unique":"Unique visitors","profile.site.stats.messages":"Messages","profile.site.stats.total_views":"Total views","profile.site.stats.total_unique":"Unique visitors","profile.site.stats.total_messages":"Messages","profile.site.stats.empty":"No data yet","profile.site.stats.loading":"Loading analytics...","profile.site.stats.no_slug":"Set your site URL to see analytics","profile.site.edit_bio_hint":'Bio and photo are edited in the "Basic info" tab.',"status.title":"Status","status.can_help_now_hint":"Your card is shown higher in search","status.need_help_hint":"Specialists can offer you help","profile.referral.title":"Referral program","profile.referral.desc":"Share your link and earn rewards for every new user you invite.","profile.referral.link_label":"Your referral link","profile.referral.copy":"Copy","profile.referral.copied":"Copied!","profile.referral.invited_count":"successful referrals","profile.referral.no_code":"Referral code is not available.","notifications.title":"Notification settings","notifications.email.new_tasks":"Email for new tasks","notifications.email.new_tasks.desc":"Receive an email when a new task is posted in your categories","notifications.messages.desc":"Receive a notification when a new message arrives","notifications.saved":"Settings saved","notifications.plan_required":"Not available in your plan","profile.tab.info":"Basic info","profile.tab.finance":"Finance","profile.tab.skills":"Skills","profile.tab.categories":"Categories","profile.tab.geography":"Geography","profile.specialist.categories":"Work categories","profile.specialist.categories.desc":"Select the categories you work in","profile.specialist.geography":"Coverage areas","profile.specialist.geography.desc":"Select the cities / districts where you are active","profile.saving":"Saving...","profile.upload.error":"Error uploading photo","profile.saved":"Saved","profile.tab.cards":"Portfolio","profile.cards.count":"Portfolio","profile.cards.add":"Add portfolio","profile.cards.new_title":"New portfolio title","profile.cards.placeholder":"e.g. Plumbing","profile.cards.create":"Create","profile.cards.cancel":"Cancel","profile.cards.empty":"No portfolio yet","profile.cards.create_first":"Create your first portfolio","profile.cards.delete_confirm":"Delete portfolio?","profile.card.tab.main":"General","profile.card.tab.skills":"Skills","profile.card.tab.categories":"Categories","profile.card.tab.geography":"Geography","profile.card.tab.portfolio":"Portfolio","profile.card.active":"Active","profile.card.save":"Save","profile.card.saved":"Saved","profile.card.delete":"Delete","profile.card.skill.add":"Add skill","profile.card.photo.add":"Add photo","profile.card.photo.uploading":"Uploading...","profile.card.photo.empty":"No photos yet","profile.card.item.title":"Title","profile.card.item.desc":"Description","profile.card.item.save":"Save","profile.card.item.cancel":"Cancel","profile.card.item.edit":"Edit","profile.upgrade.cards_limit":"Portfolio limit reached","profile.upgrade.plan":"Current plan:","profile.upgrade.contact":"Contact the administrator to change your plan","profile.upgrade.ok":"Got it","profile.plan.title":"Subscription plan","profile.balance":"Balance","profile.balance.topup":"Top Up Balance","profile.balance.topup.title":"Top Up Balance","profile.balance.topup.amount":"Amount (EUR)","profile.balance.topup.hint":"Choose a preset or enter a custom amount","profile.balance.topup.submit":"Proceed to Payment","profile.balance.topup.loading":"Redirecting...","profile.balance.topup.error":"Payment initiation failed. Please try again.","payment.success.title":"Payment Successful!","payment.success.desc":"Your balance has been updated.","payment.cancelled.title":"Payment Cancelled","payment.cancelled.desc":"Payment was cancelled. No charges were made.","payment.pending.title":"Processing...","payment.pending.desc":"Your payment is being processed.","payment.back_to_profile":"Back to Profile","profile.plan.basic":"Basic (free)","profile.plan.contact_upgrade":"Contact admin to upgrade your plan","profile.plan.cards_up_to":"Portfolio: up to","profile.plan.cards_unlimited":"Portfolio: unlimited","profile.plan.tasks_up_to":"Tasks: up to","profile.plan.offers_up_to":"Offers: up to","profile.plan.valid_until":"Valid until","profile.plan.no_expiry":"No expiry","create.error":"Error posting task","tasks.category.general":"General","tasks.budget.range":"Range:","tasks.budget.from":"from","tasks.budget.to":"to","tasks.filter.reset":"Reset filters","tasks.load_more":"Load more","tasks.showing":"Results:","tasks.field.budget":"Budget, €","admin.title":"Admin Panel","admin.tab.stats":"Statistics","admin.tab.users":"Users","admin.tab.tasks":"Tasks","admin.tab.reports":"Reports","admin.stats.users":"Users","admin.stats.tasks":"Tasks","admin.stats.offers":"Offers","admin.stats.reviews":"Reviews","admin.tasks.by_status":"Tasks by status","admin.col.user":"User","admin.col.email":"Email","admin.col.role":"Role","admin.col.registered":"Registered","admin.col.status":"Status","admin.col.title":"Title","admin.col.budget":"Budget","admin.col.created":"Created","admin.users.active":"Active","admin.users.inactive":"Inactive","admin.users.deactivate":"Deactivate","admin.users.activate":"Activate","admin.tasks.cancel":"Cancel","admin.reports.none":"No reports","admin.reports.reviewed":"Reviewed","admin.reports.dismiss":"Dismiss","admin.pagination.total":"Total","admin.users.role.change":"Change role","admin.users.search.placeholder":"Search name or email...","admin.tasks.delete":"Delete","admin.tasks.delete.confirm":"Permanently delete this task?","admin.tasks.search.placeholder":"Search title...","admin.col.customer":"Customer","admin.col.reporter":"Reporter","admin.col.target":"Target","admin.filter.all_roles":"All roles","admin.filter.all_statuses":"All statuses","admin.reports.target.task":"Task","admin.reports.target.user":"User","admin.tab.categories":"Categories","admin.tab.locations":"Cities & Districts","admin.tab.logs":"Logs","admin.tab.plans":"Plans","admin.tab.settings":"Settings","admin.logs.subtab.ai":"AI Logs","admin.logs.subtab.activity":"Activity","admin.logs.subtab.mail":"Mail","admin.logs.subtab.notifications":"Notifications","admin.notif_logs.type":"Type","admin.notif_logs.title":"Title","admin.notif_logs.read":"Read","admin.notif_logs.empty":"No notification logs","admin.stats.notif_chart_title":"Notifications per day","admin.stats.notif_label":"Notifications","admin.stats.mail_chart_title":"Emails per day","admin.stats.mail_label":"Emails","admin.filter.all":"All","admin.stats.specialists":"Specialists","admin.col.plan":"Plan","admin.back_home":"Home","admin.plans.title":"Subscription plans","admin.plans.add":"+ New plan","admin.plans.empty":"No plans created","admin.plans.form.new":"New plan","admin.plans.form.edit":"Edit plan","admin.plans.form.name":"Name","admin.plans.form.price":"Price (EUR)","admin.plans.form.old_price":"Old price (EUR, optional)","admin.plans.form.max_offers":"Max offers (empty = no limit)","admin.plans.form.max_cards":"Max portfolio (empty = no limit)","admin.plans.form.duration_days":"Duration (days, empty = no expiry)","admin.plans.form.description":"Description","admin.plans.form.features":"Features (one per line)","admin.plans.form.notify":"Notify about new tasks","admin.plans.form.default":"Default","admin.plans.form.active":"Active","admin.plans.form.order":"Order","admin.plans.form.role":"Role","admin.plans.form.tier":"Tier","admin.plans.form.role.customer":"Customer","admin.plans.form.role.specialist":"Specialist","admin.plans.form.tier.free":"Free","admin.plans.form.tier.pro":"Pro","admin.plans.form.tier.ultimate":"Ultimate","admin.plans.form.section.limits":"Limits (empty = unlimited)","admin.plans.form.max_messages_day":"Max Messages/Day","admin.plans.form.max_orders_day":"Max Orders/Day","admin.plans.form.max_skills":"Max Skills","admin.plans.form.max_profiles":"Max Profiles","admin.plans.form.max_portfolio":"Max Portfolio Items","admin.plans.form.section.boost":"Multipliers & Boost","admin.plans.form.search_boost":"Search Boost","admin.plans.form.offers_multiplier":"Offers Multiplier","admin.plans.form.section.contact":"Contact Permissions","admin.plans.form.can_contact_free":"Contact Free Plan users","admin.plans.form.can_contact_pro":"Contact Pro Plan users","admin.plans.form.can_contact_all":"Contact All users","admin.plans.form.can_show_contact":"Show Contact Info","admin.plans.form.can_view_phone":"View Phone","admin.plans.form.section.features":"Feature Flags","admin.plans.form.upload_video":"Upload Video","admin.plans.form.favorites":"Favorites","admin.plans.form.google_calendar":"Google Calendar","admin.plans.form.verified_badge":"Verified Badge","admin.plans.form.highlighted_reviews":"Highlighted Reviews","admin.plans.form.personal_site":"Personal Site","admin.plans.form.can_help_now":"Can Help Now Status","admin.plans.form.need_help":"Need Help Status","admin.plans.form.auto_response":"Auto Response","admin.plans.form.auto_match":"Auto Match","admin.plans.form.instant_dispatch_free":"Instant Dispatch (Free)","admin.plans.form.instant_dispatch_pro":"Instant Dispatch (Pro)","admin.plans.badge.default":"Default","admin.plans.badge.inactive":"Inactive","admin.plans.make_default":"Set as default","admin.plans.tasks":"Tasks","admin.plans.offers":"Offers","admin.plans.cards":"Portfolio","admin.plans.notify_tasks":"Task notifications","admin.plans.delete.confirm":"Delete plan","admin.activity.title":"Activity log","admin.activity.event":"Event","admin.activity.all_events":"All events","admin.activity.from":"From","admin.activity.to":"To","admin.activity.reset":"Reset","admin.activity.total":"Total","admin.activity.empty":"No records","admin.mail.event":"Email event","admin.mail.all_events":"All email events","admin.mail.from":"From","admin.mail.to":"To","admin.mail.reset":"Reset","admin.mail.total":"Total","admin.mail.empty":"No email logs","admin.mail.recipient":"Recipient","admin.mail.provider":"Provider","admin.mail.details":"Details","admin.mail.status":"Status","admin.mail.success":"Success","admin.mail.failed":"Failed","admin.event.email_sent":"Email sent","admin.event.email_failed":"Email failed","admin.event.email_dev":"Email DEV fallback","admin.event.admin_email_test_sent":"Admin test email sent","admin.event.admin_email_test_failed":"Admin test email failed","admin.logs.empty":"No records","admin.logs.date":"Date","admin.logs.provider":"Provider","admin.logs.model":"Model","admin.logs.action":"Action","admin.logs.langs":"Languages","admin.logs.in":"In","admin.logs.out":"Out","admin.logs.total":"Total","admin.logs.ms":"ms","admin.logs.status":"Status","admin.stats.activity_30d":"Activity over 30 days","admin.stats.tasks_label":"Tasks","admin.stats.users_label":"Users","admin.stats.specialists_label":"Specialists","admin.stats.tokens_title":"Token usage (by month)","admin.stats.tokens_out":"Output","admin.stats.tokens_in":"Input","admin.stats.tokens_out_label":"Output tokens","admin.stats.tokens_in_label":"Input tokens","admin.stats.cost_label":"Cost (USD)","admin.stats.tasks_by_status":"Tasks by status","admin.task_status.open":"Open","admin.task_status.in_progress":"In progress","admin.task_status.completed":"Completed","admin.task_status.cancelled":"Cancelled","admin.task_status.draft":"Drafts","admin.settings.tab.general":"General","admin.settings.tab.smtp":"E-Mail","admin.settings.tab.notifications":"Notifications","admin.settings.tab.payment":"Payment","admin.settings.tab.referral":"Referrals","admin.settings.tab.seo":"SEO","admin.settings.tab.socials":"Socials","admin.settings.socials.title":"Social Network Links","admin.settings.socials.hint":"Filled links are displayed in the site footer","admin.settings.seo.maintenance_label":"Maintenance Mode","admin.settings.seo.maintenance_hint":"Show a maintenance page to all visitors","admin.settings.seo.indexing_label":"Search Engine Indexing","admin.settings.seo.indexing_hint":"Allow search engines to index the site","admin.settings.seo.head_scripts_label":" Scripts (JS)","admin.settings.seo.head_scripts_hint":"Runs on every page (Google Tag Manager, analytics, etc.)","admin.settings.seo.site_title_label":"Site Title","admin.settings.seo.site_description_label":"Site Description (meta description)","admin.settings.referral.title":"Referral program","admin.settings.referral.hint":"Reward users who bring new registrations.","admin.settings.referral.enabled_label":"Enabled","admin.settings.referral.enabled_hint":"Enable / disable reward application","admin.settings.referral.customer_section":"For customers","admin.settings.referral.specialist_section":"For specialists","admin.settings.referral.plan_label":"Reward plan","admin.settings.referral.no_plan":"— no plan —","admin.settings.referral.plan_hint":"This plan will be assigned to the referrer. If their current plan is higher, only days will be added.","admin.settings.referral.days_label":"Reward days","admin.settings.referral.days_hint":"Number of days added to the plan expiry.","admin.settings.general.title":"General settings","admin.settings.general.site_name":"Site name","admin.settings.general.site_url":"Site URL","admin.settings.general.contact_email":"Contact email","admin.settings.general.support_phone":"Support phone","admin.settings.smtp.title":"SMTP settings","admin.settings.smtp.hint":"Used to send email notifications.","admin.settings.smtp.host":"SMTP Host","admin.settings.smtp.port":"Port","admin.settings.smtp.encryption":"Encryption","admin.settings.smtp.enc.none":"None","admin.settings.smtp.enc.tls":"STARTTLS (port 587)","admin.settings.smtp.enc.ssl":"SSL/TLS (port 465)","admin.settings.smtp.username":"Username","admin.settings.smtp.password":"Password / App Password","admin.settings.smtp.from_name":"Sender name","admin.settings.smtp.from_email":"Sender email","admin.settings.smtp.test":"Send test email","admin.settings.smtp.sending":"Sending...","admin.settings.payment.hint":"ePay Piraeus Bank credentials.","admin.settings.env.test":"Test (sandbox)","admin.settings.env.prod":"Production","admin.settings.env.label":"Environment","admin.settings.merchant_id":"Merchant ID","admin.settings.api_user":"API User","admin.settings.api_password":"API Password","admin.settings.confirm_url":"Confirmation URL (webhook)","admin.settings.cancel_url":"Cancel URL","admin.settings.active":"Active","admin.settings.saving":"Saving...","admin.settings.saved":"Saved","admin.notif.vars_hint":"Available variables in templates","admin.notif.tmpl.not_set":"Template not configured","admin.notif.tmpl.subject_label":"Email subject","admin.notif.tmpl.body_label":"Email body (HTML)","admin.notif.tmpl.save":"Save","admin.notif.tmpl.close":"Close","admin.notif.tmpl.translate":"Auto-translate to other languages","admin.notif.tmpl.translating":"Translating...","admin.notif.tmpl.saving":"Saving...","admin.notif.email_verification":"Email verification","admin.notif.registration_success":"Successful registration","admin.notif.password_reset":"Password reset","admin.notif.new_offer":"New offer","admin.notif.new_task":"New task","admin.notif.offer_accepted":"Offer accepted","admin.notif.new_message":"New message","admin.notif.offer_declined":"Offer declined","admin.notif.offer_other_accepted":"Another specialist chosen","admin.notif.task_updated":"Task updated","admin.notif.deadline_reminder":"Deadline reminder","admin.notif.task_archived":"Task unpublished automatically","admin.notif.referral_reward":"Referral reward","admin.email_template.plan_activated":"Plan activated","admin.email_template.plan_upgraded":"Plan upgraded","admin.email_template.plan_downgrade_scheduled":"Downgrade scheduled","admin.email_template.plan_downgrade_applied":"Downgrade applied","admin.email_template.plan_renewal_reminder":"Renewal reminder","admin.email_template.plan_insufficient_funds":"Insufficient funds warning","pricing.confirm.title":"Confirm plan selection","pricing.confirm.plan":"Plan","pricing.confirm.prorated":"Prorated credit","pricing.confirm.effective_price":"Amount due","pricing.confirm.your_balance":"Your balance","pricing.confirm.downgrade_info":"The switch to the new plan will happen automatically after the current period ends.","pricing.confirm.insufficient":"Insufficient balance.","pricing.confirm.top_up":"Top up","pricing.confirm.schedule_downgrade":"Schedule downgrade","pricing.confirm.pay":"Pay","admin.user_edit.title":"Edit user","admin.user_edit.email":"Email","admin.user_edit.email_verified":"Email verified","admin.user_edit.email_not_verified":"Email not verified","admin.user_edit.verify_email_btn":"Verify manually","admin.user_edit.verify_email_done":"Email verified!","admin.user_edit.id":"ID","admin.user_edit.registered":"Registered","admin.user_edit.last_seen":"Last seen","admin.user_edit.lang":"Language","admin.user_edit.first_name":"First name","admin.user_edit.last_name":"Last name","admin.user_edit.phone":"Phone","admin.user_edit.bio":"Bio","admin.user_edit.role":"Role","admin.user_edit.plan":"Plan","admin.user_edit.no_plan":"— No plan —","admin.user_edit.active":"Active account","admin.user_edit.balance":"Balance (EUR)","admin.user_edit.skills":"Skills","admin.user_edit.tab.profile":"Profile","admin.user_edit.tab.account":"Account","admin.user_edit.tab.balance":"Balance","admin.user_edit.tab.settings":"Settings","admin.user_edit.tab.specialist":"Portfolio","admin.user_edit.tab.site":"Website","admin.user_edit.plan_expires":"Plan expires","admin.user_edit.interface_lang":"Interface language","admin.user_edit.comm_languages":"Communication languages","admin.user_edit.personal_site_slug":"Personal page","admin.user_edit.show_contact_info":"Show contact info","admin.user_edit.show_contact_info.hint":"Visible to customers","admin.user_edit.notify_new_tasks":"Notify about new tasks","admin.user_edit.notify_new_tasks.hint":"Push and email notifications","admin.user_edit.notif_messages":"Message notifications","admin.user_edit.notif_messages.hint":"New messages in chat","admin.user_edit.site_settings":"Personal page settings","admin.user_edit.categories":"Service categories","admin.user_edit.locations":"Service areas","admin.user_edit.skill_placeholder":"New skill...","admin.user_edit.add_category":"— Select category —","admin.user_edit.add_location":"— Select location —","admin.user_edit.specialist_cards":"Portfolio","admin.user_edit.no_cards":"No portfolio found","admin.user_edit.card_title":"Portfolio title","admin.user_edit.card_description":"Description","admin.balance.topup.btn":"Top up","admin.balance.withdraw.btn":"Withdraw","admin.balance.modal_hint":"Changes take effect immediately and are recorded in history","admin.balance.topup.title":"Top up balance","admin.balance.topup.amount":"Amount","admin.balance.topup.description":"Comment","admin.balance.topup.description.placeholder":"For example: bonus or manual top-up","admin.balance.topup.submit":"Top up balance","admin.balance.withdraw.title":"Withdraw balance","admin.balance.withdraw.amount":"Amount","admin.balance.withdraw.description":"Comment","admin.balance.withdraw.description.placeholder":"For example: refund or manual debit","admin.balance.withdraw.submit":"Withdraw from balance","admin.user_edit.role.customer":"Customer","admin.user_edit.role.specialist":"Specialist","admin.user_edit.role.admin":"Administrator","common.refresh":"Refresh","common.back_home":"Home","admin.loc.hint":"Manage cities and districts","admin.loc.add_city":"New city","admin.loc.add_district":"Add district","admin.loc.new":"New location","admin.loc.edit":"Edit location","admin.loc.district":"district","admin.loc.empty":"No locations","admin.loc.delete.confirm":"Delete location? All districts will also be deleted.","admin.cat.add_root":"New category","admin.cat.add_sub":"Subcategory","admin.cat.edit":"Edit","admin.cat.delete":"Delete","admin.cat.delete.confirm":"Delete category? All subcategories will also be deleted.","admin.cat.slug":"Slug","admin.cat.icon":"Icon","admin.cat.name_el":"Greek","admin.cat.name_en":"English","admin.cat.name_ru":"Russian","admin.cat.order":"Order","admin.cat.active":"Active","admin.cat.parent":"Parent category","admin.cat.no_parent":"Top level","admin.cat.save":"Save","admin.cat.cancel":"Cancel","admin.cat.empty":"No categories","admin.cat.hint":"Manage categories with multi-level hierarchy","admin.cat.new":"New category","admin.cat.subcategory":"subcategory","admin.cat.add_child":"Add subcategory","admin.cat.inactive":"Inactive","admin.event.user_login":"Login","admin.event.user_register":"Registration","admin.event.admin_user_deactivate":"User blocked","admin.event.admin_user_activate":"User activated","admin.event.admin_user_role_changed":"Role changed","admin.event.admin_task_cancelled":"Task cancelled","admin.event.admin_task_deleted":"Task deleted","admin.event.admin_report_reviewed":"Report reviewed","admin.event.admin_report_dismissed":"Report dismissed","admin.event.task_created":"Task created","user.online":"Online","user.seen_minutes":"was here {n} min ago","user.seen_hours":"was here {n} hr ago","user.seen_yesterday":"was here yesterday","user.seen_days":"was here {n} days ago","specialists.title":"Specialists","specialists.search":"Search specialist...","specialists.search.btn":"Search","specialists.empty":"No specialists found","specialists.no_bio":"No description","specialists.view":"View profile","specialists.reviews":"reviews","specialist.favorite":"Add to favorites","specialist.unfavorite":"Remove from favorites","specialist.site_link":"Personal site","favorites.specialists.title":"Favourite specialists","favorites.specialists.empty":"No favourite specialists yet","nav.favorites":"Favourites","nav.schedule":"Schedule","nav.find_tasks":"Find Orders","schedule.title":"My Schedule","schedule.subtitle":"Mark the days when you are free or busy — clients will see your availability","schedule.available":"Available","schedule.busy":"Busy","schedule.unset":"Not set","schedule.click_hint":"← click to cycle status","schedule.range_mode":"Select range","schedule.range_from":"From {date} — select end date","schedule.click_to_set":"Click to set","schedule.free":"free","schedule.busy_count":"busy","schedule.free_days":"free days","schedule.googleCalendar":"Google Calendar","schedule.connectGoogle":"Connect Google Calendar","schedule.disconnectGoogle":"Disconnect","schedule.connectedAs":"Connected as","schedule.importFromGoogle":"Sync from Google","schedule.gcalConnected":"✓ Google Calendar connected","schedule.gcalError":"Google Calendar connection error","schedule.gcalImportDone":"Imported {n} days from Google Calendar","schedule.gcalAutoSyncNote":"Availability changes are automatically synced to Google Calendar","schedule.gcalConnectDesc":"Connect Google Calendar to automatically sync your availability","schedule.gcalDisconnectConfirm":"Disconnect Google Calendar?","find_tasks.title":"Find Orders","find_tasks.for_me":"For me","find_tasks.all":"All orders","find_tasks.by_category":"By category","find_tasks.list":"List","find_tasks.already_offered":"Offer sent","find_tasks.offer_now":"Make an offer","find_tasks.empty_for_me":"No tasks found in your categories","find_tasks.banner_hint":"Find tasks matching your portfolio categories","find_tasks.no_cards":"Create a specialist portfolio to see tasks matched to you","find_tasks.add_card":"Create portfolio","find_tasks.search":"Search tasks...","find_tasks.tasks_count":"tasks","footer.tagline":"The task platform for Greece","footer.rights":"All rights reserved.","app.download_title":"Download the CanHelp mobile app","app.download_desc":"All of CanHelp — always at your fingertips. Available for Android and iOS.","nav.pricing":"Pricing","pricing.title":"Pricing","pricing.subtitle":"Choose the right plan for you","pricing.role.customer":"Customer","pricing.role.specialist":"Specialist","pricing.free":"Free","pricing.per_month":"mo","pricing.duration":"Duration","pricing.days":"days","pricing.current_plan":"Your plan","pricing.popular":"Popular","pricing.choose":"Choose","pricing.your_plan":"Active plan","pricing.free_default":"Default","pricing.compare":"Compare features","pricing.feature":"Feature","pricing.faq_note":"Payment is deducted from your CanHelp balance. Top up available in Payments.","pricing.feat.messages":"Messages / day","pricing.feat.orders":"Orders / day","pricing.feat.contact_all":"Contact everyone","pricing.feat.view_phone":"View phone number","pricing.feat.show_contact":"Show contact info","pricing.feat.favorites":"Favorites","pricing.feat.verified_badge":"Verified badge","pricing.feat.google_calendar":"Google Calendar","pricing.feat.personal_site":"Personal site","pricing.feat.auto_response":"Auto-response","pricing.feat.auto_match":"Auto-match","pricing.feat.highlighted_reviews":"Highlighted reviews","pricing.feat.portfolio":"Portfolio items","pricing.feat.cards":"Specialist cards","pricing.feat.notify_tasks":"New task notifications","pricing.feat.video":"Video in portfolio","upgrade.available_in":"Available in","upgrade.cta":"Upgrade","dashboard.plan.title":"My Plan","dashboard.plan.expires":"Expires in {n} days","dashboard.plan.upgrade":"Upgrade plan","dashboard.plan.no_plan":"Free plan","dashboard.plan.messages":"Messages today","dashboard.plan.orders":"Orders today","dashboard.plan.limits":"Daily limits","dashboard.plan.features":"Features","dashboard.plan.stats":"Stats","dashboard.stats.cards":"Portfolios","dashboard.stats.maxCards":"Max portfolios","dashboard.stats.portfolioItems":"Portfolio items","dashboard.stats.maxPortfolioItems":"Max items","dashboard.stats.activeOffers":"Active offers","dashboard.stats.reviewsReceived":"Reviews","dashboard.stats.activeTasks":"Active tasks","dashboard.stats.completedTasks":"Completed","status.need_help":"I need help","status.active":"Active","status.toggle_on":"Enable","status.toggle_off":"Disable","fomo.missed_orders":"Missed {n} orders","fomo.missed_value":"Worth €{v}","fomo.upgrade_hint":"Upgrade to receive more orders","fomo.conversion":"Task conversion","fomo.active":"Active","fomo.with_offers":"With offers","fomo.completed":"Completed","fomo.already_offered":"{n} specialists have already responded","fomo.specialist_missed":"You missed {n} orders","fomo.top_categories":"Categories","fomo.offers_received":"offers received","fomo.avg_offers":"Avg {n}/task","fomo.completion_rate":"completed","task.auto_match":"Auto-match","task.auto_match_results":"Top specialists","task.no_offer_yet":"You haven't sent an offer yet","task.make_offer":"Send offer","auto_response.title":"Auto-Response","auto_response.enabled":"Enable auto-response","auto_response.min_budget":"Min budget","auto_response.max_budget":"Max budget","auto_response.default_price":"Default price","auto_response.default_message":"Default message","auto_response.max_per_day":"Max auto-offers per day","auto_response.save":"Save","auto_response.saved":"Saved","auto_response.categories":"Categories","auto_response.locations":"Locations","profile.personal_site":"Personal Site","profile.site_slug":"URL slug","profile.site_slug_hint":"Only latin letters, numbers, - and _","profile.site_open":"Open site","profile.site_preview":"Your site","profile.show_contact":"Show contact info","profile.show_contact_hint":"Customers with Pro/Ultimate plans will see your phone number","gcal.upgrade_required":"Google Calendar requires a Pro or Ultimate plan","chat.limit_warning":"{n} messages left today","chat.limit_reached":"Message limit reached. Upgrade your plan","chat.upgrade":"Upgrade","site.member_since":"Member since","site.rating":"Rating","site.completed_tasks":"Completed","site.languages":"Languages","site.photos":"photos","site.contact_form":"Get in touch","site.contact_sent":"Message sent!","site.contact_sent_desc":"The specialist will contact you soon","site.contact_name":"Name","site.contact_name_ph":"Your name","site.contact_email_ph":"your@email.com","site.contact_message":"Message","site.contact_message_ph":"Describe your task...","site.contact_send":"Send","site.share":"Share","site.speaks_languages":"Speaks","site.message_sent":"Message sent!","site.message_sent_desc":"The specialist will receive it in the chat","site.message_placeholder":"Write your message...","site.write_to_chat":"Write to chat","site.auth_required_title":"Sign in required","site.auth_required_desc":"To write in the chat, you need to sign in to your CanHelp account.","site.auth_login_btn":"Sign in","site.auth_contact_form_btn":"Contact via feedback form","specialist.services":"Services","portfolio.title":"Portfolio","status.can_help_now":"Available now","common.not_found":"Page not found","common.anonymous":"Anonymous","specialist_setup.page_title":"Specialist profile setup","specialist_setup.step_of":"Step {current} of {total}","specialist_setup.next":"Next","specialist_setup.back":"Back","specialist_setup.skip":"Skip","specialist_setup.finish":"Finish","specialist_setup.go_to_profile":"Go to profile","specialist_setup.browse_tasks":"Browse tasks","specialist_setup.step1.title":"Welcome!","specialist_setup.step1.subtitle":"Let's set up your profile","specialist_setup.step1.desc":"A complete profile helps you find more clients. Follow the steps to create the perfect specialist profile.","specialist_setup.step1.what_next":"What we will do:","specialist_setup.step1.item1":"Fill in basic information","specialist_setup.step1.item2":"Create a service card","specialist_setup.step1.item3":"Add skills and categories","specialist_setup.step1.item4":"Select service area","specialist_setup.step1.item5":"Upload portfolio photos","specialist_setup.step2.title":"Basic profile","specialist_setup.step2.subtitle":"Tell us about yourself","specialist_setup.step2.bio_label":"About me","specialist_setup.step2.bio_placeholder":"Describe your experience, services you offer...","specialist_setup.step2.phone_label":"Phone","specialist_setup.step2.phone_placeholder":"+30 6900000000","specialist_setup.step2.photo_label":"Profile photo","specialist_setup.step2.photo_btn":"Upload photo","specialist_setup.step2.photo_uploading":"Uploading...","specialist_setup.step2.photo_hint":"Shown on your profile","specialist_setup.step3.title":"Service card","specialist_setup.step3.subtitle":"Create your first service card","specialist_setup.step3.title_label":"Card title","specialist_setup.step3.title_placeholder":"E.g. Plumber, Electrician, Cleaning...","specialist_setup.step3.desc_label":"Description","specialist_setup.step3.desc_placeholder":"Describe in detail what you offer, your experience, advantages...","specialist_setup.step3.title_required":"Title is required","specialist_setup.step4.title":"Skills & Categories","specialist_setup.step4.subtitle":"Add skills and select categories","specialist_setup.step4.skills_label":"Skills","specialist_setup.step4.skills_placeholder":"E.g. Pipe installation...","specialist_setup.step4.skills_add":"Add","specialist_setup.step4.categories_label":"Categories","specialist_setup.step5.title":"Service area","specialist_setup.step5.subtitle":"Where do you provide services?","specialist_setup.step5.hint":"Select cities or specific areas","specialist_setup.done.title":"Your profile is ready!","specialist_setup.done.subtitle":"Congratulations! Your profile has been set up","specialist_setup.done.desc":"You can now receive orders from clients. Browse tasks that match your skills."},ru:{"footer.slogan":"Ваша задача — наша забота! Решаем любые вопросы быстро и удобно.","footer.links":"Ссылки","footer.socials":"Мы в соцсетях","nav.home":"Главная","nav.tasks":"Задачи","nav.post":"+ Опубликовать","nav.dashboard":"Панель управления","nav.chat":"Сообщения","nav.notifications":"Уведомления","nav.profile":"Профиль","nav.admin":"Админка","nav.specialists":"Специалисты","nav.new_task":"Новая задача","nav.login":"Войти","nav.register":"Регистрация","nav.logout":"Выйти","hero.title":"Найди специалиста для любой работы","hero.subtitle":"Опубликуй задачу, получи предложения и выбери лучшего профессионала","hero.cta.post":"Опубликовать задачу","hero.cta.browse":"Стать специалистом","hero.search.placeholder":"Что нужно? напр. электрик, уборка...","stats.specialists":"специалистов","stats.tasks":"задач","stats.categories":"категорий","stats.free":"бесплатная регистрация","section.categories":"Создай задачу в любой категории","section.how":"Как это работает","section.recent":"Последние задачи","section.all":"Смотреть все →","section.more":"ещё","section.cities":"Города и районы","section.community":"Общественный проект для всех","community.subtitle":"CanHelp — не просто маркетплейс, это сообщество взаимопомощи. Любой, у кого есть знания или навык, может найти клиента. Любой, у кого есть задача, может найти специалиста.","community.point1.title":"Умеете что-то делать?","community.point1.desc":"Ремонт, репетиторство, дизайн, переводы, уход — каждый навык имеет ценность. Создайте профиль и находите клиентов рядом с вами.","community.point2.title":"Нужна помощь?","community.point2.desc":"Опубликуйте задачу за минуту и получайте предложения от проверенных специалистов в вашем городе.","community.point3.title":"Помогите проекту расти","community.point3.desc":"CanHelp развивается благодаря сообществам. Поделитесь ссылкой с друзьями и знакомыми — вместе мы строим что-то полезное для всех.","community.share":"Поделиться с друзьями","community.share.copied":"Ссылка скопирована!","section.referral":"Реферальная программа","referral.home.subtitle":"Поделитесь ссылкой — каждый новый пользователь, зарегистрировавшийся по ней, принесёт вам награду.","referral.home.step1.title":"Зарегистрируйтесь и получите ссылку","referral.home.step1.desc":"Создайте аккаунт и найдите свою уникальную реферальную ссылку в профиле.","referral.home.step2.title":"Поделитесь с друзьями","referral.home.step2.desc":"Отправьте ссылку друзьям, знакомым или опубликуйте в социальных сетях.","referral.home.step3.title":"Получайте награды","referral.home.step3.desc":"Как только друг подтвердит email, вы автоматически получите свою награду.","referral.home.cta":"Получить ссылку","referral.home.badge":"Реферальная программа","section.faq":"Частые вопросы","faq.q1":"Как работает CanHelp?","faq.a1":"Опубликуйте задачу, получите предложения от специалистов, выберите лучшего и начните сотрудничество. Это быстро, просто и бесплатно для клиентов.","faq.q2":"Сколько стоит использование платформы?","faq.a2":"Регистрация и публикация задач полностью бесплатны для клиентов. Специалисты имеют доступ к бесплатному плану, а также к премиум-опциям.","faq.q3":"Как стать специалистом?","faq.a3":"Зарегистрируйтесь, перейдите в \xabСтать специалистом\xbb, заполните профиль навыками и категориями и начните получать задачи.","faq.q4":"Как выбрать подходящего специалиста?","faq.a4":"Оцените отзывы, опыт, навыки и портфолио каждого специалиста. Общайтесь через чат платформы и уточняйте детали до принятия решения.","faq.q5":"Что если я не доволен результатом?","faq.a5":"Вы можете оставить отзыв о специалисте и поставить оценку от 1 до 5 звёзд. Отзывы помогают другим пользователям выбирать проверенных профессионалов.","faq.q6":"Можно ли связаться со специалистом до принятия предложения?","faq.a6":"Да. Как только вы получили предложение, можно открыть чат со специалистом, задать вопросы и уточнить все детали до принятия решения.","faq.q7":"Сколько времени ждать предложений?","faq.a7":"Как правило, в течение нескольких часов. Специалисты получают уведомление о новых задачах и могут быстро ответить.","faq.q8":"Можно ли разместить задачу в любом городе Греции?","faq.a8":"Да! CanHelp охватывает всю Грецию — Афины, Фессалоники, Патры и другие города.","faq.q9":"Какие виды задач есть на CanHelp?","faq.a9":"Ремонт, уборка, электрики, репетиторство, дизайн, IT, переезды, красота и многое другое. Категории постоянно расширяются.","faq.q10":"Есть ли мобильное приложение?","faq.a10":"Да! CanHelp доступно для Android и iOS. Скачайте приложение и управляйте всем со своего телефона.","how.step1.title":"Опубликуй задачу","how.step1.desc":"Опиши что нужно и установи бюджет","how.step2.title":"Получи предложения","how.step2.desc":"Специалисты пришлют предложения с ценой и сроками","how.step3.title":"Выбери и начни","how.step3.desc":"Выбери лучшего профессионала и начни сотрудничество","tasks.title":"задач","tasks.filters":"Фильтры","tasks.search":"Поиск","tasks.search.placeholder":"Название или ключевое слово...","tasks.search.btn":"Поиск","tasks.publish":"Опубликовать","tasks.category.all":"Все","tasks.category.all_in":"Все в","tasks.category.label":"Категория","tasks.location.label":"Город","tasks.location.placeholder":"напр. Афины","tasks.empty":"Задачи не найдены","tasks.empty.cta":"Опубликуй первую","task.status.open":"Открыта","task.status.in_progress":"В работе","task.status.completed":"Завершена","task.status.cancelled":"Отменена","task.status.draft":"Черновик","task.budget":"Бюджет","task.location":"Местоположение","task.deadline":"Дата начала","task.created_at":"Создано","task.customer":"Заказчик","task.offer.btn":"Отправить предложение","task.invite.banner_title":"Вас пригласили на это задание","task.invite.banner_hint":"Заказчик лично пригласил вас","task.invite.accept":"Отправить предложение","task.invite.decline":"Отказаться","offer.accept":"Принять","offer.decline":"Отклонить","task.complete":"Завершить задачу","task.complete.confirm":"Отметить задачу как выполненную?","task.edit":"Редактировать","task.status_label":"Статус","task.yours":"Ваша задача","task.offer.yours":"Ваше предложение","review.leave":"Оставить отзыв","review.rating":"Оценка","review.comment":"Комментарий","review.comment.placeholder":"Расскажите о своём опыте...","review.submit":"Отправить отзыв","review.submitting":"Отправка...","review.done":"Отзыв отправлен!","profile.reviews":"Отзывы","profile.no_reviews":"Отзывов пока нет","profile.rating":"Рейтинг","profile.skills.label":"Навыки","profile.member_since":"Участник с","task.offers":"Предложения","task.offers.none":"Предложений пока нет","create.title":"Опубликовать задачу","create.field.title":"Название","create.field.description":"Описание","create.field.category":"Категория","create.field.category.select":"Выберите...","create.field.location":"Местоположение","create.field.location.any":"Где угодно","create.field.location.all":"Весь город","create.field.budget":"Бюджет (€)","create.field.deadline":"Дата начала","create.field.budget_negotiable":"Цена обсуждается","create.field.time_slot":"Время выполнения","create.field.time_slot.any":"В любое время","create.field.time_slot.morning":"Утром (08:00–13:00)","create.field.time_slot.afternoon":"Днём (13:00–18:00)","create.field.time_slot.evening":"Вечером (18:00–22:00)","create.field.time_slot.weekend":"Выходной","create.field.address":"Адрес (необязательно)","create.field.address.district":"Квартал","create.field.address.street":"Улица","create.field.address.house":"Дом","create.field.confidential":"Конфиденциальная заметка","create.field.confidential.placeholder":"Детали, видные только назначенному специалисту...","create.field.confidential.hint":"Не отображается публично","create.field.photos":"Фотографии","create.field.photos.add":"Добавить фото","create.field.photos.uploading":"Загрузка...","task.budget_negotiable":"Цена обсуждается","task.time_slot":"Время","task.confidential":"Конфид. заметка","create.field.title.placeholder":"напр. Уборка квартиры 80кв","create.field.description.placeholder":"Подробно опишите что нужно...","create.field.location.placeholder":"напр. Афины, Колонаки","create.field.budget.placeholder":"напр. 100","create.submit":"Опубликовать задачу","create.submitting":"Публикация...","login.title":"Добро пожаловать","login.subtitle":"Вход в CanHelp","login.email":"Email","login.password":"Пароль","login.submit":"Войти","login.submitting":"Вход...","login.error":"Неверный email или пароль","login.unverified.title":"Подтвердите ваш email","login.unverified.desc":"Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.","login.unverified.resend":"Отправить письмо повторно","login.unverified.sending":"Отправка...","login.unverified.sent":"✓ Отправлено — проверьте входящие","profile.email.verified":"Email подтверждён","profile.email.not_verified":"Email не подтверждён","login.no_account":"Нет аккаунта?","login.register_link":"Зарегистрироваться","login.forgot_password":"Забыл пароль?","login.or_continue_with":"или продолжите через","login.continue_google":"Войти через Google","forgot.title":"Забыл пароль","forgot.subtitle":"Введите email для получения ссылки восстановления","forgot.email":"Email","forgot.submit":"Отправить ссылку","forgot.submitting":"Отправка...","forgot.sent.title":"Проверьте входящие","forgot.sent.desc":"Если аккаунт с таким email существует, мы отправим ссылку для сброса пароля.","forgot.back_to_login":"Вернуться ко входу","forgot.error":"Не удалось отправить ссылку. Проверьте адрес и попробуйте снова.","forgot.error.not_found":"Аккаунт с таким email не найден.","forgot.error.send_failed":"Ошибка отправки письма. Попробуйте позже.","reset.title":"Новый пароль","reset.subtitle":"Введите новый пароль","reset.password":"Новый пароль","reset.confirm":"Подтвердите пароль","reset.submit":"Изменить пароль","reset.submitting":"Сохранение...","reset.success":"Пароль успешно изменён. Перенаправление ко входу...","reset.back_to_login":"Вернуться ко входу","reset.error.mismatch":"Пароли не совпадают","reset.error.invalid":"Недействительная или устаревшая ссылка. Запросите новую.","register.title":"Регистрация","register.subtitle":"Создать аккаунт в CanHelp","register.first_name":"Имя","register.last_name":"Фамилия","register.email":"Email","register.password":"Пароль (мин. 8 символов)","register.role":"Роль","register.role.customer":"Пользователь","register.role.customer.desc":"Публикую задачи","register.role.specialist":"Специалист","register.role.specialist.desc":"Беру задачи","register.submit":"Создать аккаунт","register.submitting":"Регистрация...","register.has_account":"Уже есть аккаунт?","register.login_link":"Войти","register.continue_google":"Зарегистрироваться через Google","register.check_email.title":"Проверьте почту","register.check_email.desc":"Мы отправили ссылку для подтверждения на ваш email. Проверьте входящие (или спам) и перейдите по ссылке.","register.check_email.login":"Вернуться к входу","dashboard.title":"Панель управления","dashboard.new_task":"+ Новая задача","dashboard.my_tasks":"Мои задачи","dashboard.my_offers":"Мои предложения","dashboard.invitations":"Приглашения на задания","dashboard.offers_count":"предл.","dashboard.declined_count":"откл.","dashboard.completed_tasks":"Завершённые задачи","dashboard.completed_offers":"Завершённые предложения","dashboard.review_pending":"Оценка ещё не оставлена","tasks.new.top_specialists":"Топ специалисты","tasks.new.select_category":"Выберите категорию, чтобы увидеть специалистов","tasks.new.invite":"Предложить работу","tasks.new.invited":"Выбран ✓","reviews.count":"отзывов","filter.location":"Локация","filter.language":"Языки","filter.language.any":"Любой язык","filter.category.all":"Все категории","user.categories":"Категории","user.work_area":"Район работы","dashboard.tasks.empty":"Вы не публиковали задачи","dashboard.tasks.empty.cta":"Опубликуйте первую","dashboard.tasks.add_new":"Добавить новую задачу","dashboard.offers.empty":"Вы не отправляли предложений","dashboard.offers.empty.cta":"Найти задачи","dashboard.customer.specialists_title":"Ищете исполнителя?","dashboard.customer.specialists_hint":"Просматривайте профили специалистов, читайте отзывы и приглашайте их на свои задачи","dashboard.customer.specialists_cta":"Найти исполнителя","dashboard.customer.how_title":"Как это работает","dashboard.customer.step1":"Создайте задачу с описанием и бюджетом","dashboard.customer.step2":"Специалисты пришлют предложения с ценой и сроками","dashboard.customer.step3":"Выберите подходящего и начните работу","notif.title":"Уведомления","notif.mark_all":"Отметить все как прочитанные","notif.empty":"Нет уведомлений","notif.type.new_offer":"Новое предложение","notif.type.offer_accepted":"Ваше предложение принято","notif.type.offer_declined":"Ваше предложение отклонено","notif.type.task_completed":"Задание выполнено","notif.type.task_cancelled":"Задание отменено","notif.type.new_message":"Новое сообщение","notif.type.new_review":"Новый отзыв","notif.type.task_invite":"Приглашение на задание","notif.body.new_offer":"Новое предложение на \xab{title}\xbb","notif.body.offer_accepted":"Ваше предложение на \xab{title}\xbb принято","notif.body.offer_declined":"Ваше предложение на \xab{title}\xbb отклонено","notif.body.task_invite":"Вас приглашают на \xab{title}\xbb","notif.body.new_review":"Вы получили оценку {rating}★","offer.status.pending":"Ожидает","offer.status.accepted":"Принято","offer.status.declined":"Отклонено","offer.status.withdrawn":"Отозвано","offer.status.other_accepted":"Выбран другой исполнитель","common.loading":"Загрузка...","common.error":"Ошибка","common.save":"Сохранить","common.saving":"Сохранение...","common.cancel":"Отмена","common.add":"Добавить","common.close":"Закрыть","common.edit":"Редактировать","common.delete":"Удалить","common.from":"от","common.currency":"€","common.greece":"Греция","chat.connected":"Подключено","chat.disconnected":"Отключено","chat.no_rooms":"Переписок пока нет","chat.task_fallback":"Задача","chat.select":"Выберите переписку","chat.no_messages":"Сообщений пока нет","chat.placeholder":"Напишите сообщение... (Enter для отправки)","chat.conversation_fallback":"Переписка","chat.direct_chat":"Личный чат","chat.linked_task":"Прикреплённый заказ","chat.write_btn":"Написать","chat.just_now":"только что","chat.min_ago":"м","chat.write_specialist":"Написать специалисту","chat.write_customer":"Написать заказчику","chat.notif_settings":"Настройки уведомлений","chat.notif_messages":"Уведомления о новых сообщениях","chat.toast_title":"Новое сообщение","chat.toast_open":"Открыть чат","offer.price":"Цена","offer.price.placeholder":"напр. 80","offer.customer_budget":"Бюджет заказчика","offer.message":"Сообщение","offer.optional":"необязательно","offer.message.placeholder":"Представьтесь, расскажите об опыте и почему вы лучший выбор...","offer.submitting":"Отправка...","profile.photo":"Фото профиля","profile.photo.change":"Изменить фото","profile.photo.hint":"JPEG, PNG, WebP \xb7 до 5MB","profile.basic_info":"Основная информация","profile.phone":"Телефон","profile.phone.placeholder":"+30 6901234567","profile.bio":"Краткое описание","profile.bio.placeholder":"Расскажите немного о себе...","profile.language":"Язык","profile.language.hint":"Язык интерфейса и email-уведомлений","profile.languages":"Языки общения","profile.languages.hint":"Выберите все языки, на которых вы общаетесь","profile.skills":"Навыки","profile.skills.subtitle":"Добавьте услуги, которые вы предлагаете","profile.skills.placeholder":"напр. Уборка, IT, Репетиторство...","profile.role":"Роль аккаунта","profile.role.specialist":"\uD83D\uDD27 Специалист","profile.role.admin":"\uD83D\uDC51 Admin","profile.role.customer":"\uD83D\uDC64 Пользователь","profile.role.change":"Для смены роли обратитесь в службу поддержки.","profile.become_specialist":"Стать специалистом","profile.become_specialist.desc":"Перейдите в роль специалиста, чтобы брать задачи и наполнить профиль.","become_specialist.hero.title":"Зарабатывай, делая то, что умеешь","become_specialist.hero.subtitle":"Создай профиль специалиста и получай заказы от клиентов по всей Греции","become_specialist.how.title":"Как это работает","become_specialist.step1.title":"Создай портфолио специалиста","become_specialist.step1.desc":"Укажи категории, навыки и зону покрытия — система автоматически подберёт подходящие заказы","become_specialist.step2.title":"Ищи заказы","become_specialist.step2.desc":"Просматривай задачи по своим категориям в разделе \xabПоиск заказов\xbb","become_specialist.step3.title":"Откликайся и зарабатывай","become_specialist.step3.desc":"Отправляй предложения с ценой и сроками, общайся с клиентами и выполняй заказы","become_specialist.benefits.title":"Преимущества профиля специалиста","become_specialist.benefit1":"Поиск заказов по вашим категориям и локации","become_specialist.benefit2":"Публичный профиль с отзывами клиентов","become_specialist.benefit3":"Расписание доступности, видимое клиентам","become_specialist.benefit4":"Добавление в избранное клиентами","become_specialist.cta":"Подробнее","become_specialist.free_badge":"Бесплатная регистрация","profile.tab.notifications":"Уведомления","profile.tab.reviews":"Отзывы","profile.tab.referral":"Рефералы","profile.tab.auto_response":"Авто-ответ","profile.tab.site":"Сайт","profile.site.title":"Персональная страница","profile.site.url_label":"Личный сайт","profile.site.copy":"Копировать","profile.site.copied":"Скопировано","profile.site.visible_title":"Что отображается на вашей странице","profile.site.visible.name":"Имя и фото","profile.site.visible.bio":"Биография","profile.site.visible.rating":"Рейтинг и отзывы","profile.site.visible.portfolio":"Портфолио / Карточки","profile.site.visible.contacts":"Контактные данные","profile.site.visible.full_last_name":"Фамилия полностью","profile.site.visible.services":"Карточки услуг","profile.site.visible.reviews":"Раздел с отзывами","profile.site.visible.status":"Статус \xabГотов помочь\xbb","profile.site.theme":"Тема оформления","profile.site.theme.dark":"Тёмная","profile.site.theme.light":"Светлая","profile.site.slug_taken":"Этот адрес уже занят","profile.site.stats.title":"Аналитика сайта","profile.site.stats.days":"последние 30 дней","profile.site.stats.views":"Просмотры","profile.site.stats.unique":"Уникальные посетители","profile.site.stats.messages":"Сообщения","profile.site.stats.total_views":"Просмотры","profile.site.stats.total_unique":"Уник. посетители","profile.site.stats.total_messages":"Сообщения","profile.site.stats.empty":"Данных пока нет","profile.site.stats.loading":"Загрузка аналитики...","profile.site.stats.no_slug":"Укажите адрес сайта, чтобы видеть статистику","profile.site.edit_bio_hint":"Биография и фото настраиваются во вкладке \xabОсновное\xbb.","status.title":"Статус","status.can_help_now_hint":"Ваша карточка показывается выше в поиске","status.need_help_hint":"Специалисты могут предложить вам помощь","profile.referral.title":"Партнёрская программа","profile.referral.desc":"Поделитесь ссылкой и получайте награду за каждого привлечённого пользователя.","profile.referral.link_label":"Ваша реферальная ссылка","profile.referral.copy":"Копировать","profile.referral.copied":"Скопировано!","profile.referral.invited_count":"успешных приглашений","profile.referral.no_code":"Реферальный код недоступен.","notifications.title":"Настройки уведомлений","notifications.email.new_tasks":"Email о новых заказах","notifications.email.new_tasks.desc":"Получать email, когда в ваших категориях публикуется новый заказ","notifications.messages.desc":"Получать уведомление при новом входящем сообщении","notifications.saved":"Настройки сохранены","notifications.plan_required":"Недоступно в вашем тарифе","profile.tab.info":"Основное","profile.tab.finance":"Финансы","profile.tab.skills":"Навыки","profile.tab.categories":"Категории","profile.tab.geography":"География","profile.specialist.categories":"Категории работ","profile.specialist.categories.desc":"Выберите категории, в которых вы работаете","profile.specialist.geography":"Города покрытия","profile.specialist.geography.desc":"Выберите города / районы, где вы работаете","profile.saving":"Сохранение...","profile.upload.error":"Ошибка загрузки фото","profile.saved":"Сохранено","profile.tab.cards":"Портфолио","profile.cards.count":"Портфолио","profile.cards.add":"Добавить портфолио","profile.cards.new_title":"Название нового портфолио","profile.cards.placeholder":"Например: Сантехника","profile.cards.create":"Создать","profile.cards.cancel":"Отмена","profile.cards.empty":"У вас нет портфолио","profile.cards.create_first":"Создать первое портфолио","profile.cards.delete_confirm":"Удалить портфолио?","profile.card.tab.main":"Основное","profile.card.tab.skills":"Навыки","profile.card.tab.categories":"Категории","profile.card.tab.geography":"География","profile.card.tab.portfolio":"Галерея","profile.card.active":"Активна","profile.card.save":"Сохранить","profile.card.saved":"Сохранено","profile.card.delete":"Удалить","profile.card.skill.add":"Добавить навык","profile.card.photo.add":"Добавить фото","profile.card.photo.uploading":"Загрузка...","profile.card.photo.empty":"Нет фотографий","profile.card.item.title":"Заголовок","profile.card.item.desc":"Описание","profile.card.item.save":"Сохранить","profile.card.item.cancel":"Отмена","profile.card.item.edit":"Описание работы","profile.upgrade.cards_limit":"Лимит портфолио исчерпан","profile.upgrade.plan":"Текущий тариф:","profile.upgrade.contact":"Обратитесь к администратору для смены тарифа","profile.upgrade.ok":"Понятно","profile.plan.title":"Тарифный план","profile.balance":"Баланс","profile.balance.topup":"Пополнить баланс","profile.balance.topup.title":"Пополнить баланс","profile.balance.topup.amount":"Сумма (в EUR)","profile.balance.topup.hint":"Выберите сумму или введите вручную","profile.balance.topup.submit":"Перейти к оплате","profile.balance.topup.loading":"Перенаправление...","profile.balance.topup.error":"Ошибка инициализации платежа. Попробуйте снова.","payment.success.title":"Оплата прошла успешно!","payment.success.desc":"Ваш баланс обновлён.","payment.cancelled.title":"Оплата отменена","payment.cancelled.desc":"Оплата была отменена. Средства не списаны.","payment.pending.title":"Обрабатывается...","payment.pending.desc":"Ваш платёж в обработке.","payment.back_to_profile":"Вернуться в профиль","profile.plan.basic":"Базовый (бесплатный)","profile.plan.contact_upgrade":"Обратитесь к администратору для подключения тарифа","profile.plan.cards_up_to":"Портфолио: до","profile.plan.cards_unlimited":"Портфолио: безлимитно","profile.plan.tasks_up_to":"Задач: до","profile.plan.offers_up_to":"Откликов: до","profile.plan.valid_until":"Действителен до","profile.plan.no_expiry":"Бессрочно","create.error":"Ошибка при публикации","tasks.category.general":"Общее","tasks.budget.range":"Диапазон:","tasks.budget.from":"от","tasks.budget.to":"до","tasks.filter.reset":"Сбросить фильтры","tasks.load_more":"Загрузить ещё","tasks.showing":"Результатов:","tasks.field.budget":"Бюджет, €","admin.title":"Панель администратора","admin.tab.stats":"Статистика","admin.tab.users":"Пользователи","admin.tab.tasks":"Задачи","admin.tab.reports":"Жалобы","admin.stats.users":"Пользователи","admin.stats.tasks":"Задачи","admin.stats.offers":"Предложения","admin.stats.reviews":"Отзывы","admin.tasks.by_status":"Задачи по статусу","admin.col.user":"Пользователь","admin.col.email":"Email","admin.col.role":"Роль","admin.col.registered":"Регистрация","admin.col.status":"Статус","admin.col.title":"Название","admin.col.budget":"Бюджет","admin.col.created":"Создано","admin.users.active":"Активен","admin.users.inactive":"Неактивен","admin.users.deactivate":"Деактивировать","admin.users.activate":"Активировать","admin.tasks.cancel":"Отменить","admin.reports.none":"Жалоб нет","admin.reports.reviewed":"Рассмотрено","admin.reports.dismiss":"Отклонить","admin.pagination.total":"Всего","admin.users.role.change":"Изменить роль","admin.users.search.placeholder":"Поиск по имени или email...","admin.tasks.delete":"Удалить","admin.tasks.delete.confirm":"Удалить эту задачу навсегда?","admin.tasks.search.placeholder":"Поиск по названию...","admin.col.customer":"Заказчик","admin.col.reporter":"Жалобщик","admin.col.target":"Цель","admin.filter.all_roles":"Все роли","admin.filter.all_statuses":"Все статусы","admin.reports.target.task":"Задача","admin.reports.target.user":"Пользователь","admin.tab.categories":"Категории","admin.tab.locations":"Города и районы","admin.tab.logs":"Логи","admin.tab.plans":"Тарифы","admin.tab.settings":"Настройки","admin.logs.subtab.ai":"AI логи","admin.logs.subtab.activity":"Активность","admin.logs.subtab.mail":"Mail","admin.logs.subtab.notifications":"Уведомления","admin.notif_logs.type":"Тип","admin.notif_logs.title":"Заголовок","admin.notif_logs.read":"Прочитано","admin.notif_logs.empty":"Логи уведомлений пусты","admin.stats.notif_chart_title":"Уведомления по дням","admin.stats.notif_label":"Уведомления","admin.stats.mail_chart_title":"Email по дням","admin.stats.mail_label":"Emails","admin.filter.all":"Все","admin.stats.specialists":"Исполнители","admin.col.plan":"Тариф","admin.back_home":"На главную","admin.plans.title":"Тарифные пакеты","admin.plans.add":"+ Добавить тариф","admin.plans.empty":"Тарифы не созданы","admin.plans.form.new":"Новый тариф","admin.plans.form.edit":"Редактировать тариф","admin.plans.form.name":"Название","admin.plans.form.price":"Цена (EUR)","admin.plans.form.old_price":"Старая цена (EUR, необязательно)","admin.plans.form.max_offers":"Макс. откликов (пусто = без лимита)","admin.plans.form.max_cards":"Макс. портфолио (пусто = без лимита)","admin.plans.form.duration_days":"Срок (дней, пусто = без истечения)","admin.plans.form.description":"Описание","admin.plans.form.features":"Возможности (по одной на строку)","admin.plans.form.notify":"Уведомления о новых заказах","admin.plans.form.default":"По умолчанию","admin.plans.form.active":"Активен","admin.plans.form.order":"Порядок","admin.plans.form.role":"Роль","admin.plans.form.tier":"Уровень","admin.plans.form.role.customer":"Заказчик","admin.plans.form.role.specialist":"Специалист","admin.plans.form.tier.free":"Бесплатный","admin.plans.form.tier.pro":"Pro","admin.plans.form.tier.ultimate":"Ultimate","admin.plans.form.section.limits":"Лимиты (пусто = без ограничений)","admin.plans.form.max_messages_day":"Макс. сообщений/день","admin.plans.form.max_orders_day":"Макс. заказов/день","admin.plans.form.max_skills":"Макс. навыков","admin.plans.form.max_profiles":"Макс. профилей","admin.plans.form.max_portfolio":"Макс. элементов портфолио","admin.plans.form.section.boost":"Множители & Буст","admin.plans.form.search_boost":"Буст в поиске","admin.plans.form.offers_multiplier":"Множитель откликов","admin.plans.form.section.contact":"Права контактов","admin.plans.form.can_contact_free":"Контакт с бесплатными пользователями","admin.plans.form.can_contact_pro":"Контакт с Pro пользователями","admin.plans.form.can_contact_all":"Контакт со всеми","admin.plans.form.can_show_contact":"Показывать контакты","admin.plans.form.can_view_phone":"Просмотр телефона","admin.plans.form.section.features":"Возможности","admin.plans.form.upload_video":"Загрузка видео","admin.plans.form.favorites":"Избранное","admin.plans.form.google_calendar":"Google Calendar","admin.plans.form.verified_badge":"Знак верификации","admin.plans.form.highlighted_reviews":"Выделенные отзывы","admin.plans.form.personal_site":"Личный сайт","admin.plans.form.can_help_now":"Статус \xabМогу помочь\xbb","admin.plans.form.need_help":"Статус \xabНужна помощь\xbb","admin.plans.form.auto_response":"Автоответ","admin.plans.form.auto_match":"Автоподбор","admin.plans.form.instant_dispatch_free":"Мгновенная рассылка (бесплатно)","admin.plans.form.instant_dispatch_pro":"Мгновенная рассылка (Pro)","admin.plans.badge.default":"По умолчанию","admin.plans.badge.inactive":"Неактивен","admin.plans.make_default":"Сделать по умолчанию","admin.plans.tasks":"Задач","admin.plans.offers":"Откликов","admin.plans.cards":"Портфолио","admin.plans.notify_tasks":"Уведомления о заказах","admin.plans.delete.confirm":"Удалить тариф","admin.activity.title":"Журнал активности","admin.activity.event":"Событие","admin.activity.all_events":"Все события","admin.activity.from":"От","admin.activity.to":"До","admin.activity.reset":"Сбросить","admin.activity.total":"Всего","admin.activity.empty":"Нет записей","admin.mail.event":"Email событие","admin.mail.all_events":"Все email события","admin.mail.from":"От","admin.mail.to":"До","admin.mail.reset":"Сбросить","admin.mail.total":"Всего","admin.mail.empty":"Нет email логов","admin.mail.recipient":"Получатель","admin.mail.provider":"Провайдер","admin.mail.details":"Детали","admin.mail.status":"Статус","admin.mail.success":"Успешно","admin.mail.failed":"Ошибка","admin.event.email_sent":"Email отправлен","admin.event.email_failed":"Email не отправлен","admin.event.email_dev":"Email DEV fallback","admin.event.admin_email_test_sent":"Тестовый email отправлен","admin.event.admin_email_test_failed":"Тестовый email не отправлен","admin.logs.empty":"Нет записей","admin.logs.date":"Дата","admin.logs.provider":"Провайдер","admin.logs.model":"Модель","admin.logs.action":"Действие","admin.logs.langs":"Языки","admin.logs.in":"Вход","admin.logs.out":"Выход","admin.logs.total":"Итого","admin.logs.ms":"мс","admin.logs.status":"Статус","admin.stats.activity_30d":"Активность за 30 дней","admin.stats.tasks_label":"Заявки","admin.stats.users_label":"Пользователи","admin.stats.specialists_label":"Исполнители","admin.stats.tokens_title":"Расход токенов (по месяцам)","admin.stats.tokens_out":"Исходящие","admin.stats.tokens_in":"Входящие","admin.stats.tokens_out_label":"Исходящие токены","admin.stats.tokens_in_label":"Входящие токены","admin.stats.cost_label":"Стоимость (USD)","admin.stats.tasks_by_status":"Заявки по статусам","admin.task_status.open":"Открытые","admin.task_status.in_progress":"В работе","admin.task_status.completed":"Завершённые","admin.task_status.cancelled":"Отменённые","admin.task_status.draft":"Черновики","admin.settings.tab.general":"Общие","admin.settings.tab.smtp":"E-Mail","admin.settings.tab.notifications":"Уведомления","admin.settings.tab.payment":"Оплата","admin.settings.tab.referral":"Реферальная","admin.settings.tab.seo":"SEO","admin.settings.tab.socials":"Соцсети","admin.settings.socials.title":"Ссылки на социальные сети","admin.settings.socials.hint":"Заполненные ссылки отображаются в подвале сайта","admin.settings.seo.maintenance_label":"Режим обслуживания","admin.settings.seo.maintenance_hint":"Показывать страницу обслуживания всем посетителям","admin.settings.seo.indexing_label":"Индексация поисковыми системами","admin.settings.seo.indexing_hint":"Разрешить поисковым системам индексировать сайт","admin.settings.seo.head_scripts_label":"Скрипты в (JS)","admin.settings.seo.head_scripts_hint":"Выполняется на каждой странице (Google Tag Manager, аналитика и т.д.)","admin.settings.seo.site_title_label":"Заголовок сайта","admin.settings.seo.site_description_label":"Описание сайта (meta description)","admin.settings.referral.title":"Партнёрская программа","admin.settings.referral.hint":"Награждайте пользователей, приводящих новых участников.","admin.settings.referral.enabled_label":"Включено","admin.settings.referral.enabled_hint":"Включить / отключить выдачу наград","admin.settings.referral.customer_section":"Для клиентов","admin.settings.referral.specialist_section":"Для специалистов","admin.settings.referral.plan_label":"Тарифный план за реферала","admin.settings.referral.no_plan":"— без плана —","admin.settings.referral.plan_hint":"Этот план будет назначен пригласившему. Если его текущий план выше — добавятся только дни.","admin.settings.referral.days_label":"Дней награды","admin.settings.referral.days_hint":"Количество дней, добавляемых к сроку действия плана.","admin.settings.general.title":"Общие настройки","admin.settings.general.site_name":"Название сайта","admin.settings.general.site_url":"URL сайта","admin.settings.general.contact_email":"Email для связи","admin.settings.general.support_phone":"Телефон поддержки","admin.settings.smtp.title":"Настройки SMTP сервера","admin.settings.smtp.hint":"Используется для отправки email-уведомлений.","admin.settings.smtp.host":"SMTP Хост","admin.settings.smtp.port":"Порт","admin.settings.smtp.encryption":"Шифрование","admin.settings.smtp.enc.none":"Нет","admin.settings.smtp.enc.tls":"STARTTLS (порт 587)","admin.settings.smtp.enc.ssl":"SSL/TLS (порт 465)","admin.settings.smtp.username":"Имя пользователя","admin.settings.smtp.password":"Пароль / App Password","admin.settings.smtp.from_name":"Имя отправителя","admin.settings.smtp.from_email":"Email отправителя","admin.settings.smtp.test":"Отправить тестовый email","admin.settings.smtp.sending":"Отправка...","admin.settings.payment.hint":"Данные для подключения к ePay Piraeus Bank.","admin.settings.env.test":"Тест (sandbox)","admin.settings.env.prod":"Боевой режим","admin.settings.env.label":"Среда","admin.settings.merchant_id":"Merchant ID","admin.settings.api_user":"API User","admin.settings.api_password":"API Password","admin.settings.confirm_url":"Confirmation URL (webhook)","admin.settings.cancel_url":"Cancel URL","admin.settings.active":"Активен","admin.settings.saving":"Сохранение...","admin.settings.saved":"Сохранено","admin.notif.vars_hint":"Доступные переменные в шаблонах","admin.notif.tmpl.not_set":"Шаблон не настроен","admin.notif.tmpl.subject_label":"Тема письма","admin.notif.tmpl.body_label":"Текст письма (HTML)","admin.notif.tmpl.save":"Сохранить","admin.notif.tmpl.close":"Закрыть","admin.notif.tmpl.translate":"Авто-перевод на другие языки","admin.notif.tmpl.translating":"Перевод...","admin.notif.tmpl.saving":"Сохранение...","admin.notif.email_verification":"Подтверждение email адреса","admin.notif.registration_success":"Успешная регистрация","admin.notif.password_reset":"Восстановление пароля","admin.notif.new_offer":"Новое предложение","admin.notif.new_task":"Новая задача","admin.notif.offer_accepted":"Предложение принято","admin.notif.new_message":"Новое сообщение","admin.notif.offer_declined":"Отклонение предложения","admin.notif.offer_other_accepted":"Выбран другой исполнитель","admin.notif.task_updated":"Изменение задания","admin.notif.deadline_reminder":"Напоминание о дедлайне","admin.notif.task_archived":"Автоснятие задания","admin.notif.referral_reward":"Реферальная награда","admin.email_template.plan_activated":"Тарифы — активация тарифа","admin.email_template.plan_upgraded":"Тарифы — повышение тарифа","admin.email_template.plan_downgrade_scheduled":"Тарифы — запланированное понижение","admin.email_template.plan_downgrade_applied":"Тарифы — применение понижения","admin.email_template.plan_renewal_reminder":"Тарифы — напоминание о продлении","admin.email_template.plan_insufficient_funds":"Тарифы — нехватка средств","pricing.confirm.title":"Подтвердите выбор тарифа","pricing.confirm.plan":"Тариф","pricing.confirm.prorated":"Зачёт остатка","pricing.confirm.effective_price":"К оплате","pricing.confirm.your_balance":"Ваш баланс","pricing.confirm.downgrade_info":"Переход на новый тариф произойдёт автоматически после окончания текущего периода.","pricing.confirm.insufficient":"Недостаточно средств на балансе.","pricing.confirm.top_up":"Пополнить","pricing.confirm.schedule_downgrade":"Запланировать переход","pricing.confirm.pay":"Оплатить","admin.user_edit.title":"Редактирование пользователя","admin.user_edit.email":"Email","admin.user_edit.email_verified":"Email подтверждён","admin.user_edit.email_not_verified":"Email не подтверждён","admin.user_edit.verify_email_btn":"Подтвердить вручную","admin.user_edit.verify_email_done":"Email подтверждён!","admin.user_edit.id":"ID","admin.user_edit.registered":"Регистрация","admin.user_edit.last_seen":"Последний визит","admin.user_edit.lang":"Язык","admin.user_edit.first_name":"Имя","admin.user_edit.last_name":"Фамилия","admin.user_edit.phone":"Телефон","admin.user_edit.bio":"О себе","admin.user_edit.role":"Роль","admin.user_edit.plan":"Тариф","admin.user_edit.no_plan":"— Без тарифа —","admin.user_edit.active":"Активный аккаунт","admin.user_edit.balance":"Баланс (EUR)","admin.user_edit.skills":"Навыки","admin.user_edit.tab.profile":"Профиль","admin.user_edit.tab.account":"Аккаунт","admin.user_edit.tab.balance":"Баланс","admin.user_edit.tab.settings":"Настройки","admin.user_edit.tab.specialist":"Портфолио","admin.user_edit.tab.site":"Сайт","admin.user_edit.plan_expires":"Тариф истекает","admin.user_edit.interface_lang":"Язык интерфейса","admin.user_edit.comm_languages":"Языки общения","admin.user_edit.personal_site_slug":"Персональная страница","admin.user_edit.show_contact_info":"Показывать контакты","admin.user_edit.show_contact_info.hint":"Видно заказчикам","admin.user_edit.notify_new_tasks":"Уведомлять о новых задачах","admin.user_edit.notify_new_tasks.hint":"Push и email уведомления","admin.user_edit.notif_messages":"Уведомления о сообщениях","admin.user_edit.notif_messages.hint":"Новые сообщения в чате","admin.user_edit.site_settings":"Настройки персональной страницы","admin.user_edit.categories":"Категории услуг","admin.user_edit.locations":"Районы обслуживания","admin.user_edit.skill_placeholder":"Новый навык...","admin.user_edit.add_category":"— Выберите категорию —","admin.user_edit.add_location":"— Выберите район —","admin.user_edit.specialist_cards":"Портфолио специалиста","admin.user_edit.no_cards":"Портфолио не найдено","admin.user_edit.card_title":"Заголовок портфолио","admin.user_edit.card_description":"Описание","admin.balance.topup.btn":"Пополнить","admin.balance.withdraw.btn":"Списать","admin.balance.modal_hint":"Изменения применяются сразу и фиксируются в истории","admin.balance.topup.title":"Пополнение баланса","admin.balance.topup.amount":"Сумма","admin.balance.topup.description":"Комментарий","admin.balance.topup.description.placeholder":"Например: бонус или ручное пополнение","admin.balance.topup.submit":"Пополнить баланс","admin.balance.withdraw.title":"Снятие баланса","admin.balance.withdraw.amount":"Сумма","admin.balance.withdraw.description":"Комментарий","admin.balance.withdraw.description.placeholder":"Например: возврат или ручное списание","admin.balance.withdraw.submit":"Списать баланс","admin.user_edit.role.customer":"Заказчик","admin.user_edit.role.specialist":"Исполнитель","admin.user_edit.role.admin":"Администратор","common.refresh":"Обновить","common.back_home":"На главную","admin.loc.hint":"Управление городами и районами","admin.loc.add_city":"Новый город","admin.loc.add_district":"Добавить район","admin.loc.new":"Новая локация","admin.loc.edit":"Редактировать локацию","admin.loc.district":"район","admin.loc.empty":"Нет локаций","admin.loc.delete.confirm":"Удалить локацию? Все районы также будут удалены.","admin.cat.add_root":"Новая категория","admin.cat.add_sub":"Подкатегория","admin.cat.edit":"Редактировать","admin.cat.delete":"Удалить","admin.cat.delete.confirm":"Удалить категорию? Все подкатегории также будут удалены.","admin.cat.slug":"Slug","admin.cat.icon":"Иконка","admin.cat.name_el":"Греческий","admin.cat.name_en":"Английский","admin.cat.name_ru":"Русский","admin.cat.order":"Порядок","admin.cat.active":"Активна","admin.cat.parent":"Родительская категория","admin.cat.no_parent":"Верхний уровень","admin.cat.save":"Сохранить","admin.cat.cancel":"Отмена","admin.cat.empty":"Нет категорий","admin.cat.hint":"Управление категориями с многоуровневой иерархией","admin.cat.new":"Новая категория","admin.cat.subcategory":"подкатегория","admin.cat.add_child":"Добавить подкатегорию","admin.cat.inactive":"Неактивна","admin.event.user_login":"Вход","admin.event.user_register":"Регистрация","admin.event.admin_user_deactivate":"Блокировка юзера","admin.event.admin_user_activate":"Разблокировка юзера","admin.event.admin_user_role_changed":"Смена роли","admin.event.admin_task_cancelled":"Отмена задачи","admin.event.admin_task_deleted":"Удаление задачи","admin.event.admin_report_reviewed":"Жалоба рассмотрена","admin.event.admin_report_dismissed":"Жалоба отклонена","admin.event.task_created":"Создана задача","user.online":"Онлайн","user.seen_minutes":"был здесь {n} мин назад","user.seen_hours":"был здесь {n} ч назад","user.seen_yesterday":"был здесь вчера","user.seen_days":"был здесь {n} дн назад","specialists.title":"Специалисты","specialists.search":"Поиск специалиста...","specialists.search.btn":"Поиск","specialists.empty":"Специалисты не найдены","specialists.no_bio":"Без описания","specialists.view":"Смотреть профиль","specialists.reviews":"отзывов","specialist.favorite":"Добавить в избранное","specialist.unfavorite":"Убрать из избранного","specialist.site_link":"Личный сайт","favorites.specialists.title":"Избранные специалисты","favorites.specialists.empty":"Вы ещё не добавили специалистов в избранное","nav.favorites":"Избранное","nav.schedule":"Расписание","nav.find_tasks":"Поиск заказов","schedule.title":"Моё расписание","schedule.subtitle":"Отмечайте дни когда вы свободны или заняты — заказчики увидят вашу доступность","schedule.available":"Свободен","schedule.busy":"Занят","schedule.unset":"Не указано","schedule.click_hint":"← клик меняет статус по кругу","schedule.range_mode":"Выделить диапазон","schedule.range_from":"С {date} — выберите конечную дату","schedule.click_to_set":"Нажмите чтобы отметить","schedule.free":"свободно","schedule.busy_count":"занято","schedule.free_days":"свободных дней","schedule.googleCalendar":"Google Календарь","schedule.connectGoogle":"Подключить Google Календарь","schedule.disconnectGoogle":"Отключить","schedule.connectedAs":"Подключено как","schedule.importFromGoogle":"Синхр. из Google","schedule.gcalConnected":"✓ Google Календарь подключён","schedule.gcalError":"Ошибка подключения Google Календарь","schedule.gcalImportDone":"Импортировано {n} дней из Google Календарь","schedule.gcalAutoSyncNote":"Изменения доступности автоматически отправляются в Google Календарь","schedule.gcalConnectDesc":"Подключите Google Календарь для автоматической синхронизации расписания","schedule.gcalDisconnectConfirm":"Отключить Google Календарь?","find_tasks.title":"Поиск заказов","find_tasks.for_me":"Для меня","find_tasks.all":"Все заказы","find_tasks.by_category":"По категориям","find_tasks.list":"Списком","find_tasks.already_offered":"Предложение отправлено","find_tasks.offer_now":"Откликнуться","find_tasks.empty_for_me":"Нет заказов в ваших категориях","find_tasks.banner_hint":"Найдите заказы по категориям вашего портфолио","find_tasks.no_cards":"Создайте портфолио специалиста, чтобы видеть подходящие заказы","find_tasks.add_card":"Создать портфолио","find_tasks.search":"Поиск заказов...","find_tasks.tasks_count":"заданий","footer.tagline":"Платформа задач для Греции","footer.rights":"Все права защищены.","app.download_title":"Скачайте мобильное приложение CanHelp","app.download_desc":"Всё CanHelp — всегда под рукой. Доступно для Android и iOS.","nav.pricing":"Тарифы","pricing.title":"Тарифы","pricing.subtitle":"Выберите подходящий план","pricing.role.customer":"Заказчик","pricing.role.specialist":"Специалист","pricing.free":"Бесплатно","pricing.per_month":"мес","pricing.duration":"Срок","pricing.days":"дн.","pricing.current_plan":"Ваш план","pricing.popular":"Популярный","pricing.choose":"Выбрать","pricing.your_plan":"Активный план","pricing.free_default":"По умолчанию","pricing.compare":"Сравнение функций","pricing.feature":"Функция","pricing.faq_note":"Оплата списывается с баланса CanHelp. Пополнение доступно в разделе Оплата.","pricing.feat.messages":"Сообщений / день","pricing.feat.orders":"Заказов / день","pricing.feat.contact_all":"Связь со всеми","pricing.feat.view_phone":"Просмотр телефона","pricing.feat.show_contact":"Показывать контакты","pricing.feat.favorites":"Избранное","pricing.feat.verified_badge":"Верифицированный бейдж","pricing.feat.google_calendar":"Google Календарь","pricing.feat.personal_site":"Персональный сайт","pricing.feat.auto_response":"Авто-ответ","pricing.feat.auto_match":"Авто-подбор","pricing.feat.highlighted_reviews":"Выделенные отзывы","pricing.feat.portfolio":"Элементов портфолио","pricing.feat.cards":"Карточки специалиста","pricing.feat.notify_tasks":"Уведомления о новых задачах","pricing.feat.video":"Видео в портфолио","upgrade.available_in":"Доступно в","upgrade.cta":"Улучшить","dashboard.plan.title":"Мой план","dashboard.plan.expires":"Истекает через {n} дней","dashboard.plan.upgrade":"Улучшить план","dashboard.plan.no_plan":"Бесплатный план","dashboard.plan.messages":"Сообщений сегодня","dashboard.plan.orders":"Заказов сегодня","dashboard.plan.limits":"Дневные лимиты","dashboard.plan.features":"Функции","dashboard.plan.stats":"Статистика","dashboard.stats.cards":"Портфолио","dashboard.stats.maxCards":"Макс. портфолио","dashboard.stats.portfolioItems":"Элементы портфолио","dashboard.stats.maxPortfolioItems":"Макс. элементы","dashboard.stats.activeOffers":"Активные отклики","dashboard.stats.reviewsReceived":"Отзывы","dashboard.stats.activeTasks":"Активные задачи","dashboard.stats.completedTasks":"Завершённые","status.need_help":"Нужна помощь","status.active":"Активен","status.toggle_on":"Включить","status.toggle_off":"Выключить","fomo.missed_orders":"Пропущено {n} заказов","fomo.missed_value":"На сумму €{v}","fomo.upgrade_hint":"Улучшите план — получайте больше заказов","fomo.conversion":"Конверсия задач","fomo.active":"Активные","fomo.with_offers":"С офертами","fomo.completed":"Завершённые","fomo.already_offered":"{n} специалистов уже откликнулись","fomo.specialist_missed":"Вы пропустили {n} заказов","fomo.top_categories":"Категории","fomo.offers_received":"предложений получено","fomo.avg_offers":"В среднем {n}/задача","fomo.completion_rate":"завершено","task.auto_match":"Авто-матч","task.auto_match_results":"Топ специалисты","task.no_offer_yet":"Вы ещё не отправили предложение","task.make_offer":"Отправить предложение","auto_response.title":"Авто-ответ","auto_response.enabled":"Включить авто-ответ","auto_response.min_budget":"Мин. бюджет","auto_response.max_budget":"Макс. бюджет","auto_response.default_price":"Цена по умолчанию","auto_response.default_message":"Сообщение по умолчанию","auto_response.max_per_day":"Макс. авто-офертов в день","auto_response.save":"Сохранить","auto_response.saved":"Сохранено","auto_response.categories":"Категории","auto_response.locations":"Локации","profile.personal_site":"Персональный сайт","profile.site_slug":"URL slug","profile.site_slug_hint":"Только латинские буквы, цифры, - и _","profile.site_open":"Открыть сайт","profile.site_preview":"Ваш сайт","profile.show_contact":"Показывать контакты","profile.show_contact_hint":"Заказчики с Pro/Ultimate-планом увидят ваш телефон","gcal.upgrade_required":"Google Календарь требует план Pro или Ultimate","chat.limit_warning":"Осталось {n} сообщений сегодня","chat.limit_reached":"Лимит сообщений исчерпан. Улучшите план","chat.upgrade":"Улучшить","site.member_since":"С нами с","site.rating":"Рейтинг","site.completed_tasks":"Выполнено","site.languages":"Языков","site.photos":"фото","site.contact_form":"Связаться","site.contact_sent":"Сообщение отправлено!","site.contact_sent_desc":"Специалист свяжется с вами в ближайшее время","site.contact_name":"Имя","site.contact_name_ph":"Ваше имя","site.contact_email_ph":"your@email.com","site.contact_message":"Сообщение","site.contact_message_ph":"Опишите вашу задачу...","site.contact_send":"Отправить","site.share":"Поделиться","site.speaks_languages":"Говорит на языках","site.message_sent":"Сообщение отправлено!","site.message_sent_desc":"Специалист получит его в чате","site.message_placeholder":"Напишите сообщение...","site.write_to_chat":"Написать в чат","site.auth_required_title":"Нужна авторизация","site.auth_required_desc":"Чтобы написать в чат, необходимо войти в аккаунт CanHelp.","site.auth_login_btn":"Войти в аккаунт","site.auth_contact_form_btn":"Написать через форму обратной связи","specialist.services":"Услуги","portfolio.title":"Портфолио","status.can_help_now":"Готов помочь","common.not_found":"Страница не найдена","common.anonymous":"Анонимно","specialist_setup.page_title":"Настройка профиля специалиста","specialist_setup.step_of":"Шаг {current} из {total}","specialist_setup.next":"Далее","specialist_setup.back":"Назад","specialist_setup.skip":"Пропустить","specialist_setup.finish":"Завершить","specialist_setup.go_to_profile":"Перейти в профиль","specialist_setup.browse_tasks":"Найти задачи","specialist_setup.step1.title":"Добро пожаловать!","specialist_setup.step1.subtitle":"Давайте настроим ваш профиль","specialist_setup.step1.desc":"Полный профиль помогает находить больше клиентов. Следуйте шагам, чтобы создать идеальный профиль специалиста.","specialist_setup.step1.what_next":"Что мы сделаем:","specialist_setup.step1.item1":"Заполним основную информацию","specialist_setup.step1.item2":"Создадим карточку услуги","specialist_setup.step1.item3":"Добавим навыки и категории","specialist_setup.step1.item4":"Выберем географию обслуживания","specialist_setup.step1.item5":"Загрузим фото портфолио","specialist_setup.step2.title":"Базовый профиль","specialist_setup.step2.subtitle":"Расскажите о себе","specialist_setup.step2.bio_label":"О себе","specialist_setup.step2.bio_placeholder":"Опишите ваш опыт, услуги которые вы предлагаете...","specialist_setup.step2.phone_label":"Телефон","specialist_setup.step2.phone_placeholder":"+30 6900000000","specialist_setup.step2.photo_label":"Фото профиля","specialist_setup.step2.photo_btn":"Загрузить фото","specialist_setup.step2.photo_uploading":"Загрузка...","specialist_setup.step2.photo_hint":"Отображается в вашем профиле","specialist_setup.step3.title":"Карточка услуги","specialist_setup.step3.subtitle":"Создайте вашу первую карточку услуги","specialist_setup.step3.title_label":"Название карточки","specialist_setup.step3.title_placeholder":"Напр. Сантехник, Электрик, Уборка...","specialist_setup.step3.desc_label":"Описание","specialist_setup.step3.desc_placeholder":"Подробно опишите что вы предлагаете, опыт, преимущества...","specialist_setup.step3.title_required":"Название обязательно","specialist_setup.step4.title":"Навыки и категории","specialist_setup.step4.subtitle":"Добавьте навыки и выберите категории","specialist_setup.step4.skills_label":"Навыки","specialist_setup.step4.skills_placeholder":"Напр. Монтаж труб...","specialist_setup.step4.skills_add":"Добавить","specialist_setup.step4.categories_label":"Категории","specialist_setup.step5.title":"География обслуживания","specialist_setup.step5.subtitle":"Где вы оказываете услуги?","specialist_setup.step5.hint":"Выберите города или конкретные районы","specialist_setup.done.title":"Ваш профиль готов!","specialist_setup.done.subtitle":"Поздравляем! Профиль настроен","specialist_setup.done.desc":"Теперь вы можете получать заказы от клиентов. Найдите задачи, которые соответствуют вашим навыкам."}};function f(a){let b=e[a]??e.el;return(a,c)=>b[a]??e.el[a]??c??a}},13260:(a,b,c)=>{"use strict";c.d(b,{CI:()=>f,Hh:()=>g,Jv:()=>e,wV:()=>h,yK:()=>d});let d=(0,c(69183).M)({baseURL:"https://api.canhelp.gr"}),{signIn:e,signOut:f,signUp:g,useSession:h}=d},14276:()=>{},15043:(a,b,c)=>{"use strict";c.d(b,{Footer:()=>k});var d=c(78157),e=c(96484),f=c(31768),g=c(94496),h=c.n(g);let i=[{key:"telegram",label:"Telegram",hoverClass:"hover:text-sky-500",svg:''},{key:"instagram",label:"Instagram",hoverClass:"hover:text-pink-500",svg:''},{key:"facebook",label:"Facebook",hoverClass:"hover:text-blue-600",svg:''},{key:"twitter",label:"X",hoverClass:"hover:text-gray-900",svg:''},{key:"youtube",label:"YouTube",hoverClass:"hover:text-red-600",svg:''},{key:"tiktok",label:"TikTok",hoverClass:"hover:text-black",svg:''},{key:"whatsapp",label:"WhatsApp",hoverClass:"hover:text-green-500",svg:''},{key:"viber",label:"Viber",hoverClass:"hover:text-purple-600",svg:''}];function j({className:a="",links:b}){let c=i.filter(({key:a})=>b?.[a]);return 0===c.length?null:(0,d.jsx)("div",{className:`flex gap-4 flex-wrap ${a}`,children:c.map(({key:a,label:c,hoverClass:e,svg:f})=>(0,d.jsx)("a",{href:b[a],target:"_blank",rel:"noopener noreferrer","aria-label":c,className:`text-gray-500 transition ${e}`,children:(0,d.jsx)("svg",{width:"22",height:"22",viewBox:"0 0 24 24",fill:"currentColor",dangerouslySetInnerHTML:{__html:f}})},a))})}function k(){let{t:a}=(0,e.Y)(),b=new Date().getFullYear(),[c,g]=(0,f.useState)({});return(0,d.jsx)("footer",{className:"bg-white border-t border-gray-200 mt-16",children:(0,d.jsxs)("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12",children:[(0,d.jsxs)("div",{className:"flex flex-col md:flex-row justify-between items-start gap-10",children:[(0,d.jsxs)("div",{className:"flex-1 min-w-[200px] flex flex-col items-start",children:[(0,d.jsx)("span",{className:"logo-text text-3xl text-blue-700 font-bold mb-2",children:"CanHelp"}),(0,d.jsx)("p",{className:"text-base text-gray-600 mb-4",children:a("footer.slogan")})]}),(0,d.jsxs)("div",{className:"flex-1 min-w-[180px]",children:[(0,d.jsx)("h3",{className:"text-lg font-semibold text-blue-900 mb-3",children:a("footer.links")}),(0,d.jsxs)("ul",{className:"space-y-2",children:[(0,d.jsx)("li",{children:(0,d.jsx)(h(),{href:"/",className:"hover:text-blue-600 transition",children:a("nav.home")})}),(0,d.jsx)("li",{children:(0,d.jsx)(h(),{href:"/tasks",className:"hover:text-blue-600 transition",children:a("nav.tasks")})}),(0,d.jsx)("li",{children:(0,d.jsx)(h(),{href:"/become-specialist",className:"hover:text-blue-600 transition",children:a("nav.specialists")})}),(0,d.jsx)("li",{children:(0,d.jsx)(h(),{href:"/pricing",className:"hover:text-blue-600 transition",children:a("nav.pricing")})})]})]}),(0,d.jsxs)("div",{className:"flex-1 min-w-[180px]",children:[(0,d.jsx)("h3",{className:"text-lg font-semibold text-blue-900 mb-3",children:a("footer.socials")}),(0,d.jsx)("p",{className:"text-gray-500 text-sm mb-2",children:"info@canhelp.gr"}),(0,d.jsx)(j,{className:"mt-2",links:c})]})]}),(0,d.jsxs)("div",{className:"mt-10 border-t border-gray-100 pt-6 text-center text-gray-400 text-sm",children:["\xa9 ",b," CanHelp. ",a("footer.rights")]})]})})}},20138:(a,b,c)=>{"use strict";c.d(b,{LocaleProvider:()=>e});var d=c(25459);let e=(0,d.registerClientReference)(function(){throw Error("Attempted to call LocaleProvider() from the server but LocaleProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/opt/canhelp/apps/web/src/context/locale.tsx","LocaleProvider");(0,d.registerClientReference)(function(){throw Error("Attempted to call useLocale() from the server but useLocale is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/opt/canhelp/apps/web/src/context/locale.tsx","useLocale")},21046:(a,b,c)=>{"use strict";c.d(b,{ScrollToTopButton:()=>f});var d=c(78157),e=c(31768);function f(){let[a,b]=(0,e.useState)(!1);return(0,d.jsx)("button",{className:`scroll-to-top-btn${a?" visible":""}`,"aria-label":"Наверх",onClick:()=>window.scrollTo({top:0,behavior:"smooth"}),children:(0,d.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:(0,d.jsx)("path",{d:"M10 16V4M10 4L4 10M10 4L16 10",stroke:"white",strokeWidth:"2.8",strokeLinecap:"round",strokeLinejoin:"round"})})})}},30460:()=>{},32948:(a,b,c)=>{"use strict";c.d(b,{ScrollToTopButton:()=>d});let d=(0,c(25459).registerClientReference)(function(){throw Error("Attempted to call ScrollToTopButton() from the server but ScrollToTopButton is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/opt/canhelp/apps/web/src/components/ScrollToTopButton.tsx","ScrollToTopButton")},33506:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>g});var d=c(5939),e=c(3498),f=c.n(e);function g(){return(0,d.jsx)("div",{className:"min-h-screen flex items-center justify-center text-center px-4",children:(0,d.jsxs)("div",{children:[(0,d.jsx)("h1",{className:"text-8xl font-bold text-blue-600 mb-4",children:"404"}),(0,d.jsx)("p",{className:"text-xl text-gray-700 mb-6",children:"Η σελίδα δεν βρέθηκε"}),(0,d.jsx)(f(),{href:"/",className:"bg-blue-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-blue-700",children:"Επιστροφή στην Αρχική"})]})})}},39348:(a,b,c)=>{"use strict";c.d(b,{Footer:()=>d});let d=(0,c(25459).registerClientReference)(function(){throw Error("Attempted to call Footer() from the server but Footer is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/opt/canhelp/apps/web/src/components/Footer.tsx","Footer")},47570:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>m,generateMetadata:()=>l});var d=c(5939),e=c(56057);c(14276);var f=c(67674),g=c(39348),h=c(20138),i=c(1697),j=c(32948);async function k(){try{let a=await fetch("https://api.canhelp.gr/api/admin/seo-public",{next:{revalidate:60}});if(!a.ok)return{};return a.json()}catch{return{}}}async function l(){let a=await k();return{title:a["seo.siteTitle"]||"CanHelp — Βρες ειδικό για κάθε δουλειά",description:a["seo.siteDescription"]||"Η ελληνική πλατφόρμα για online ανάθεση εργασιών. Βρες επαγγελματίες για καθαρισμό, υδραυλικά, μαθήματα και πολλά άλλα.",keywords:"εργασίες, ειδικοί, Ελλάδα, freelance, καθαρισμός, υδραυλικά",robots:"false"===a["seo.indexingEnabled"]?"noindex, nofollow":void 0}}async function m({children:a}){let b=await (0,e.UL)(),c=((await (0,e.b3)()).get("x-pathname")??"").startsWith("/site/"),l=b.get("canhelp_locale")?.value,m=["el","en","ru"].includes(l)?l:"el",n=decodeURIComponent(b.get("canhelp_location")?.value??""),o=(await k())["seo.headScripts"]??"",p=[];if(o.trim()){let a,b=/]*)>([\s\S]*?)<\/script>|]*)\/>/gi;for(;null!==(a=b.exec(o));){let b=a[1]??a[3]??"",c=(a[2]??"").trim(),d=b.match(/src=["']([^"']+)["']/);p.push({src:d?.[1],async:/\basync\b/i.test(b),defer:/\bdefer\b/i.test(b),inline:c||void 0})}}return(0,d.jsxs)("html",{lang:m,children:[(0,d.jsx)("head",{children:p.map((a,b)=>a.src?(0,d.jsx)("script",{src:a.src,async:a.async,defer:a.defer},b):a.inline?(0,d.jsx)("script",{dangerouslySetInnerHTML:{__html:a.inline}},b):null)}),(0,d.jsx)("body",{children:(0,d.jsx)(h.LocaleProvider,{initialLocale:m,children:(0,d.jsxs)(i.LocationProvider,{initialSlug:n,children:[!c&&(0,d.jsx)(f.Header,{}),(0,d.jsx)("main",{className:"min-h-screen",children:a}),!c&&(0,d.jsx)(j.ScrollToTopButton,{}),!c&&(0,d.jsx)(g.Footer,{})]})})})]})}},48178:(a,b,c)=>{"use strict";function d(a){if(!a?.trim())return"—";let b=a.trim().split(/\s+/);return b.length<2||!b[1]?b[0]:`${b[0]} ${b[1][0].toUpperCase()}.`}function e(a,b,c){if(a?.trim()){let c=b?.trim();return c?`${a.trim()} ${c[0].toUpperCase()}.`:a.trim()}return d(c)}c.d(b,{E:()=>d,H:()=>e})},49046:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,94496,23))},56003:(a,b,c)=>{"use strict";c.d(b,{LocationProvider:()=>g,z:()=>h});var d=c(78157),e=c(31768);c(91864);let f=(0,e.createContext)({locationSlug:"",locationTree:[],locationLoading:!0,setLocation:()=>{},getLabel:()=>""});function g({children:a,initialSlug:b=""}){let[c,g]=(0,e.useState)(b),[h,i]=(0,e.useState)([]),[j,k]=(0,e.useState)(!0),l=(0,e.useCallback)(a=>{g(a);let b=encodeURIComponent(a);document.cookie=`canhelp_location=${b}; path=/; max-age=31536000; SameSite=Lax`},[]),m=(0,e.useCallback)(a=>{if(!c)return"";for(let b of h){if(b.slug===c)return b.names[a]??b.names.el;for(let d of b.children??[])if(d.slug===c)return d.names[a]??d.names.el}return c},[c,h]);return(0,d.jsx)(f.Provider,{value:{locationSlug:c,locationTree:h,locationLoading:j,setLocation:l,getLabel:m},children:a})}function h(){return(0,e.useContext)(f)}},58719:(a,b,c)=>{"use strict";c.d(b,{Header:()=>n});var d=c(78157),e=c(94496),f=c.n(e),g=c(71159),h=c(13260),i=c(96484),j=c(48178),k=c(31768),l=c(12998);function m(){let{locale:a,setLocale:b}=(0,i.Y)(),[c,e]=(0,k.useState)(!1),f=(0,k.useRef)(null),g=l.YZ.find(b=>b.code===a)??l.YZ[0];return(0,d.jsxs)("div",{ref:f,className:"relative",children:[(0,d.jsxs)("button",{onClick:()=>e(!c),className:"flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg border border-gray-200 hover:border-blue-400 hover:bg-blue-50 transition text-sm font-medium text-gray-700","aria-label":"Change language",children:[(0,d.jsx)("span",{children:g.code.toUpperCase()}),(0,d.jsx)("svg",{className:`w-3.5 h-3.5 text-gray-400 transition-transform ${c?"rotate-180":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})]}),c&&(0,d.jsx)("div",{className:"absolute right-0 mt-1 w-40 bg-white border border-gray-200 rounded-xl shadow-lg z-50 overflow-hidden",children:l.YZ.map(c=>(0,d.jsxs)("button",{onClick:()=>{b(c.code),e(!1)},className:`w-full flex items-center gap-2.5 px-3.5 py-2.5 text-sm hover:bg-blue-50 transition ${a===c.code?"bg-blue-50 text-blue-700 font-medium":"text-gray-700"}`,children:[(0,d.jsx)("span",{children:c.label}),a===c.code&&(0,d.jsx)("svg",{className:"w-3.5 h-3.5 ml-auto text-blue-600",fill:"currentColor",viewBox:"0 0 20 20",children:(0,d.jsx)("path",{fillRule:"evenodd",d:"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",clipRule:"evenodd"})})]},c.code))})]})}function n(){(0,g.useRouter)();let a=(0,g.usePathname)(),{data:b}=(0,h.wV)(),{t:c,locale:e}=(0,i.Y)(),[l,n]=(0,k.useState)(!1),[o,p]=(0,k.useState)(!1),[q,r]=(0,k.useState)(0),[s,t]=(0,k.useState)(0),[u,v]=(0,k.useState)(null),[w,x]=(0,k.useState)(null),y=(0,k.useRef)(null),z=(0,k.useRef)(null);(0,k.useRef)(null);let A=b?.user?.role==="admin",B=b?.user?.role==="specialist";return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)("header",{ref:z,className:"header-base bg-white border-b border-gray-200 sticky top-0 z-50 transition-all duration-300",children:(0,d.jsxs)("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:[(0,d.jsxs)("div",{className:"flex items-center justify-between h-16 header-content transition-all duration-300",children:[(0,d.jsx)(f(),{href:"/",className:"flex items-center shrink-0",children:(0,d.jsx)("span",{className:"logo-text text-2xl font-bold text-blue-600 transition-all duration-300",children:"CanHelp"})}),(0,d.jsxs)("nav",{className:"hidden md:flex items-center gap-5 ml-auto",children:[B?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(f(),{href:"/tasks",className:"text-gray-600 hover:text-blue-600 font-medium text-sm",children:c("nav.find_tasks")}),(0,d.jsx)(f(),{href:"/dashboard",className:"text-gray-600 hover:text-blue-600 font-medium text-sm",children:c("nav.dashboard")})]}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(f(),{href:"/tasks/new",className:"text-gray-600 hover:text-blue-600 font-medium text-sm",children:c("dashboard.new_task")}),(0,d.jsx)(f(),{href:"/specialists",className:"text-gray-600 hover:text-blue-600 font-medium text-sm",children:c("nav.specialists")})]}),(0,d.jsx)(f(),{href:"/pricing",className:`font-medium text-sm transition ${"/pricing"===a?"text-blue-600":"text-gray-600 hover:text-blue-600"}`,children:c("nav.pricing","Pricing")}),b?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/notifications",className:"relative text-gray-600 hover:text-gray-900 flex items-center",children:[(0,d.jsx)("svg",{className:`w-5 h-5 ${q>0?"text-orange-500":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"})}),q>0&&(0,d.jsx)("span",{className:"absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none",children:q>99?"99+":q})]}),(0,d.jsxs)(f(),{href:"/chat",className:"relative text-gray-600 hover:text-gray-900 flex items-center",children:[(0,d.jsx)("svg",{className:`w-5 h-5 ${s>0?"text-green-500":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"})}),s>0&&(0,d.jsx)("span",{className:"absolute -top-1.5 -right-1.5 min-w-[16px] h-4 px-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center leading-none",children:s>99?"99+":s})]}),(0,d.jsxs)("div",{className:"relative",ref:y,children:[(0,d.jsxs)("button",{onClick:()=>p(!o),className:"flex items-center gap-1.5 text-sm font-medium text-gray-600 hover:text-blue-600",children:[(0,d.jsx)("span",{className:"truncate max-w-[100px]",children:(0,j.H)(b.user.firstName,b.user.lastName,b.user.name)}),"pro"===w&&(0,d.jsx)("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-blue-100 text-blue-700 leading-none",children:"Pro"}),"ultimate"===w&&(0,d.jsx)("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-bold bg-gradient-to-r from-amber-400 via-yellow-400 to-amber-400 text-gray-900 shadow-sm shadow-amber-300/50 leading-none",children:"★"}),(0,d.jsx)("svg",{className:"w-4 h-4 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})]}),o&&(0,d.jsxs)("div",{className:"absolute right-0 mt-2 w-52 bg-white border border-gray-200 rounded-xl shadow-lg py-1 z-50",children:[B?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/tasks/new",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"})}),c("nav.new_task")]}),(0,d.jsxs)(f(),{href:"/specialists",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"})}),c("nav.specialists")]})]}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/notifications",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:`w-4 h-4 shrink-0 ${q>0?"text-orange-500":"text-gray-400"}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"})}),(0,d.jsxs)("span",{className:"flex items-center gap-1.5",children:[c("nav.notifications"),q>0&&(0,d.jsx)("span",{className:"px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full leading-none",children:q>99?"99+":q})]})]}),(0,d.jsxs)(f(),{href:"/chat",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:`w-4 h-4 shrink-0 ${s>0?"text-green-500":"text-gray-400"}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"})}),(0,d.jsxs)("span",{className:"flex items-center gap-1.5",children:[c("nav.chat"),s>0&&(0,d.jsx)("span",{className:"px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full leading-none",children:s>99?"99+":s})]})]}),(0,d.jsxs)(f(),{href:"/dashboard",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"})}),c("nav.dashboard")]})]}),A&&(0,d.jsxs)(f(),{href:"/tasks",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})}),c("nav.find_tasks")]}),(B||A)&&(0,d.jsxs)(f(),{href:"/schedule",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"})}),c("nav.schedule")]}),A&&(0,d.jsxs)(f(),{href:"/admin",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsxs)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:[(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"}),(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15 12a3 3 0 11-6 0 3 3 0 016 0z"})]}),c("nav.admin")]}),(0,d.jsxs)(f(),{href:"/profile",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"})}),c("nav.profile")]}),(0,d.jsxs)(f(),{href:"/favorites",className:"flex items-center gap-2.5 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",onClick:()=>p(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"})}),c("nav.favorites")]}),(0,d.jsx)("hr",{className:"my-1 border-gray-100"}),(0,d.jsxs)("button",{className:"w-full flex items-center gap-2.5 px-4 py-2 text-sm text-red-500 hover:bg-red-50",onClick:()=>{p(!1),(0,h.CI)().then(()=>{window.location.href="/"})},children:[(0,d.jsx)("svg",{className:"w-4 h-4 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"})}),c("nav.logout")]})]})]})]}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(f(),{href:"/login",className:"text-gray-600 hover:text-blue-600 font-medium text-sm",children:c("nav.login")}),(0,d.jsx)(f(),{href:"/register",className:"bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium text-sm",children:c("nav.register")})]}),(0,d.jsx)(m,{})]}),(0,d.jsxs)("div",{className:"md:hidden flex items-center gap-2",children:[(0,d.jsx)(m,{}),(0,d.jsx)("button",{className:"p-2",onClick:()=>n(!l),"aria-label":"Toggle menu",children:(0,d.jsx)("svg",{className:"w-5 h-5 text-gray-600",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:l?(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M6 18L18 6M6 6l12 12"}):(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 6h16M4 12h16M4 18h16"})})})]})]}),l&&(0,d.jsxs)("div",{className:"md:hidden py-4 border-t border-gray-100 flex flex-col gap-3",children:[B?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/tasks",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})}),c("nav.find_tasks")]}),(0,d.jsxs)(f(),{href:"/dashboard",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"})}),c("nav.dashboard")]})]}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/tasks/new",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"})}),c("nav.new_task")]}),(0,d.jsxs)(f(),{href:"/specialists",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"})}),c("nav.specialists")]})]}),b?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/chat",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:`w-4 h-4 ${s>0?"text-green-500":"text-gray-400"}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"})}),c("nav.chat"),s>0&&(0,d.jsx)("span",{className:"ml-1 px-1.5 py-0.5 bg-green-500 text-white text-[10px] font-bold rounded-full",children:s})]}),B?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/tasks/new",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 4v16m8-8H4"})}),c("nav.new_task")]}),(0,d.jsxs)(f(),{href:"/specialists",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"})}),c("nav.specialists")]})]}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(f(),{href:"/notifications",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:`w-4 h-4 ${q>0?"text-orange-500":"text-gray-400"}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"})}),(0,d.jsxs)("span",{className:"flex items-center gap-1.5",children:[c("nav.notifications"),q>0&&(0,d.jsx)("span",{className:"px-1.5 py-0.5 bg-red-500 text-white text-[10px] font-bold rounded-full",children:q>99?"99+":q})]})]}),(0,d.jsxs)(f(),{href:"/dashboard",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"})}),c("nav.dashboard")]})]}),(0,d.jsxs)(f(),{href:"/favorites",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"})}),c("nav.favorites")]}),(B||A)&&(0,d.jsxs)(f(),{href:"/schedule",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"})}),c("nav.schedule")]}),A&&(0,d.jsxs)(f(),{href:"/admin",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsxs)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:[(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"}),(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15 12a3 3 0 11-6 0 3 3 0 016 0z"})]}),c("nav.admin")]}),(0,d.jsxs)(f(),{href:"/profile",className:"flex items-center gap-2 text-gray-700 font-medium py-1",onClick:()=>n(!1),children:[(0,d.jsx)("svg",{className:"w-4 h-4 text-gray-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"})}),c("nav.profile")]}),(0,d.jsxs)("button",{onClick:()=>{n(!1),(0,h.CI)().then(()=>{window.location.href="/"})},className:"flex items-center gap-2 text-left text-red-500 py-1 font-medium",children:[(0,d.jsx)("svg",{className:"w-4 h-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.8,children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"})}),c("nav.logout")]})]}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(f(),{href:"/login",className:"text-gray-700 font-medium py-1",onClick:()=>n(!1),children:c("nav.login")}),(0,d.jsx)(f(),{href:"/register",className:"text-blue-600 font-medium py-1",onClick:()=>n(!1),children:c("nav.register")})]})]})]})}),u&&(0,d.jsx)("div",{className:"fixed bottom-5 right-5 z-[200] max-w-sm w-full",children:(0,d.jsxs)("div",{className:"bg-white border border-gray-200 rounded-xl shadow-xl p-4 flex items-start gap-3 animate-fade-in",children:[(0,d.jsx)("span",{className:"text-2xl shrink-0",children:"\uD83D\uDCAC"}),(0,d.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,d.jsx)("p",{className:"font-semibold text-gray-900 text-sm",children:c("chat.toast_title")}),(0,d.jsx)("p",{className:"text-xs text-gray-500 truncate mt-0.5",children:u.body})]}),(0,d.jsxs)("div",{className:"flex flex-col items-end gap-2 shrink-0",children:[(0,d.jsx)("button",{onClick:()=>v(null),className:"text-gray-400 hover:text-gray-600 text-lg leading-none","aria-label":"close",children:"\xd7"}),(0,d.jsx)(f(),{href:`/chat?room=${u.roomId}`,onClick:()=>v(null),className:"text-xs text-blue-600 hover:underline font-medium",children:c("chat.toast_open")})]})]})})]})}c(91864),c(44826)},64271:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,58671,23)),Promise.resolve().then(c.t.bind(c,56542,23)),Promise.resolve().then(c.t.bind(c,88248,23)),Promise.resolve().then(c.t.bind(c,49743,23)),Promise.resolve().then(c.t.bind(c,96231,23)),Promise.resolve().then(c.t.bind(c,10959,23)),Promise.resolve().then(c.t.bind(c,72041,23)),Promise.resolve().then(c.t.bind(c,95094,23)),Promise.resolve().then(c.t.bind(c,67487,23))},67674:(a,b,c)=>{"use strict";c.d(b,{Header:()=>d});let d=(0,c(25459).registerClientReference)(function(){throw Error("Attempted to call Header() from the server but Header is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/opt/canhelp/apps/web/src/components/Header.tsx","Header")},72088:()=>{},72519:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,48365,23)),Promise.resolve().then(c.t.bind(c,64596,23)),Promise.resolve().then(c.t.bind(c,56186,23)),Promise.resolve().then(c.t.bind(c,67805,23)),Promise.resolve().then(c.t.bind(c,27561,23)),Promise.resolve().then(c.t.bind(c,47569,23)),Promise.resolve().then(c.t.bind(c,42747,23)),Promise.resolve().then(c.t.bind(c,56676,23)),Promise.resolve().then(c.bind(c,97225))},85105:(a,b,c)=>{Promise.resolve().then(c.bind(c,15043)),Promise.resolve().then(c.bind(c,58719)),Promise.resolve().then(c.bind(c,21046)),Promise.resolve().then(c.bind(c,96484)),Promise.resolve().then(c.bind(c,56003))},85998:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,3498,23))},91864:(a,b,c)=>{"use strict";c.d(b,{$7:()=>P,$H:()=>n,$M:()=>A,Bb:()=>aE,Bm:()=>H,Bq:()=>aI,Br:()=>ah,CX:()=>at,Cs:()=>aQ,D1:()=>aA,Em:()=>e,F7:()=>q,F9:()=>D,FI:()=>ax,Fu:()=>f,GB:()=>ab,Gp:()=>aX,H:()=>aS,H6:()=>s,He:()=>U,Ip:()=>B,Je:()=>aU,K7:()=>Q,KD:()=>N,Lb:()=>o,Lp:()=>au,ML:()=>a$,Mm:()=>V,NL:()=>C,Nt:()=>am,OM:()=>az,OV:()=>a_,OX:()=>ao,On:()=>w,P0:()=>aO,QN:()=>v,RN:()=>a1,RQ:()=>aY,Rt:()=>j,S$:()=>a0,Sw:()=>k,T9:()=>aR,Tr:()=>z,UE:()=>a2,UT:()=>h,V:()=>L,VL:()=>x,VM:()=>p,Vs:()=>J,Wi:()=>T,Xz:()=>aB,Yj:()=>_,Zp:()=>u,_z:()=>y,aT:()=>l,bR:()=>ar,bW:()=>I,bc:()=>aW,bi:()=>ai,bx:()=>r,cS:()=>S,dE:()=>R,eR:()=>aF,eU:()=>ad,f5:()=>aH,fm:()=>aM,g0:()=>aN,gg:()=>g,hD:()=>aP,hl:()=>aC,iN:()=>ay,j_:()=>ae,jd:()=>W,jg:()=>av,k_:()=>ak,lC:()=>i,nf:()=>aa,oh:()=>aK,oq:()=>Y,pD:()=>K,pK:()=>aL,q7:()=>t,qT:()=>ap,qt:()=>ag,rC:()=>as,rl:()=>aJ,sD:()=>M,st:()=>F,td:()=>aq,ts:()=>m,u4:()=>aj,uQ:()=>$,v9:()=>G,vh:()=>a3,vy:()=>X,wc:()=>aw,wl:()=>Z,yJ:()=>al,yO:()=>af,yk:()=>E,z4:()=>aT,z5:()=>ac,z6:()=>aV,zB:()=>aD,zR:()=>an,zZ:()=>O,zc:()=>aG,zk:()=>aZ});let d=process.env.INTERNAL_API_URL||"https://api.canhelp.gr";async function e(a,b){let c=`${d}/api${a}`;console.log("[api] SSR fetch",c);let e=await fetch(c,{...b,credentials:"include",headers:{"Content-Type":"application/json",...b?.headers}});if(!e.ok){let a=await e.json().catch(()=>({error:e.statusText}));throw Error("string"==typeof a.error?a.error:"string"==typeof a.message?a.message:e.statusText||"Request failed")}return e.json()}let f=()=>e("/tasks/my"),g=a=>e(`/tasks/${a}`),h=a=>e("/tasks",{method:"POST",body:JSON.stringify(a)}),i=(a,b)=>e(`/tasks/${a}`,{method:"PATCH",body:JSON.stringify(b)}),j=a=>e(`/tasks/${a}/complete`,{method:"PATCH"}),k=a=>e(`/offers?taskId=${a}`),l=()=>e("/offers/my"),m=a=>e("/offers",{method:"POST",body:JSON.stringify(a)}),n=a=>e(`/offers/${a}/accept`,{method:"PATCH"}),o=a=>e(`/offers/${a}/decline`,{method:"PATCH"}),p=a=>e(`/users/${a}/profile`),q=a=>{let b=a?"?"+new URLSearchParams(a):"";return e(`/users/specialists${b}`)},r=a=>e("/reviews",{method:"POST",body:JSON.stringify(a)}),s=a=>e(`/reviews/task/${a}`),t=()=>e("/reviews/my"),u=()=>e("/chat/rooms"),v=a=>e(`/chat/direct/${a}`),w=a=>e(`/chat/can-message/${a}`),x=a=>e(`/chat/rooms/${a}/messages`),y=(a,b)=>e("/chat/messages",{method:"POST",body:JSON.stringify({roomId:a,body:b})}),z=()=>e("/notifications"),A=()=>e("/notifications/count"),B=a=>e(`/notifications/${a}/read`,{method:"PATCH"}),C=()=>e("/notifications/read-all",{method:"PATCH"}),D=a=>e(`/notifications?type=task_invite&referenceId=${a}`),E=a=>e(`/notifications/${a}`,{method:"DELETE"}),F=()=>e("/users/me/referral"),G=a=>e(`/reviews/user/${a}`),H=a=>e(`/reviews/user/${a}/rating`),I=()=>e("/categories"),J=()=>e("/locations"),K=()=>e("/favorites/specialists"),L=a=>e(`/favorites/specialists/${a}`,{method:"POST"}),M=a=>e(`/favorites/specialists/${a}`,{method:"DELETE"}),N=()=>e("/admin/categories"),O=a=>e("/admin/categories",{method:"POST",body:JSON.stringify(a)}),P=(a,b)=>e(`/admin/categories/${a}`,{method:"PATCH",body:JSON.stringify(b)}),Q=a=>e(`/admin/categories/${a}`,{method:"DELETE"}),R=()=>e("/admin/stats"),S=(a=1,b,c)=>{let d=new URLSearchParams({page:String(a),limit:"20"});return b&&d.set("q",b),c&&d.set("role",c),e(`/admin/users?${d}`)},T=a=>e(`/admin/users/${a}/deactivate`,{method:"PATCH"}),U=a=>e(`/admin/users/${a}/activate`,{method:"PATCH"}),V=(a,b)=>e(`/admin/users/${a}/role`,{method:"PATCH",body:JSON.stringify({role:b})}),W=a=>e(`/admin/users/${a}`),X=a=>e(`/admin/users/${a}/specialist-cards`),Y=(a,b)=>e(`/admin/specialist-cards/${a}`,{method:"PATCH",body:JSON.stringify(b)}),Z=(a,b)=>e(`/admin/users/${a}`,{method:"PATCH",body:JSON.stringify(b)}),$=a=>e(`/admin/users/${a}/verify-email`,{method:"PATCH"}),_=(a=1,b,c)=>{let d=new URLSearchParams({page:String(a),limit:"20"});return b&&d.set("q",b),c&&d.set("status",c),e(`/admin/tasks?${d}`)},aa=a=>e(`/admin/tasks/${a}/cancel`,{method:"PATCH"}),ab=a=>e(`/admin/tasks/${a}`,{method:"DELETE"}),ac=(a=1)=>e(`/admin/reports?page=${a}&limit=20`),ad=(a,b)=>e(`/admin/reports/${a}/status`,{method:"PATCH",body:JSON.stringify({status:b})}),ae=(a=1)=>e(`/admin/ai-logs?page=${a}&limit=50`),af=(a={})=>{let b=new URLSearchParams;return a.page&&b.set("page",String(a.page)),a.event&&b.set("event",a.event),a.userId&&b.set("userId",a.userId),a.dateFrom&&b.set("dateFrom",a.dateFrom),a.dateTo&&b.set("dateTo",a.dateTo),b.set("limit","50"),e(`/admin/activity-logs?${b}`)},ag=(a={})=>{let b=new URLSearchParams;return a.page&&b.set("page",String(a.page)),a.event&&b.set("event",a.event),a.dateFrom&&b.set("dateFrom",a.dateFrom),a.dateTo&&b.set("dateTo",a.dateTo),b.set("limit","50"),e(`/admin/mail-logs?${b}`)},ah=(a={})=>{let b=new URLSearchParams;return a.page&&b.set("page",String(a.page)),a.type&&b.set("type",a.type),a.dateFrom&&b.set("dateFrom",a.dateFrom),a.dateTo&&b.set("dateTo",a.dateTo),b.set("limit","50"),e(`/admin/notification-logs?${b}`)},ai=()=>e("/admin/notification-stats"),aj=()=>e("/admin/mail-stats"),ak=()=>e("/admin/locations"),al=a=>e("/admin/locations",{method:"POST",body:JSON.stringify(a)}),am=(a,b)=>e(`/admin/locations/${a}`,{method:"PATCH",body:JSON.stringify(b)}),an=a=>e(`/admin/locations/${a}`,{method:"DELETE"}),ao=()=>e("/admin/plans"),ap=a=>e("/admin/plans",{method:"POST",body:JSON.stringify(a)}),aq=(a,b)=>e(`/admin/plans/${a}`,{method:"PATCH",body:JSON.stringify(b)}),ar=a=>e(`/admin/plans/${a}`,{method:"DELETE"}),as=()=>e("/admin/settings"),at=a=>e("/admin/settings",{method:"PUT",body:JSON.stringify(a)}),au=()=>e("/admin/settings/templates"),av=(a,b)=>e(`/admin/settings/templates/${a}`,{method:"PUT",body:JSON.stringify(b)}),aw=a=>e("/admin/settings/templates/translate",{method:"POST",body:JSON.stringify(a)}),ax=()=>e("/admin/settings/test-email",{method:"POST"}),ay=a=>e(`/availability/my${a?`?month=${a}`:""}`),az=(a,b,c)=>e("/availability/set",{method:"POST",body:JSON.stringify({date:a,status:b,note:c})}),aA=(a,b,c)=>e("/availability/set-range",{method:"POST",body:JSON.stringify({from:a,to:b,status:c})}),aB=(a,b)=>e(`/availability/user/${a}${b?`?month=${b}`:""}`),aC=(a,b)=>e(`/portfolio/${a}`,{method:"PATCH",body:JSON.stringify(b)}),aD=a=>e(`/portfolio/${a}`,{method:"DELETE"}),aE=()=>e("/specialist-cards/my"),aF=a=>e("/specialist-cards",{method:"POST",body:JSON.stringify(a)}),aG=(a,b)=>e(`/specialist-cards/${a}`,{method:"PATCH",body:JSON.stringify(b)}),aH=a=>e(`/specialist-cards/${a}`,{method:"DELETE"}),aI=a=>e(`/specialist-cards/user/${a}`),aJ=a=>{let b=a?.length?"?"+a.map(a=>`category=${encodeURIComponent(a)}`).join("&"):"";return e(`/skill-suggestions${b}`)},aK=a=>e("/payments/topup/init",{method:"POST",body:JSON.stringify({amount:a})}),aL=()=>e("/payments/history"),aM=(a=50)=>e(`/payments/balance-history?limit=${a}`),aN=(a={})=>{let b=new URLSearchParams;return a.page&&b.set("page",String(a.page)),a.userId&&b.set("userId",a.userId),a.kind&&b.set("kind",a.kind),b.set("limit","50"),e(`/admin/balance-history?${b}`)},aO=(a,b)=>e(`/admin/users/${a}/balance/topup`,{method:"POST",body:JSON.stringify(b)}),aP=(a,b)=>e(`/admin/users/${a}/balance/withdraw`,{method:"POST",body:JSON.stringify(b)}),aQ=a=>e("/payments/plan/preview",{method:"POST",body:JSON.stringify({planId:a})}),aR=a=>{let b=a?`?role=${a}`:"";return e(`/plans${b}`)},aS=()=>e("/dashboard/me"),aT=()=>e("/plans/daily-usage"),aU=(a,b=!0)=>e("/payments/plan/purchase",{method:"POST",body:JSON.stringify({planId:a,payFromBalance:b})}),aV=()=>e("/statuses/me"),aW=(a,b)=>e("/statuses/toggle",{method:"POST",body:JSON.stringify({statusType:a,active:b})}),aX=()=>e("/auto-response"),aY=a=>e("/auto-response",{method:"PUT",body:JSON.stringify(a)}),aZ=()=>e("/fomo/specialist"),a$=()=>e("/fomo/customer"),a_=a=>e(`/auto-match/${a}`,{method:"POST"}),a0=a=>e(`/users/site/${a}`),a1=()=>e("/users/me/site-stats"),a2=a=>e(`/users/site/${a}/track-message`,{method:"POST"}).catch(()=>{}),a3=a=>e(`/tasks/${a}/stats`)},91946:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>e});var d=c(43560);let e=async a=>[{type:"image/svg+xml",sizes:"any",url:(0,d.fillMetadataSegment)(".",await a.params,"icon.svg")+"?71a523b2dd824001"}]},94833:(a,b,c)=>{Promise.resolve().then(c.bind(c,39348)),Promise.resolve().then(c.bind(c,67674)),Promise.resolve().then(c.bind(c,32948)),Promise.resolve().then(c.bind(c,20138)),Promise.resolve().then(c.bind(c,1697))},96484:(a,b,c)=>{"use strict";c.d(b,{LocaleProvider:()=>i,Y:()=>j});var d=c(78157),e=c(31768),f=c(71159),g=c(12998);let h=(0,e.createContext)({locale:"el",setLocale:()=>{},t:a=>a});function i({children:a,initialLocale:b}){let c=(0,f.useRouter)(),[i,j]=(0,e.useState)(b??"el"),k=(0,e.useCallback)(a=>{j(a),document.cookie=`canhelp_locale=${a}; path=/; max-age=31536000; SameSite=Lax`,document.documentElement.lang=a,fetch("https://api.canhelp.gr/api/users/me",{method:"PATCH",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify({locale:a})}).catch(()=>{}),c.refresh()},[c]),l=(0,e.useCallback)((a,b)=>(0,g.$)(i)(a,b),[i]);return(0,d.jsx)(h.Provider,{value:{locale:i,setLocale:k,t:l},children:a})}function j(){return(0,e.useContext)(h)}}};  ='"use strict";exports.id=902,exports.ids=[902],exports.modules={59902:(a,b,c)=>{c.d(b,{CC:()=>f,F7:()=>h,Vs:()=>j,bW:()=>i,gg:()=>g});let d=process.env.INTERNAL_API_URL||"https://api.canhelp.gr";async function e(a,b){let c=`${d}/api${a}`;console.log("[api] SSR fetch",c);let e=await fetch(c,{...b,credentials:"include",headers:{"Content-Type":"application/json",...b?.headers}});if(!e.ok){let a=await e.json().catch(()=>({error:e.statusText}));throw Error("string"==typeof a.error?a.error:"string"==typeof a.message?a.message:e.statusText||"Request failed")}return e.json()}let f=a=>{let b=a?"?"+new URLSearchParams(a):"";return e(`/tasks/budget-range${b}`)},g=a=>e(`/tasks/${a}`),h=a=>{let b=a?"?"+new URLSearchParams(a):"";return e(`/users/specialists${b}`)},i=()=>e("/categories"),j=()=>e("/locations")}};