/opt/canhelp/apps/web/.next/cache/webpack/server-production
Edit: /opt/canhelp/apps/web/.next/cache/webpack/server-production/17.pack (2459157B)
wpc % webpack/lib/cache/PackFileCacheStrategyPackContentItems ResolverCachePlugin|normal|default|alias=|false|dependencyType=|esm|modules=[|0=|node_modules|]|fallback=|false|exportsFields=[|0=|exports|]|importsFields=[|0=|imports|]|conditionNames=[|0=|node|1=|import|]|descriptionFiles=[|0=|package.json|]|extensions=[|0=|.js|1=|.json|2=|.node|]|enforceExtensions=|false|symlinks=|true|mainFields=[|0=|main|]|mainFiles=[|0=|index|]|roots=[|]|fullySpecified=|true|preferRelative=|false|preferAbsolute=|false|restrictions=[|]|path=|/opt/canhelp/apps/web|request=|/opt/canhelp/apps/web/src/app/admin/page.tsxO ResolverCachePlugin|normal|default|alias=[|server-only$=|next/dist/compiled/server-only/empty|client-only$=|next/dist/compiled/client-only/error|next/dist/compiled/server-only$=|next/dist/compiled/server-only/empty|next/dist/compiled/client-only$=|next/dist/compiled/client-only/error|/opt/canhelp/node_modules/next/head.js=|next/dist/client/components/noop-head|/opt/canhelp/node_modules/next/image.js=|next/dist/api/image|/opt/canhelp/node_modules/next/constants.js=|next/dist/api/constants|/opt/canhelp/node_modules/next/router.js=|next/dist/api/router|/opt/canhelp/node_modules/next/dynamic.js=|next/dist/api/app-dynamic|/opt/canhelp/node_modules/next/script.js=|next/dist/api/script|/opt/canhelp/node_modules/next/link.js=|next/dist/client/app-dir/link|/opt/canhelp/node_modules/next/form.js=|next/dist/client/app-dir/form|/opt/canhelp/node_modules/next/navigation.js=|next/dist/api/navigation.react-server|/opt/canhelp/node_modules/next/headers.js=|next/dist/api/headers|/opt/canhelp/node_modules/next/og.js=|next/dist/api/og|/opt/canhelp/node_modules/next/server.js=|next/dist/api/server|/opt/canhelp/node_modules/next/document.js=|next/dist/api/document|/opt/canhelp/node_modules/next/app.js=|next/dist/api/app|next=|/opt/canhelp/node_modules/next|]|dependencyType=|esm|path=|/opt/canhelp/apps/web|request=|/opt/canhelp/apps/web/src/app/admin/page.tsx 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/admin/page.tsx|rscA ResolverCachePlugin|normal|default|alias=[|server-only$=|next/dist/compiled/server-only/index|client-only$=|next/dist/compiled/client-only/index|next/dist/compiled/client-only$=|next/dist/compiled/client-only/index|next/dist/compiled/server-only=|next/dist/compiled/server-only/index|/opt/canhelp/node_modules/next/head.js=|next/dist/client/components/noop-head|/opt/canhelp/node_modules/next/image.js=|next/dist/api/image|/opt/canhelp/node_modules/next/constants.js=|next/dist/api/constants|/opt/canhelp/node_modules/next/router.js=|next/dist/api/router|/opt/canhelp/node_modules/next/dynamic.js=|next/dist/api/app-dynamic|/opt/canhelp/node_modules/next/script.js=|next/dist/api/script|/opt/canhelp/node_modules/next/link.js=|next/dist/client/app-dir/link|/opt/canhelp/node_modules/next/form.js=|next/dist/client/app-dir/form|/opt/canhelp/node_modules/next/navigation.js=|next/dist/api/navigation|/opt/canhelp/node_modules/next/headers.js=|next/dist/api/headers|/opt/canhelp/node_modules/next/og.js=|next/dist/api/og|/opt/canhelp/node_modules/next/server.js=|next/dist/api/server|/opt/canhelp/node_modules/next/document.js=|next/dist/api/document|/opt/canhelp/node_modules/next/app.js=|next/dist/api/app|next=|/opt/canhelp/node_modules/next|]|dependencyType=|esm|path=|/opt/canhelp/apps/web|request=|/opt/canhelp/apps/web/src/app/admin/page.tsx% 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/admin/page.tsx|ssr- FlagDependencyExportsPlugin|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/admin/page.tsx|ssr< 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/admin/page.tsx|ssr|webpack-runtimewebpack/lib/cache/ResolverCachePlugin`_ResolverCachePluginCacheMisscontextpathrequestqueryfragmentmoduledirectoryfileinternalfullySpecifieddescriptionFilePathdescriptionFileDatadescriptionFileRootrelativePath/opt/canhelp/apps/web/src/app/admin/page.tsx0/opt/canhelp/apps/web/package.jsonnameversionprivatescriptsdependenciesdevDependenciesweb0.1.0devbuildstartlinttypechecknext dev --port 3000next buildnext startnext linttsc --noEmit @canhelp/shared@marsidev/react-turnstilebetter-authnanostoresnextreactreact-domsocket.io-clientzod*^1.5.0^1.2.7^1.2.0^15.1.6^19.0.0^4.8.1^3.24.1@types/node@types/react@types/react-domautoprefixerpostcsstailwindcsstypescript^22.10.7^19.0.6^19.0.3^10.4.20^8.5.1^3.4.17^5.7.3/opt/canhelp/apps/web./src/app/admin/page.tsxwebpack/lib/FileSystemInfoSnapshot@ `լyB `լyB
/opt/canhelp/apps/web/src/app/admin/opt/canhelp/apps/web/src/app/opt/canhelp/apps/web/src/opt/canhelp/apps/opt/canhelp/opt/safeTimetimestamphash! eyB eyBd659fc12c42d40f9! qѬyB qѬyBac740e53cb3a163e @ /opt/canhelp/apps/web/src/app/admin/package.json/opt/canhelp/apps/web/src/app/package.json/opt/canhelp/apps/web/src/package.jsonissuerissuerLayercompilerrscserver @ լyB @ `/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/package.json/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/package.json/opt/canhelp/apps/web/opt/canhelp/apps/web/src/package.json/opt/canhelp/apps/web/opt/canhelp/apps/web/package.json/opt/canhelp/apps/web/opt/canhelp/apps/package.json/opt/canhelp/apps/web/opt/canhelp/package.json/opt/canhelp/apps/web/opt/package.json/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx.js/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx.mjs/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx.tsx/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx.ts/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx.jsx/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx.json/opt/canhelp/apps/web/opt/canhelp/apps/web/src/app/admin/page.tsx.wasm webpack/lib/NormalModulewebpack/lib/util/registerExternalSerializerwebpack-sources/RawSource$ // This file is generated by the Webpack next-flight-loader.
import { registerClientReference } from "react-server-dom-webpack/server";
export default registerClientReference(
function() { throw new Error("Attempted to call the default export of \"/opt/canhelp/apps/web/src/app/admin/page.tsx\" from the server, but it's 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/app/admin/page.tsx",
"default",
);
exportsTypenamespace
javascript/autoaliasmainFieldsconditionNames`$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.tsqnext/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/next(mainreact-server...`cacheableparsedfileDependenciescontextDependenciesmissingDependenciesbuildDependenciesvalueDependenciesmassetsassetsInfostrictexportsArgumenttopLevelDeclarationssnapshotwebpack/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.js webpack/DefinePlugin_hash4028310fd7d9d8f7363ce1c9typeactionIdsclientRefsclientEntryTypeisClientRefclientdefaultauto__webpack_exports__*default* ԬyB
Vwebpack/lib/dependencies/HarmonyCompatibilityDependency
d webpack/lib/dependencies/ConstDependency`=@
`Jwebpack/lib/dependencies/HarmonyExportHeaderDependency A " A #
webpack/lib/dependencies/HarmonyImportSideEffectDependencyreact-server-dom-webpack/server
`Jwebpack/lib/dependencies/HarmonyExportExpressionDependency`
webpack/lib/dependencies/HarmonyImportSpecifierDependencyaregisterClientReferenceA
b&
WssrX ,-.@ 08֬yB
HjM J
/* __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 } from 'next/navigation';
import Link from 'next/link';
import { useSession } from '@/lib/auth';
import { useLocale } from '@/context/locale';
import * as api from '@/lib/api';
import { request } from '@/lib/api';
import { formatShortName } from '@/lib/formatName';
import { formatPrice } from '@/lib/taskLocale';
const TEMPLATE_VARS = {
registration_success: [
'userName',
'link',
'siteName',
'siteUrl'
],
email_verification: [
'userName',
'link',
'siteName',
'siteUrl'
],
password_reset: [
'userName',
'link',
'siteName',
'siteUrl'
],
new_offer: [
'userName',
'taskTitle',
'taskId',
'specialistName',
'price',
'link'
],
new_task: [
'userName',
'taskTitle',
'taskId',
'customerName',
'link'
],
offer_accepted: [
'userName',
'taskTitle',
'price',
'link'
],
new_message: [
'userName',
'senderName',
'preview',
'link'
],
offer_declined: [
'userName',
'taskTitle',
'taskId',
'link'
],
offer_other_accepted: [
'userName',
'taskTitle',
'taskId',
'link'
],
task_updated: [
'userName',
'taskTitle',
'taskId',
'link'
],
deadline_reminder: [
'userName',
'taskTitle',
'taskId',
'link'
],
task_archived: [
'userName',
'taskTitle',
'taskId',
'link'
],
referral_reward: [
'userName',
'days',
'planName',
'link'
],
plan_activated: [
'userName',
'planName',
'price',
'expiresAt',
'link'
],
plan_upgraded: [
'userName',
'oldPlanName',
'newPlanName',
'charged',
'expiresAt',
'link'
],
plan_downgrade_scheduled: [
'userName',
'currentPlanName',
'newPlanName',
'scheduledDate',
'link'
],
plan_downgrade_applied: [
'userName',
'planName',
'link'
],
plan_renewal_reminder: [
'userName',
'planName',
'amount',
'expiresAt',
'link'
],
plan_insufficient_funds: [
'userName',
'currentPlanName',
'requiredAmount',
'currentBalance',
'expiresAt',
'topUpLink'
]
};
const TEMPLATE_HINT_VARS = Array.from(new Set(Object.values(TEMPLATE_VARS).flat()));
function getCatLabel(row, locale) {
if (!row) return '';
return locale === 'en' ? row.namesEn || row.namesEl || row.slug || '' : locale === 'ru' ? row.namesRu || row.namesEl || row.slug || '' : row.namesEl || row.namesEn || row.slug || '';
}
function getLocLabel(row, locale) {
if (!row) return '';
return locale === 'en' ? row.nameEn || row.nameEl || row.slug || '' : locale === 'ru' ? row.nameRu || row.nameEl || row.slug || '' : row.nameEl || row.nameEn || row.slug || '';
}
function AdminCatPicker({ catRows, locale, selected, onAdd, addLabel }) {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState('');
const [expandedParent, setExpandedParent] = useState(null);
const ref = useRef(null);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
function h(e) {
if (ref.current && !ref.current.contains(e.target)) {
setOpen(false);
setSearch('');
}
}
document.addEventListener('mousedown', h);
return ()=>document.removeEventListener('mousedown', h);
}, []);
const parents = catRows.filter((r)=>!r.parentId);
const lowerSearch = search.toLowerCase();
const matchesSearch = (r)=>!search || getCatLabel(r, locale).toLowerCase().includes(lowerSearch) || (r.slug ?? '').toLowerCase().includes(lowerSearch);
return /*#__PURE__*/ _jsxs("div", {
className: "relative",
ref: ref,
children: [
/*#__PURE__*/ _jsxs("button", {
type: "button",
onClick: ()=>setOpen((v)=>!v),
className: `w-full flex items-center gap-1.5 px-3 py-1.5 text-xs transition-colors ${open ? 'rounded-t-lg border border-blue-400 bg-white text-gray-900' : 'rounded-lg border border-gray-300 bg-white hover:bg-gray-50 text-gray-500 hover:text-gray-700'}`,
children: [
/*#__PURE__*/ _jsx("svg", {
className: "w-3.5 h-3.5 text-blue-400 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M4 6h16M4 10h16M4 14h16M4 18h16"
})
}),
/*#__PURE__*/ _jsx("span", {
className: "flex-1 text-left truncate",
children: addLabel
}),
/*#__PURE__*/ _jsx("svg", {
className: `w-3 h-3 text-gray-400 shrink-0 transition-transform ${open ? 'rotate-180' : ''}`,
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19 9l-7 7-7-7"
})
})
]
}),
open && /*#__PURE__*/ _jsxs("div", {
className: "absolute left-0 top-full w-full min-w-[240px] bg-white border border-t-0 border-blue-400 rounded-b-xl shadow-lg z-50 max-h-72 overflow-y-auto",
children: [
/*#__PURE__*/ _jsx("div", {
className: "sticky top-0 bg-white px-3 py-2 border-b border-gray-100",
children: /*#__PURE__*/ _jsx("input", {
autoFocus: true,
value: search,
onChange: (e)=>setSearch(e.target.value),
placeholder: "Поиск...",
className: "w-full text-xs border border-gray-200 rounded-lg px-2.5 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-300"
})
}),
parents.map((parent)=>{
const children = catRows.filter((r)=>r.parentId === parent.id);
const parentLabel = getCatLabel(parent, locale);
const isExpanded = expandedParent === parent.id;
const matchingChildren = children.filter((c)=>!selected.includes(c.slug) && matchesSearch(c));
const parentAvail = !selected.includes(parent.slug) && matchesSearch(parent);
const hasChildren = children.length > 0;
if (!parentAvail && matchingChildren.length === 0 && search) return null;
return /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: "w-full flex items-center gap-2 px-3 py-2 text-xs text-left hover:bg-gray-50 text-gray-800",
onClick: ()=>{
if (hasChildren && !search) {
setExpandedParent(isExpanded ? null : parent.id);
} else if (parentAvail) {
onAdd(parent.slug);
setOpen(false);
setSearch('');
}
},
children: [
parent.icon ? /*#__PURE__*/ _jsx("span", {
className: "text-sm leading-none shrink-0",
children: parent.icon
}) : null,
/*#__PURE__*/ _jsx("span", {
className: "flex-1 font-medium",
children: parentLabel
}),
hasChildren && !search ? /*#__PURE__*/ _jsx("svg", {
className: `w-3.5 h-3.5 text-gray-400 shrink-0 transition-transform ${isExpanded ? 'rotate-90' : ''}`,
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 5l7 7-7 7"
})
}) : null
]
}),
(isExpanded || !!search) && matchingChildren.map((child)=>/*#__PURE__*/ _jsxs("button", {
type: "button",
className: "w-full flex items-center gap-2 pl-8 pr-3 py-1.5 text-xs text-left bg-gray-50 hover:bg-gray-100 text-gray-600",
onClick: ()=>{
onAdd(child.slug);
setOpen(false);
setSearch('');
},
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-1.5 h-1.5 rounded-full bg-gray-300 shrink-0"
}),
/*#__PURE__*/ _jsx("span", {
className: "flex-1",
children: getCatLabel(child, locale)
})
]
}, child.id))
]
}, parent.id);
})
]
})
]
});
}
function AdminLocPicker({ locRows, locale, selected, onAdd, addLabel }) {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState('');
const [expandedCity, setExpandedCity] = useState(null);
const ref = useRef(null);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
function h(e) {
if (ref.current && !ref.current.contains(e.target)) {
setOpen(false);
setSearch('');
}
}
document.addEventListener('mousedown', h);
return ()=>document.removeEventListener('mousedown', h);
}, []);
const cities = locRows.filter((r)=>!r.parentId);
const lowerSearch = search.toLowerCase();
const matchesSearch = (r)=>!search || getLocLabel(r, locale).toLowerCase().includes(lowerSearch) || (r.slug ?? '').toLowerCase().includes(lowerSearch);
return /*#__PURE__*/ _jsxs("div", {
className: "relative",
ref: ref,
children: [
/*#__PURE__*/ _jsxs("button", {
type: "button",
onClick: ()=>setOpen((v)=>!v),
className: `w-full flex items-center gap-1.5 px-3 py-1.5 text-xs transition-colors ${open ? 'rounded-t-lg border border-blue-400 bg-white text-gray-900' : 'rounded-lg border border-gray-300 bg-white hover:bg-gray-50 text-gray-500 hover:text-gray-700'}`,
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-3.5 h-3.5 text-blue-400 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M15 11a3 3 0 11-6 0 3 3 0 016 0z"
})
]
}),
/*#__PURE__*/ _jsx("span", {
className: "flex-1 text-left truncate",
children: addLabel
}),
/*#__PURE__*/ _jsx("svg", {
className: `w-3 h-3 text-gray-400 shrink-0 transition-transform ${open ? 'rotate-180' : ''}`,
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19 9l-7 7-7-7"
})
})
]
}),
open && /*#__PURE__*/ _jsxs("div", {
className: "absolute left-0 top-full w-full min-w-[220px] bg-white border border-t-0 border-blue-400 rounded-b-xl shadow-lg z-50 max-h-72 overflow-y-auto",
children: [
/*#__PURE__*/ _jsx("div", {
className: "sticky top-0 bg-white px-3 py-2 border-b border-gray-100",
children: /*#__PURE__*/ _jsx("input", {
autoFocus: true,
value: search,
onChange: (e)=>setSearch(e.target.value),
placeholder: "Поиск...",
className: "w-full text-xs border border-gray-200 rounded-lg px-2.5 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-300"
})
}),
cities.map((city)=>{
const districts = locRows.filter((r)=>r.parentId === city.id);
const cityLabel = getLocLabel(city, locale);
const isExpanded = expandedCity === city.id;
const hasDistricts = districts.length > 0;
const matchingDistricts = districts.filter((d)=>!selected.includes(d.slug) && matchesSearch(d));
const cityAvail = !selected.includes(city.slug) && matchesSearch(city);
if (!cityAvail && matchingDistricts.length === 0 && search) return null;
return /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("button", {
type: "button",
className: "w-full flex items-center gap-2 px-3 py-2 text-xs text-left hover:bg-gray-50 text-gray-800",
onClick: ()=>{
if (hasDistricts && !search) {
setExpandedCity(isExpanded ? null : city.id);
} else if (cityAvail) {
onAdd(city.slug);
setOpen(false);
setSearch('');
}
},
children: [
/*#__PURE__*/ _jsx("svg", {
className: "w-3 h-3 text-blue-300 shrink-0",
fill: "currentColor",
viewBox: "0 0 24 24",
children: /*#__PURE__*/ _jsx("path", {
d: "M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"
})
}),
/*#__PURE__*/ _jsx("span", {
className: "flex-1 font-medium",
children: cityLabel
}),
hasDistricts && !search ? /*#__PURE__*/ _jsx("svg", {
className: `w-3.5 h-3.5 text-gray-400 shrink-0 transition-transform ${isExpanded ? 'rotate-90' : ''}`,
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 5l7 7-7 7"
})
}) : null
]
}),
(isExpanded || !!search) && matchingDistricts.map((d)=>/*#__PURE__*/ _jsxs("button", {
type: "button",
className: "w-full flex items-center gap-2 pl-8 pr-3 py-1.5 text-xs text-left bg-gray-50 hover:bg-gray-100 text-gray-600",
onClick: ()=>{
onAdd(d.slug);
setOpen(false);
setSearch('');
},
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-1.5 h-1.5 rounded-full bg-gray-300 shrink-0"
}),
/*#__PURE__*/ _jsx("span", {
className: "flex-1",
children: getLocLabel(d, locale)
})
]
}, d.id))
]
}, city.id);
})
]
})
]
});
}
export default function AdminPage() {
const router = useRouter();
const { data: session, isPending } = useSession();
const { t, locale } = useLocale();
const [tab, setTab] = useState('stats');
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
setSidebarCollapsed(window.innerWidth < 1024);
}, []);
// Stats
const [stats, setStats] = useState(null);
// Users
const [users, setUsers] = useState([]);
const [usersPage, setUsersPage] = useState(1);
const [usersTotal, setUsersTotal] = useState(0);
const [usersQ, setUsersQ] = useState('');
const [usersQInput, setUsersQInput] = useState('');
const [usersRole, setUsersRole] = useState('');
// Tasks
const [tasks, setTasks] = useState([]);
const [tasksPage, setTasksPage] = useState(1);
const [tasksTotal, setTasksTotal] = useState(0);
const [tasksQ, setTasksQ] = useState('');
const [tasksQInput, setTasksQInput] = useState('');
const [tasksStatus, setTasksStatus] = useState('');
// Reports
const [reports, setReports] = useState([]);
const [reportsPage, setReportsPage] = useState(1);
const [reportsTotal, setReportsTotal] = useState(0);
// AI Logs
const [logs, setLogs] = useState([]);
const [logsPage, setLogsPage] = useState(1);
const [logsTotal, setLogsTotal] = useState(0);
// Activity Logs
const [activityLog, setActivityLog] = useState([]);
const [activityTotal, setActivityTotal] = useState(0);
const [activityPage, setActivityPage] = useState(1);
const [activityEvent, setActivityEvent] = useState('');
const [activityUserId, setActivityUserId] = useState('');
const [activityDateFrom, setActivityDateFrom] = useState('');
const [activityDateTo, setActivityDateTo] = useState('');
const [activityEventTypes, setActivityEventTypes] = useState([]);
// Mail Logs
const [mailLog, setMailLog] = useState([]);
const [mailTotal, setMailTotal] = useState(0);
const [mailPage, setMailPage] = useState(1);
const [mailEvent, setMailEvent] = useState('');
const [mailDateFrom, setMailDateFrom] = useState('');
const [mailDateTo, setMailDateTo] = useState('');
const [mailEventTypes, setMailEventTypes] = useState([]);
// Logs sub-tab
const [logsSubTab, setLogsSubTab] = useState('ai');
// Notification Logs
const [notifLogs, setNotifLogs] = useState([]);
const [notifLogsPage, setNotifLogsPage] = useState(1);
const [notifLogsTotal, setNotifLogsTotal] = useState(0);
const [notifLogsType, setNotifLogsType] = useState('');
const [notifLogsTypes, setNotifLogsTypes] = useState([]);
const [notifLogsDateFrom, setNotifLogsDateFrom] = useState('');
const [notifLogsDateTo, setNotifLogsDateTo] = useState('');
// Notification stats chart
const [notifsByDay, setNotifsByDay] = useState([]);
const [mailByDay, setMailByDay] = useState([]);
// Balance archive
const [balanceRows, setBalanceRows] = useState([]);
const [balanceTotal, setBalanceTotal] = useState(0);
const [balancePage, setBalancePage] = useState(1);
const [balanceUserId, setBalanceUserId] = useState('');
const [balanceKind, setBalanceKind] = useState('');
const [topUpSaving, setTopUpSaving] = useState(false);
const [withdrawSaving, setWithdrawSaving] = useState(false);
// User edit modal
const [editUser, setEditUser] = useState(null);
const [editUserSaving, setEditUserSaving] = useState(false);
const [verifyingEmail, setVerifyingEmail] = useState(false);
const [editUserTab, setEditUserTab] = useState('profile');
const [balanceModal, setBalanceModal] = useState(null);
const [skillInput, setSkillInput] = useState('');
const [editUserCards, setEditUserCards] = useState([]);
const [editUserCardsLoading, setEditUserCardsLoading] = useState(false);
const [cardSkillInputs, setCardSkillInputs] = useState({});
const [cardSaving, setCardSaving] = useState({});
const [cardCatSelects, setCardCatSelects] = useState({});
const [cardLocSelects, setCardLocSelects] = useState({});
// Plans
const [planRows, setPlanRows] = useState([]);
const [planForm, setPlanForm] = useState(null);
const [planSaving, setPlanSaving] = useState(false);
// Locations
const [locRows, setLocRows] = useState([]);
const [locForm, setLocForm] = useState(null);
const [locSaving, setLocSaving] = useState(false);
const [locExpanded, setLocExpanded] = useState(new Set());
// Categories
const [catRows, setCatRows] = useState([]);
const [catForm, setCatForm] = useState(null);
const [catSaving, setCatSaving] = useState(false);
const [catExpanded, setCatExpanded] = useState(new Set());
// Settings
const [settingsTab, setSettingsTab] = useState('general');
const [generalForm, setGeneralForm] = useState({
siteName: 'CanHelp',
siteUrl: '',
contactEmail: '',
supportPhone: ''
});
const [generalSaving, setGeneralSaving] = useState(false);
const [generalSaved, setGeneralSaved] = useState(false);
const [smtpForm, setSmtpForm] = useState({
host: '',
port: '587',
username: '',
password: '',
fromName: 'CanHelp',
fromEmail: '',
encryption: 'tls'
});
const [smtpSaving, setSmtpSaving] = useState(false);
const [smtpSaved, setSmtpSaved] = useState(false);
const [testEmailSending, setTestEmailSending] = useState(false);
const [testEmailResult, setTestEmailResult] = useState(null);
const [notifTemplates, setNotifTemplates] = useState({
email_verification: {
subject: 'Подтвердите ваш email — {{siteName}}',
body: ''
},
registration_success: {
subject: 'Добро пожаловать в {{siteName}}!',
body: ''
},
password_reset: {
subject: 'Восстановление пароля — {{siteName}}',
body: ''
},
new_offer: {
subject: 'Новое предложение по вашей задаче «{{taskTitle}}»',
body: ''
},
new_task: {
subject: 'Новая задача: {{taskTitle}}',
body: ''
},
offer_accepted: {
subject: 'Ваше предложение принято: {{taskTitle}}',
body: '
Ваше предложение принято! 🎉
Привет, {{userName}}!
Заказчик принял ваше предложение на выполнение задачи:
{{taskTitle}}
Сумма: {{price}}€
Открыть чат →'
},
new_message: {
subject: 'Новое сообщение от {{senderName}}',
body: '
Новое сообщение
Привет, {{userName}}!
Вам написал(а) {{senderName}}:
Ответить →'
},
offer_declined: {
subject: 'Ваше предложение отклонено: {{taskTitle}}',
body: '
Ваше предложение отклонено
Привет, {{userName}}!
К сожалению, заказчик отклонил ваше предложение на:
Найти другие заказы →'
},
offer_other_accepted: {
subject: 'Выбран другой исполнитель: {{taskTitle}}',
body: '
Выбран другой исполнитель
Привет, {{userName}}!
Заказчик выбрал другого исполнителя для задания:
Найти другие заказы →'
},
task_updated: {
subject: 'Задание обновлено: {{taskTitle}}',
body: '
Задание обновлено
Привет, {{userName}}!
Заказчик обновил детали задания:
Смотреть заказ →'
},
deadline_reminder: {
subject: 'Задание истекает завтра: {{taskTitle}}',
body: '
Напоминание о дедлайне
Привет, {{userName}}!
Ваше задание истекает через 24 часа. Обновите дедлайн, иначе задание будет автоматически снято с публикации.
Редактировать задание →'
},
task_archived: {
subject: 'Задание снято с публикации: {{taskTitle}}',
body: '
Задание переведено в черновик
Привет, {{userName}}!
Ваше задание истекло и было автоматически переведено в черновик. Обновите дедлайн, чтобы опубликовать его снова.
Редактировать задание →'
},
referral_reward: {
subject: 'Вы получили реферальную награду — {{siteName}}',
body: '
Вы получили реферальную награду! 🎁
Привет, {{userName}}!
Друг зарегистрировался по вашей реферальной ссылке. На ваш аккаунт добавлено {{days}} дней доступа к плану {{planName}}!
+{{days}} дней — {{planName}}
Перейти к аккаунту →'
},
referral_reward_el: {
subject: 'Λάβατε ανταμοιβή παραπομπής — {{siteName}}',
body: '
Λάβατε ανταμοιβή παραπομπής! 🎁
Γεια {{userName}},
Ένας φίλος εγγράφηκε χρησιμοποιώντας τον σύνδεσμο παραπομπής σας. Στον λογαριασμό σας προστέθηκαν {{days}} ημέρες πρόσβασης στο πλάνο {{planName}}!
+{{days}} ημέρες — {{planName}}
Δες τον λογαριασμό σου →'
},
referral_reward_en: {
subject: 'You received a referral reward — {{siteName}}',
body: '
You received a referral reward! 🎁
Hi {{userName}},
A friend registered using your referral link. {{days}} days of {{planName}} access have been added to your account!
+{{days}} days — {{planName}}
View your account →'
},
referral_reward_ru: {
subject: 'Вы получили реферальную награду — {{siteName}}',
body: '
Вы получили реферальную награду! 🎁
Привет, {{userName}}!
Друг зарегистрировался по вашей реферальной ссылке. На ваш аккаунт добавлено {{days}} дней доступа к плану {{planName}}!
+{{days}} дней — {{planName}}
Перейти к аккаунту →'
}
});
const [editingTemplate, setEditingTemplate] = useState(null);
const [templateLocale, setTemplateLocale] = useState('el');
const [templateSaving, setTemplateSaving] = useState(false);
const [templateTranslating, setTemplateTranslating] = useState(false);
const [ePayForm, setEPayForm] = useState({
merchantId: '',
apiUser: '',
apiPassword: '',
environment: 'test',
confirmationUrl: '',
cancelUrl: '',
enabled: false
});
const [ePaySaving, setEPaySaving] = useState(false);
const [ePaySaved, setEPaySaved] = useState(false);
const [referralForm, setReferralForm] = useState({
enabled: false,
customerPlanId: '',
customerDays: '30',
specialistPlanId: '',
specialistDays: '30'
});
const [referralSaving, setReferralSaving] = useState(false);
const [referralSaved, setReferralSaved] = useState(false);
const [seoForm, setSeoForm] = useState({
maintenanceMode: false,
indexingEnabled: true,
headScripts: '',
siteTitle: '',
siteDescription: ''
});
const [seoSaving, setSeoSaving] = useState(false);
const [seoSaved, setSeoSaved] = useState(false);
const [socialForm, setSocialForm] = useState({
telegram: '',
instagram: '',
facebook: '',
twitter: '',
youtube: '',
tiktok: '',
whatsapp: '',
viber: ''
});
const [socialSaving, setSocialSaving] = useState(false);
const [socialSaved, setSocialSaved] = useState(false);
// Backup
const [backupAutoEnabled, setBackupAutoEnabled] = useState(false);
const [backupAutoSaving, setBackupAutoSaving] = useState(false);
const [backupTables, setBackupTables] = useState([]);
const [backupTablesLoading, setBackupTablesLoading] = useState(false);
const [backupStoredFiles, setBackupStoredFiles] = useState([]);
const [backupExporting, setBackupExporting] = useState(false);
const [backupImporting, setBackupImporting] = useState(null);
const [backupRestoring, setBackupRestoring] = useState(null);
const [backupMsg, setBackupMsg] = useState(null);
const [backupMsgError, setBackupMsgError] = useState(false);
const setBackupSuccess = (msg)=>{
setBackupMsg(msg);
setBackupMsgError(false);
};
const setBackupError = (msg)=>{
setBackupMsg(msg);
setBackupMsgError(true);
};
const [loading, setLoading] = useState(false);
const isAdmin = !isPending && session && session.user?.role === 'admin';
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isPending && !session) router.push('/login');
if (!isPending && session && session.user?.role !== 'admin') router.push('/');
}, [
session,
isPending
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin) return;
api.getAdminStats().then(setStats).catch(()=>{});
api.getAdminNotifStats().then(setNotifsByDay).catch(()=>{});
api.getAdminMailStats().then(setMailByDay).catch(()=>{});
}, [
isAdmin
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'users') return;
setLoading(true);
api.getAdminUsers(usersPage, usersQ || undefined, usersRole || undefined).then((d)=>{
setUsers(d.data);
setUsersTotal(d.total);
}).catch(()=>{}).finally(()=>setLoading(false));
}, [
isAdmin,
tab,
usersPage,
usersQ,
usersRole
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'tasks') return;
setLoading(true);
api.getAdminTasks(tasksPage, tasksQ || undefined, tasksStatus || undefined).then((d)=>{
setTasks(d.data);
setTasksTotal(d.total);
}).catch(()=>{}).finally(()=>setLoading(false));
}, [
isAdmin,
tab,
tasksPage,
tasksQ,
tasksStatus
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'reports') return;
setLoading(true);
api.getAdminReports(reportsPage).then((d)=>{
setReports(d.data);
setReportsTotal(d.total);
}).catch(()=>{}).finally(()=>setLoading(false));
}, [
isAdmin,
tab,
reportsPage
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'balances') return;
setLoading(true);
api.getAdminBalanceHistory({
page: balancePage,
userId: balanceUserId || undefined,
kind: balanceKind || undefined
}).then((d)=>{
setBalanceRows(d.data);
setBalanceTotal(d.total);
}).catch(()=>{}).finally(()=>setLoading(false));
}, [
isAdmin,
tab,
balancePage,
balanceUserId,
balanceKind
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'logs') return;
if (logsSubTab === 'ai') {
setLoading(true);
api.getAdminAiLogs(logsPage).then((d)=>{
setLogs(d.data);
setLogsTotal(d.total);
}).catch(()=>{}).finally(()=>setLoading(false));
} else if (logsSubTab === 'activity') {
api.getAdminActivityLogs({
page: activityPage,
event: activityEvent || undefined,
userId: activityUserId || undefined,
dateFrom: activityDateFrom || undefined,
dateTo: activityDateTo || undefined
}).then((d)=>{
setActivityLog(d.data);
setActivityTotal(d.total);
if (d.eventTypes?.length) setActivityEventTypes(d.eventTypes);
}).catch(()=>{});
} else if (logsSubTab === 'mail') {
api.getAdminMailLogs({
page: mailPage,
event: mailEvent || undefined,
dateFrom: mailDateFrom || undefined,
dateTo: mailDateTo || undefined
}).then((d)=>{
setMailLog(d.data);
setMailTotal(d.total);
if (d.eventTypes?.length) setMailEventTypes(d.eventTypes);
}).catch(()=>{});
} else if (logsSubTab === 'notifications') {
api.getAdminNotifLogs({
page: notifLogsPage,
type: notifLogsType || undefined,
dateFrom: notifLogsDateFrom || undefined,
dateTo: notifLogsDateTo || undefined
}).then((d)=>{
setNotifLogs(d.data);
setNotifLogsTotal(d.total);
if (d.notifTypes?.length) setNotifLogsTypes(d.notifTypes);
}).catch(()=>{});
}
}, [
isAdmin,
tab,
logsSubTab,
logsPage,
activityPage,
activityEvent,
activityUserId,
activityDateFrom,
activityDateTo,
mailPage,
mailEvent,
mailDateFrom,
mailDateTo,
notifLogsPage,
notifLogsType,
notifLogsDateFrom,
notifLogsDateTo
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
setActivityPage(1);
}, [
activityEvent,
activityUserId,
activityDateFrom,
activityDateTo
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
setMailPage(1);
}, [
mailEvent,
mailDateFrom,
mailDateTo
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
setNotifLogsPage(1);
}, [
notifLogsType,
notifLogsDateFrom,
notifLogsDateTo
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'plans') return;
api.getAdminPlans().then(setPlanRows).catch(()=>{});
}, [
isAdmin,
tab
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'backup') return;
request('/admin/backup/settings').then((d)=>setBackupAutoEnabled(!!d.autoEnabled)).catch(()=>{});
setBackupTablesLoading(true);
request('/admin/backup/tables').then((d)=>setBackupTables(d.tables || [])).catch(()=>{}).finally(()=>setBackupTablesLoading(false));
request('/admin/backup/list').then((d)=>setBackupStoredFiles(d.files || [])).catch(()=>{});
}, [
isAdmin,
tab
]);
// Load plans when users tab opens (for plan selector in edit modal)
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'users') return;
if (planRows.length === 0) api.getAdminPlans().then(setPlanRows).catch(()=>{});
}, [
isAdmin,
tab
]);
// Reset page when filters change
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
setUsersPage(1);
}, [
usersQ,
usersRole
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
setTasksPage(1);
}, [
tasksQ,
tasksStatus
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
setBalancePage(1);
}, [
balanceUserId,
balanceKind
]);
async function toggleUser(id, isActive) {
const fn = isActive ? api.deactivateUser : api.activateUser;
const updated = await fn(id).catch(()=>null);
if (updated) setUsers((prev)=>prev.map((u)=>u.id === id ? updated : u));
}
async function changeRole(id, role) {
const updated = await api.changeUserRole(id, role).catch(()=>null);
if (updated) setUsers((prev)=>prev.map((u)=>u.id === id ? updated : u));
}
function openEditUser(u) {
setEditUserTab('profile');
setSkillInput('');
setBalanceModal(null);
setEditUserCards([]);
setCardSkillInputs({});
setCardSaving({});
setCardCatSelects({});
setCardLocSelects({});
setEditUser({
...u,
topUpAmount: '',
topUpDescription: '',
withdrawAmount: '',
withdrawDescription: ''
});
api.getAdminUser(u.id).then((fresh)=>setEditUser((prev)=>prev && prev.id === fresh.id ? {
...fresh,
topUpAmount: '',
topUpDescription: '',
withdrawAmount: '',
withdrawDescription: ''
} : prev)).catch(()=>{});
}
async function saveEditUser() {
if (!editUser) return;
setEditUserSaving(true);
try {
const updated = await api.updateAdminUser(editUser.id, {
firstName: editUser.firstName,
lastName: editUser.lastName,
phone: editUser.phone || null,
bio: editUser.bio || null,
role: editUser.role,
planId: editUser.planId || null,
isActive: editUser.isActive,
locale: editUser.locale,
languages: editUser.languages ?? [],
personalSiteSlug: editUser.personalSiteSlug || null,
showContactInfo: editUser.showContactInfo ?? false,
notifyNewTasks: editUser.notifyNewTasks ?? false,
notifMessages: editUser.notifMessages ?? true,
skills: editUser.skills ?? [],
siteSettings: editUser.siteSettings ?? {}
});
setUsers((prev)=>prev.map((u)=>u.id === editUser.id ? updated : u));
setEditUser(null);
} catch {} finally{
setEditUserSaving(false);
}
}
async function verifyEmail() {
if (!editUser) return;
setVerifyingEmail(true);
try {
const updated = await api.verifyAdminUserEmail(editUser.id);
setEditUser((u)=>u ? {
...u,
emailVerified: updated.emailVerified
} : u);
setUsers((prev)=>prev.map((u)=>u.id === editUser.id ? {
...u,
emailVerified: updated.emailVerified
} : u));
} catch {} finally{
setVerifyingEmail(false);
}
}
async function handleAdminTopUp() {
if (!editUser) return;
const amount = Number(editUser.topUpAmount);
if (!amount || amount <= 0) return;
setTopUpSaving(true);
try {
const result = await api.adminTopUpUserBalance(editUser.id, {
amount,
description: editUser.topUpDescription || undefined
});
setUsers((prev)=>prev.map((u)=>u.id === editUser.id ? result.user : u));
setEditUser((prev)=>prev ? {
...prev,
...result.user,
topUpAmount: '',
topUpDescription: ''
} : prev);
if (tab === 'balances') {
api.getAdminBalanceHistory({
page: balancePage,
userId: balanceUserId || undefined,
kind: balanceKind || undefined
}).then((d)=>{
setBalanceRows(d.data);
setBalanceTotal(d.total);
}).catch(()=>{});
}
} catch {
// ignore
} finally{
setTopUpSaving(false);
}
}
async function handleAdminWithdraw() {
if (!editUser) return;
const amount = Number(editUser.withdrawAmount);
if (!amount || amount <= 0) return;
setWithdrawSaving(true);
try {
const result = await api.adminWithdrawUserBalance(editUser.id, {
amount,
description: editUser.withdrawDescription || undefined
});
setUsers((prev)=>prev.map((u)=>u.id === editUser.id ? result.user : u));
setEditUser((prev)=>prev ? {
...prev,
...result.user,
withdrawAmount: '',
withdrawDescription: ''
} : prev);
if (tab === 'balances') {
api.getAdminBalanceHistory({
page: balancePage,
userId: balanceUserId || undefined,
kind: balanceKind || undefined
}).then((d)=>{
setBalanceRows(d.data);
setBalanceTotal(d.total);
}).catch(()=>{});
}
} catch {
// ignore
} finally{
setWithdrawSaving(false);
}
}
async function saveCard(cardId) {
const card = editUserCards.find((c)=>c.id === cardId);
if (!card) return;
setCardSaving((prev)=>({
...prev,
[cardId]: true
}));
try {
const updated = await api.adminUpdateSpecialistCard(cardId, {
title: card.title,
description: card.description || null,
skills: card.skills ?? [],
categories: card.categories ?? [],
locations: card.locations ?? [],
isActive: card.isActive
});
setEditUserCards((prev)=>prev.map((c)=>c.id === cardId ? updated : c));
} catch {} finally{
setCardSaving((prev)=>({
...prev,
[cardId]: false
}));
}
}
async function cancelTask(id) {
const updated = await api.cancelTaskAdmin(id).catch(()=>null);
if (updated) {
const task = updated.task || updated;
setTasks((prev)=>prev.map((row)=>{
const t = row.task || row;
return t.id === id ? {
...row,
task: task
} : row;
}));
}
}
async function deleteTask(id, title) {
if (!window.confirm(`${t('admin.tasks.delete.confirm')}\n"${title}"`)) return;
const ok = await api.deleteTaskAdmin(id).catch(()=>null);
if (ok) setTasks((prev)=>prev.filter((row)=>(row.task?.id || row.id) !== id));
}
async function handleReport(id, status) {
const updated = await api.updateReportStatus(id, status).catch(()=>null);
if (updated) setReports((prev)=>prev.map((r)=>r.id === id ? {
...r,
...updated
} : r));
}
// Locations
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'locations') return;
api.getAdminLocations().then(setLocRows).catch(()=>{});
}, [
isAdmin,
tab
]);
function openAddLoc(parentId) {
setLocForm({
parentId: parentId ?? null,
slug: '',
nameEl: '',
nameEn: '',
nameRu: '',
order: 0,
isActive: true
});
}
function openEditLoc(loc) {
setLocForm({
id: loc.id,
parentId: loc.parentId ?? null,
slug: loc.slug,
nameEl: loc.nameEl ?? loc.names?.el ?? '',
nameEn: loc.nameEn ?? loc.names?.en ?? '',
nameRu: loc.nameRu ?? loc.names?.ru ?? '',
order: loc.order ?? 0,
isActive: loc.isActive ?? true
});
}
async function saveLoc() {
if (!locForm) return;
setLocSaving(true);
try {
if (locForm.id) {
const updated = await api.updateLocation(locForm.id, locForm);
setLocRows((prev)=>prev.map((r)=>r.id === locForm.id ? updated : r));
} else {
const created = await api.createLocation({
slug: locForm.slug,
nameEl: locForm.nameEl,
nameEn: locForm.nameEn,
nameRu: locForm.nameRu,
parentId: locForm.parentId,
order: locForm.order
});
setLocRows((prev)=>[
...prev,
created
]);
}
setLocForm(null);
} catch {
// ignore
} finally{
setLocSaving(false);
}
}
async function deleteLoc(id, name) {
if (!window.confirm(`${t('admin.loc.delete.confirm')}\n"${name}"`)) return;
const ok = await api.deleteLocation(id).catch(()=>null);
if (ok) setLocRows((prev)=>prev.filter((r)=>r.id !== id));
}
function toggleLocExpand(id) {
setLocExpanded((prev)=>{
const next = new Set(prev);
next.has(id) ? next.delete(id) : next.add(id);
return next;
});
}
// Categories
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'categories') return;
api.getAdminCategories().then(setCatRows).catch(()=>{});
}, [
isAdmin,
tab
]);
function openAddCat(parentId) {
setCatForm({
parentId: parentId ?? null,
slug: '',
icon: '📦',
namesEl: '',
namesEn: '',
namesRu: '',
order: 0,
isActive: true
});
}
function openEditCat(cat) {
setCatForm({
id: cat.id,
parentId: cat.parentId ?? null,
slug: cat.slug,
icon: cat.icon,
namesEl: cat.namesEl ?? cat.names?.el ?? '',
namesEn: cat.namesEn ?? cat.names?.en ?? '',
namesRu: cat.namesRu ?? cat.names?.ru ?? '',
order: cat.order ?? 0,
isActive: cat.isActive ?? true
});
}
async function saveCat() {
if (!catForm) return;
setCatSaving(true);
try {
if (catForm.id) {
const updated = await api.updateCategory(catForm.id, catForm);
setCatRows((prev)=>prev.map((r)=>r.id === catForm.id ? updated : r));
} else {
const created = await api.createCategory({
slug: catForm.slug,
icon: catForm.icon,
namesEl: catForm.namesEl,
namesEn: catForm.namesEn,
namesRu: catForm.namesRu,
parentId: catForm.parentId,
order: catForm.order
});
setCatRows((prev)=>[
...prev,
created
]);
}
setCatForm(null);
} catch {
// ignore
} finally{
setCatSaving(false);
}
}
async function deleteCat(id, name) {
if (!window.confirm(`${t('admin.cat.delete.confirm')}\n"${name}"`)) return;
const ok = await api.deleteCategory(id).catch(()=>null);
if (ok) setCatRows((prev)=>prev.filter((r)=>r.id !== id));
}
function toggleCatExpand(id) {
setCatExpanded((prev)=>{
const next = new Set(prev);
next.has(id) ? next.delete(id) : next.add(id);
return next;
});
}
function openAddPlan() {
setPlanForm({
name: '',
description: '',
role: 'specialist',
tier: 'free',
price: '0',
oldPrice: '',
currency: 'EUR',
maxTasks: '',
maxOffers: '',
maxCards: '',
maxMessagesPerDay: '',
maxOrdersPerDay: '',
maxSkills: '',
maxProfiles: '',
maxPortfolioItems: '',
durationDays: '',
searchBoost: 0,
offersMultiplier: '1.00',
features: '',
isDefault: false,
isActive: true,
order: 0,
notifyNewTasks: false,
canContactFreePlan: false,
canContactProPlan: true,
canContactAll: false,
canShowContactInfo: false,
canViewPhone: false,
canUploadVideo: false,
hasFavorites: false,
hasGoogleCalendar: false,
hasVerifiedBadge: false,
highlightedReviews: false,
hasPersonalSite: false,
hasCanHelpNowStatus: false,
hasNeedHelpStatus: false,
hasAutoResponse: false,
hasAutoMatch: false,
receiveInstantDispatchFree: false,
receiveInstantDispatchPro: false
});
}
function openEditPlan(plan) {
setPlanForm({
id: plan.id,
name: plan.name,
description: plan.description ?? '',
role: plan.role ?? 'specialist',
tier: plan.tier ?? 'free',
price: plan.price ?? '0',
oldPrice: plan.oldPrice ?? '',
currency: plan.currency ?? 'EUR',
maxTasks: plan.maxTasks != null ? String(plan.maxTasks) : '',
maxOffers: plan.maxOffers != null ? String(plan.maxOffers) : '',
maxCards: plan.maxCards != null ? String(plan.maxCards) : '',
maxMessagesPerDay: plan.maxMessagesPerDay != null ? String(plan.maxMessagesPerDay) : '',
maxOrdersPerDay: plan.maxOrdersPerDay != null ? String(plan.maxOrdersPerDay) : '',
maxSkills: plan.maxSkills != null ? String(plan.maxSkills) : '',
maxProfiles: plan.maxProfiles != null ? String(plan.maxProfiles) : '',
maxPortfolioItems: plan.maxPortfolioItems != null ? String(plan.maxPortfolioItems) : '',
durationDays: plan.durationDays != null ? String(plan.durationDays) : '',
searchBoost: plan.searchBoost ?? 0,
offersMultiplier: plan.offersMultiplier ?? '1.00',
features: (plan.features ?? []).join('\n'),
isDefault: plan.isDefault ?? false,
isActive: plan.isActive ?? true,
order: plan.order ?? 0,
notifyNewTasks: plan.notifyNewTasks ?? false,
canContactFreePlan: plan.canContactFreePlan ?? false,
canContactProPlan: plan.canContactProPlan ?? true,
canContactAll: plan.canContactAll ?? false,
canShowContactInfo: plan.canShowContactInfo ?? false,
canViewPhone: plan.canViewPhone ?? false,
canUploadVideo: plan.canUploadVideo ?? false,
hasFavorites: plan.hasFavorites ?? false,
hasGoogleCalendar: plan.hasGoogleCalendar ?? false,
hasVerifiedBadge: plan.hasVerifiedBadge ?? false,
highlightedReviews: plan.highlightedReviews ?? false,
hasPersonalSite: plan.hasPersonalSite ?? false,
hasCanHelpNowStatus: plan.hasCanHelpNowStatus ?? false,
hasNeedHelpStatus: plan.hasNeedHelpStatus ?? false,
hasAutoResponse: plan.hasAutoResponse ?? false,
hasAutoMatch: plan.hasAutoMatch ?? false,
receiveInstantDispatchFree: plan.receiveInstantDispatchFree ?? false,
receiveInstantDispatchPro: plan.receiveInstantDispatchPro ?? false
});
}
async function savePlan() {
if (!planForm) return;
setPlanSaving(true);
try {
const payload = {
name: planForm.name,
description: planForm.description || undefined,
role: planForm.role,
tier: planForm.tier,
price: planForm.price,
oldPrice: planForm.oldPrice || null,
currency: planForm.currency,
maxTasks: planForm.maxTasks ? Number(planForm.maxTasks) : null,
maxOffers: planForm.maxOffers ? Number(planForm.maxOffers) : null,
maxCards: planForm.maxCards ? Number(planForm.maxCards) : null,
maxMessagesPerDay: planForm.maxMessagesPerDay ? Number(planForm.maxMessagesPerDay) : null,
maxOrdersPerDay: planForm.maxOrdersPerDay ? Number(planForm.maxOrdersPerDay) : null,
maxSkills: planForm.maxSkills ? Number(planForm.maxSkills) : null,
maxProfiles: planForm.maxProfiles ? Number(planForm.maxProfiles) : null,
maxPortfolioItems: planForm.maxPortfolioItems ? Number(planForm.maxPortfolioItems) : null,
durationDays: planForm.durationDays ? Number(planForm.durationDays) : null,
notifyNewTasks: planForm.notifyNewTasks,
searchBoost: planForm.searchBoost,
offersMultiplier: planForm.offersMultiplier,
canContactFreePlan: planForm.canContactFreePlan,
canContactProPlan: planForm.canContactProPlan,
canContactAll: planForm.canContactAll,
canShowContactInfo: planForm.canShowContactInfo,
canViewPhone: planForm.canViewPhone,
canUploadVideo: planForm.canUploadVideo,
hasFavorites: planForm.hasFavorites,
hasGoogleCalendar: planForm.hasGoogleCalendar,
hasVerifiedBadge: planForm.hasVerifiedBadge,
highlightedReviews: planForm.highlightedReviews,
hasPersonalSite: planForm.hasPersonalSite,
hasCanHelpNowStatus: planForm.hasCanHelpNowStatus,
hasNeedHelpStatus: planForm.hasNeedHelpStatus,
hasAutoResponse: planForm.hasAutoResponse,
hasAutoMatch: planForm.hasAutoMatch,
receiveInstantDispatchFree: planForm.receiveInstantDispatchFree,
receiveInstantDispatchPro: planForm.receiveInstantDispatchPro,
features: planForm.features ? planForm.features.split('\n').map((s)=>s.trim()).filter(Boolean) : [],
isDefault: planForm.isDefault,
isActive: planForm.isActive,
order: planForm.order
};
if (planForm.id) {
const updated = await api.updatePlan(planForm.id, payload);
setPlanRows((prev)=>prev.map((r)=>r.id === planForm.id ? updated : r));
} else {
const created = await api.createPlan(payload);
setPlanRows((prev)=>[
...prev,
created
]);
}
// If set as default — refresh all to sync isDefault flags
if (planForm.isDefault) {
api.getAdminPlans().then(setPlanRows).catch(()=>{});
}
setPlanForm(null);
} catch {
// ignore
} finally{
setPlanSaving(false);
}
}
async function deletePlan(id, name) {
if (!window.confirm(`Удалить тариф "${name}"?`)) return;
const ok = await api.deletePlan(id).catch(()=>null);
if (ok) setPlanRows((prev)=>prev.filter((r)=>r.id !== id));
}
// Settings
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
if (!isAdmin || tab !== 'settings') return;
if (planRows.length === 0) api.getAdminPlans().then(setPlanRows).catch(()=>{});
api.getAdminSettings().then((kv)=>{
setGeneralForm({
siteName: kv['general.siteName'] ?? 'CanHelp',
siteUrl: kv['general.siteUrl'] ?? '',
contactEmail: kv['general.contactEmail'] ?? '',
supportPhone: kv['general.supportPhone'] ?? ''
});
setSmtpForm({
host: kv['smtp.host'] ?? '',
port: kv['smtp.port'] ?? '587',
username: kv['smtp.username'] ?? '',
password: kv['smtp.password'] ?? '',
fromName: kv['smtp.fromName'] ?? 'CanHelp',
fromEmail: kv['smtp.fromEmail'] ?? '',
encryption: kv['smtp.encryption'] ?? 'tls'
});
setEPayForm({
merchantId: kv['payment.epay.merchantId'] ?? '',
apiUser: kv['payment.epay.apiUser'] ?? '',
apiPassword: kv['payment.epay.apiPassword'] ?? '',
environment: kv['payment.epay.environment'] ?? 'test',
confirmationUrl: kv['payment.epay.confirmationUrl'] ?? '',
cancelUrl: kv['payment.epay.cancelUrl'] ?? '',
enabled: kv['payment.epay.enabled'] === 'true'
});
setReferralForm({
enabled: kv['referral_enabled'] === 'true',
customerPlanId: kv['referral_customer_plan_id'] ?? kv['referral_plan_id'] ?? '',
customerDays: kv['referral_customer_days'] ?? kv['referral_days'] ?? '30',
specialistPlanId: kv['referral_specialist_plan_id'] ?? kv['referral_plan_id'] ?? '',
specialistDays: kv['referral_specialist_days'] ?? kv['referral_days'] ?? '30'
});
setSeoForm({
maintenanceMode: kv['seo.maintenanceMode'] === 'true',
indexingEnabled: kv['seo.indexingEnabled'] !== 'false',
headScripts: kv['seo.headScripts'] ?? '',
siteTitle: kv['seo.siteTitle'] ?? '',
siteDescription: kv['seo.siteDescription'] ?? ''
});
setSocialForm({
telegram: kv['social.telegram'] ?? '',
instagram: kv['social.instagram'] ?? '',
facebook: kv['social.facebook'] ?? '',
twitter: kv['social.twitter'] ?? '',
youtube: kv['social.youtube'] ?? '',
tiktok: kv['social.tiktok'] ?? '',
whatsapp: kv['social.whatsapp'] ?? '',
viber: kv['social.viber'] ?? ''
});
}).catch(()=>{});
api.getAdminEmailTemplates().then((rows)=>{
const map = {};
for (const r of rows)map[r.key] = {
subject: r.subject,
body: r.body
};
setNotifTemplates((prev)=>({
...prev,
...map
}));
}).catch(()=>{});
}, [
isAdmin,
tab
]);
async function saveGeneralSettings() {
setGeneralSaving(true);
try {
await api.updateAdminSettings({
'general.siteName': generalForm.siteName,
'general.siteUrl': generalForm.siteUrl,
'general.contactEmail': generalForm.contactEmail,
'general.supportPhone': generalForm.supportPhone
});
setGeneralSaved(true);
setTimeout(()=>setGeneralSaved(false), 2500);
} catch {} finally{
setGeneralSaving(false);
}
}
async function saveSmtpSettings() {
setSmtpSaving(true);
try {
await api.updateAdminSettings({
'smtp.host': smtpForm.host,
'smtp.port': smtpForm.port,
'smtp.username': smtpForm.username,
'smtp.password': smtpForm.password,
'smtp.fromName': smtpForm.fromName,
'smtp.fromEmail': smtpForm.fromEmail,
'smtp.encryption': smtpForm.encryption
});
setSmtpSaved(true);
setTimeout(()=>setSmtpSaved(false), 2500);
} catch {} finally{
setSmtpSaving(false);
}
}
async function autoTranslateTemplate(key) {
const localeKey = `${key}_${templateLocale}`;
const current = notifTemplates[localeKey] ?? notifTemplates[key] ?? {
subject: '',
body: ''
};
if (!current.subject && !current.body) return;
setTemplateTranslating(true);
try {
// Сохраняем исходный язык в БД (если ещё не сохранён)
await api.updateAdminEmailTemplate(localeKey, current);
// Переводим на остальные языки
const results = await api.translateAdminEmailTemplate({
subject: current.subject,
body: current.body,
fromLocale: templateLocale
});
// Обновляем state
setNotifTemplates((prev)=>{
const next = {
...prev,
[localeKey]: current
};
for (const [loc, tpl] of Object.entries(results)){
next[`${key}_${loc}`] = tpl;
}
return next;
});
// Сохраняем каждый перевод в БД
await Promise.all(Object.entries(results).map(([loc, tpl])=>api.updateAdminEmailTemplate(`${key}_${loc}`, tpl)));
} catch {} finally{
setTemplateTranslating(false);
}
}
async function saveTemplate(key) {
const localeKey = `${key}_${templateLocale}`;
setTemplateSaving(true);
try {
await api.updateAdminEmailTemplate(localeKey, notifTemplates[localeKey] ?? {
subject: '',
body: ''
});
setEditingTemplate(null);
} catch {} finally{
setTemplateSaving(false);
}
}
async function saveEPaySettings() {
setEPaySaving(true);
try {
await api.updateAdminSettings({
'payment.epay.merchantId': ePayForm.merchantId,
'payment.epay.apiUser': ePayForm.apiUser,
'payment.epay.apiPassword': ePayForm.apiPassword,
'payment.epay.environment': ePayForm.environment,
'payment.epay.confirmationUrl': ePayForm.confirmationUrl,
'payment.epay.cancelUrl': ePayForm.cancelUrl,
'payment.epay.enabled': String(ePayForm.enabled)
});
setEPaySaved(true);
setTimeout(()=>setEPaySaved(false), 2500);
} catch {} finally{
setEPaySaving(false);
}
}
async function saveReferralSettings() {
setReferralSaving(true);
try {
await api.updateAdminSettings({
'referral_enabled': String(referralForm.enabled),
'referral_customer_plan_id': referralForm.customerPlanId,
'referral_customer_days': referralForm.customerDays,
'referral_specialist_plan_id': referralForm.specialistPlanId,
'referral_specialist_days': referralForm.specialistDays
});
setReferralSaved(true);
setTimeout(()=>setReferralSaved(false), 2500);
} catch {} finally{
setReferralSaving(false);
}
}
async function saveSeoSettings() {
setSeoSaving(true);
try {
await api.updateAdminSettings({
'seo.maintenanceMode': String(seoForm.maintenanceMode),
'seo.indexingEnabled': String(seoForm.indexingEnabled),
'seo.headScripts': seoForm.headScripts,
'seo.siteTitle': seoForm.siteTitle,
'seo.siteDescription': seoForm.siteDescription
});
setSeoSaved(true);
setTimeout(()=>setSeoSaved(false), 2500);
} catch {} finally{
setSeoSaving(false);
}
}
async function saveSocialSettings() {
setSocialSaving(true);
try {
await api.updateAdminSettings({
'social.telegram': socialForm.telegram,
'social.instagram': socialForm.instagram,
'social.facebook': socialForm.facebook,
'social.twitter': socialForm.twitter,
'social.youtube': socialForm.youtube,
'social.tiktok': socialForm.tiktok,
'social.whatsapp': socialForm.whatsapp,
'social.viber': socialForm.viber
});
setSocialSaved(true);
setTimeout(()=>setSocialSaved(false), 2500);
} catch {} finally{
setSocialSaving(false);
}
}
if (isPending) return /*#__PURE__*/ _jsx("div", {
className: "text-center py-20 text-gray-500",
children: t('common.loading')
});
const dateLocale = locale === 'ru' ? 'ru-RU' : locale === 'en' ? 'en-US' : 'el-GR';
const catName = (id)=>{
const cat = catRows.find((c)=>c.id === id);
if (!cat) return id;
return locale === 'en' ? cat.namesEn || cat.namesEl : locale === 'ru' ? cat.namesRu || cat.namesEl : cat.namesEl || cat.namesEn || id;
};
const locName = (id)=>{
const loc = locRows.find((l)=>l.id === id);
if (!loc) return id;
return locale === 'en' ? loc.nameEn || loc.nameEl : locale === 'ru' ? loc.nameRu || loc.nameEl : loc.nameEl || loc.nameEn || id;
};
const TABS = [
{
key: 'stats',
label: t('admin.tab.stats'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
})
})
},
{
key: 'users',
label: t('admin.tab.users'),
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"
}),
/*#__PURE__*/ _jsx("circle", {
cx: "9",
cy: "7",
r: "4"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75"
})
]
})
},
{
key: 'tasks',
label: t('admin.tab.tasks'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
})
})
},
{
key: 'reports',
label: t('admin.tab.reports'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4 flex-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.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
})
})
},
{
key: 'categories',
label: t('admin.tab.categories'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
})
})
},
{
key: 'locations',
label: t('admin.tab.locations'),
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M15 11a3 3 0 11-6 0 3 3 0 016 0z"
})
]
})
},
{
key: 'balances',
label: t('admin.tab.balances', 'Баланс'),
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-2"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M20 12h-6m0 0a2 2 0 100 4h6v-8h-6a2 2 0 100 4z"
})
]
})
},
{
key: 'plans',
label: t('admin.tab.plans'),
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("rect", {
x: "1",
y: "4",
width: "22",
height: "16",
rx: "2",
ry: "2"
}),
/*#__PURE__*/ _jsx("line", {
x1: "1",
y1: "10",
x2: "23",
y2: "10"
})
]
})
},
{
key: 'logs',
label: t('admin.tab.logs'),
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("polyline", {
points: "4 17 10 11 4 5"
}),
/*#__PURE__*/ _jsx("line", {
x1: "12",
y1: "19",
x2: "20",
y2: "19"
})
]
})
},
{
key: 'settings',
label: t('admin.tab.settings'),
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("circle", {
cx: "12",
cy: "12",
r: "3"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"
})
]
})
},
{
key: 'backup',
label: t('admin.tab.backup', 'Backup'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4 flex-shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
})
})
}
];
const statusColors = {
open: 'bg-green-100 text-green-700',
in_progress: 'bg-blue-100 text-blue-700',
completed: 'bg-gray-100 text-gray-600',
cancelled: 'bg-red-100 text-red-600',
draft: 'bg-yellow-100 text-yellow-700'
};
const reportStatusColors = {
pending: 'bg-yellow-100 text-yellow-700',
reviewed: 'bg-green-100 text-green-700',
dismissed: 'bg-gray-100 text-gray-500'
};
const reasonColors = {
spam: 'bg-orange-100 text-orange-700',
inappropriate: 'bg-red-100 text-red-700',
fraud: 'bg-purple-100 text-purple-700',
duplicate: 'bg-blue-100 text-blue-700',
other: 'bg-gray-100 text-gray-600'
};
return /*#__PURE__*/ _jsx("div", {
className: "min-h-screen bg-gray-50",
children: /*#__PURE__*/ _jsxs("div", {
className: "max-w-7xl mx-auto px-4 py-8",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between mb-6",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-3",
children: [
/*#__PURE__*/ _jsx("svg", {
className: "w-7 h-7 text-yellow-500",
fill: "currentColor",
viewBox: "0 0 24 24",
children: /*#__PURE__*/ _jsx("path", {
d: "M5 16L3 5l5.5 5L12 4l3.5 6L21 5l-2 11H5zm0 3a1 1 0 000 2h14a1 1 0 000-2H5z"
})
}),
/*#__PURE__*/ _jsx("h1", {
className: "text-2xl font-bold text-gray-900",
children: t('admin.title')
})
]
}),
/*#__PURE__*/ _jsxs(Link, {
href: "/",
className: "flex items-center gap-1.5 text-sm text-gray-500 hover:text-blue-600 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: "M15 19l-7-7 7-7"
})
}),
t('admin.back_home')
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-6",
children: [
/*#__PURE__*/ _jsx("aside", {
className: `shrink-0 transition-all duration-200 ${sidebarCollapsed ? 'w-12' : 'w-52'}`,
children: /*#__PURE__*/ _jsxs("nav", {
className: "bg-white rounded-xl border border-gray-200 overflow-hidden",
children: [
/*#__PURE__*/ _jsx("button", {
type: "button",
onClick: ()=>setSidebarCollapsed((v)=>!v),
title: sidebarCollapsed ? 'Развернуть меню' : 'Свернуть меню',
className: "w-full flex items-center justify-center py-2.5 text-gray-400 hover:text-gray-600 hover:bg-gray-50 border-b border-gray-100 transition",
children: /*#__PURE__*/ _jsx("svg", {
className: `w-4 h-4 transition-transform duration-200 ${sidebarCollapsed ? 'rotate-180' : ''}`,
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M15 19l-7-7 7-7"
})
})
}),
TABS.map(({ key, label, icon })=>/*#__PURE__*/ _jsxs("button", {
onClick: ()=>setTab(key),
title: sidebarCollapsed ? label : undefined,
className: `w-full flex items-center py-3 text-sm font-medium text-left transition ${tab === key ? 'bg-blue-50 text-blue-700 border-r-2 border-blue-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'} ${sidebarCollapsed ? 'justify-center px-3' : 'gap-3 px-4'}`,
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-4 h-4 flex-shrink-0 flex items-center justify-center",
children: icon
}),
!sidebarCollapsed && /*#__PURE__*/ _jsx("span", {
children: label
})
]
}, key))
]
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 min-w-0",
children: [
tab === 'stats' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-6",
children: [
/*#__PURE__*/ _jsx("div", {
className: "grid grid-cols-2 md:grid-cols-5 gap-4",
children: [
{
label: t('admin.stats.users'),
value: stats?.userCount,
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-8 h-8",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
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"
})
}),
color: 'text-blue-600'
},
{
label: t('admin.stats.specialists'),
value: stats?.specialistCount,
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-8 h-8",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
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"
})
]
}),
color: 'text-purple-600'
},
{
label: t('admin.stats.tasks'),
value: stats?.taskCount,
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-8 h-8",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
})
}),
color: 'text-green-600'
},
{
label: t('admin.stats.offers'),
value: stats?.offerCount,
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-8 h-8",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M8 12h.01M12 12h.01M16 12h.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"
})
}),
color: 'text-orange-500'
},
{
label: t('admin.stats.reviews'),
value: stats?.reviewCount,
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-8 h-8",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z"
})
}),
color: 'text-yellow-500'
}
].map(({ label, value, icon, color })=>/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-5",
children: [
/*#__PURE__*/ _jsx("div", {
className: `mb-2 ${color}`,
children: icon
}),
/*#__PURE__*/ _jsx("div", {
className: `text-3xl font-bold ${color}`,
children: value ?? '—'
}),
/*#__PURE__*/ _jsx("div", {
className: "text-sm text-gray-500 mt-1",
children: label
})
]
}, label))
}),
stats?.tasksByDay && /*#__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("h2", {
className: "font-semibold text-gray-800",
children: t('admin.stats.activity_30d')
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-4 text-xs text-gray-500",
children: [
/*#__PURE__*/ _jsxs("span", {
className: "flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-3 h-0.5 bg-blue-500 inline-block rounded"
}),
t('admin.stats.users_label')
]
}),
/*#__PURE__*/ _jsxs("span", {
className: "flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-3 h-0.5 bg-purple-400 inline-block rounded"
}),
t('admin.stats.specialists_label')
]
}),
/*#__PURE__*/ _jsxs("span", {
className: "flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-3 h-0.5 bg-green-500 inline-block rounded"
}),
t('admin.stats.tasks_label')
]
})
]
})
]
}),
/*#__PURE__*/ _jsx(AdminAreaChart, {
series: [
{
data: stats.usersByDay,
color: '#3b82f6',
fill: '#3b82f615',
label: t('admin.stats.users_label')
},
{
data: stats.specialistsByDay,
color: '#a855f7',
fill: '#a855f710',
label: t('admin.stats.specialists_label')
},
{
data: stats.tasksByDay,
color: '#22c55e',
fill: '#22c55e10',
label: t('admin.stats.tasks_label')
}
]
})
]
}),
stats?.tasksByStatus && /*#__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-5",
children: t('admin.stats.tasks_by_status')
}),
/*#__PURE__*/ _jsx("div", {
className: "space-y-3",
children: (()=>{
const total = stats.tasksByStatus.reduce((s, r)=>s + Number(r.count), 0) || 1;
const statusMeta = {
open: {
label: t('admin.task_status.open'),
bg: 'bg-green-50',
bar: 'bg-green-500'
},
in_progress: {
label: t('admin.task_status.in_progress'),
bg: 'bg-blue-50',
bar: 'bg-blue-500'
},
completed: {
label: t('admin.task_status.completed'),
bg: 'bg-gray-50',
bar: 'bg-gray-400'
},
cancelled: {
label: t('admin.task_status.cancelled'),
bg: 'bg-red-50',
bar: 'bg-red-400'
},
draft: {
label: t('admin.task_status.draft'),
bg: 'bg-yellow-50',
bar: 'bg-yellow-400'
}
};
const order = [
'open',
'in_progress',
'completed',
'draft',
'cancelled'
];
const sorted = [
...stats.tasksByStatus
].sort((a, b)=>order.indexOf(a.status) - order.indexOf(b.status));
return sorted.map(({ status, count: c })=>{
const meta = statusMeta[status] ?? {
label: status,
bg: 'bg-gray-50',
bar: 'bg-gray-300'
};
const pct = Math.round(Number(c) / total * 100);
return /*#__PURE__*/ _jsxs("div", {
className: `flex items-center gap-3 px-3 py-2 rounded-lg ${meta.bg}`,
children: [
/*#__PURE__*/ _jsx("span", {
className: "text-sm text-gray-600 w-28 shrink-0",
children: meta.label
}),
/*#__PURE__*/ _jsx("div", {
className: "flex-1 bg-gray-200 rounded-full h-2 overflow-hidden",
children: /*#__PURE__*/ _jsx("div", {
className: `h-full rounded-full ${meta.bar} transition-all`,
style: {
width: `${pct}%`
}
})
}),
/*#__PURE__*/ _jsx("span", {
className: "text-sm font-semibold text-gray-700 w-8 text-right",
children: c
}),
/*#__PURE__*/ _jsxs("span", {
className: "text-xs text-gray-400 w-8",
children: [
pct,
"%"
]
})
]
}, status);
});
})()
})
]
}),
notifsByDay.length > 0 && /*#__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("h2", {
className: "font-semibold text-gray-800",
children: t('admin.stats.notif_chart_title')
}),
/*#__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 bg-orange-500 inline-block rounded"
}),
t('admin.stats.notif_label')
]
})
]
}),
/*#__PURE__*/ _jsx(AdminAreaChart, {
series: [
{
data: notifsByDay,
color: '#f97316',
fill: '#f9731615',
label: t('admin.stats.notif_label')
}
]
})
]
}),
mailByDay.length > 0 && /*#__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("h2", {
className: "font-semibold text-gray-800",
children: t('admin.stats.mail_chart_title')
}),
/*#__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 bg-sky-500 inline-block rounded"
}),
t('admin.stats.mail_label')
]
})
]
}),
/*#__PURE__*/ _jsx(AdminAreaChart, {
series: [
{
data: mailByDay,
color: '#0ea5e9',
fill: '#0ea5e915',
label: t('admin.stats.mail_label')
}
]
})
]
}),
stats && /*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-6 space-y-5",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between",
children: [
/*#__PURE__*/ _jsx("h2", {
className: "font-semibold text-gray-800",
children: t('admin.stats.tokens_title')
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-4 text-xs text-gray-500",
children: [
/*#__PURE__*/ _jsxs("span", {
className: "flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-3 h-0.5 bg-violet-500 inline-block rounded"
}),
t('admin.stats.tokens_out')
]
}),
/*#__PURE__*/ _jsxs("span", {
className: "flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsx("span", {
className: "w-3 h-0.5 bg-sky-500 inline-block rounded"
}),
t('admin.stats.tokens_in')
]
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-3 gap-4",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "rounded-lg bg-violet-50 border border-violet-100 px-4 py-3",
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-violet-600 mb-1",
children: t('admin.stats.tokens_out_label')
}),
/*#__PURE__*/ _jsx("div", {
className: "text-2xl font-bold text-violet-700",
children: Number(stats.totalOutputTokens).toLocaleString()
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "rounded-lg bg-sky-50 border border-sky-100 px-4 py-3",
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-sky-600 mb-1",
children: t('admin.stats.tokens_in_label')
}),
/*#__PURE__*/ _jsx("div", {
className: "text-2xl font-bold text-sky-700",
children: Number(stats.totalInputTokens).toLocaleString()
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "rounded-lg bg-emerald-50 border border-emerald-100 px-4 py-3",
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-emerald-600 mb-1",
children: t('admin.stats.cost_label')
}),
/*#__PURE__*/ _jsxs("div", {
className: "text-2xl font-bold text-emerald-700",
children: [
"$",
Number(stats.totalCostUsd ?? 0).toFixed(4)
]
})
]
})
]
}),
stats.tokensByMonth?.length > 0 && /*#__PURE__*/ _jsx(AdminMonthChart, {
dateLocale: dateLocale,
series: [
{
data: stats.tokensByMonth.map((r)=>({
month: r.month,
count: Number(r.output)
})),
color: '#8b5cf6',
fill: '#8b5cf610',
label: t('admin.stats.tokens_out_label')
},
{
data: stats.tokensByMonth.map((r)=>({
month: r.month,
count: Number(r.input)
})),
color: '#0ea5e9',
fill: '#0ea5e915',
label: t('admin.stats.tokens_in_label')
}
]
})
]
})
]
}),
tab === 'users' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-3 mb-4",
children: [
/*#__PURE__*/ _jsxs("form", {
className: "flex gap-2 flex-1",
onSubmit: (e)=>{
e.preventDefault();
setUsersQ(usersQInput);
},
children: [
/*#__PURE__*/ _jsx("input", {
value: usersQInput,
onChange: (e)=>setUsersQInput(e.target.value),
placeholder: t('admin.users.search.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: "submit",
className: "px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700",
children: t('tasks.search.btn')
})
]
}),
/*#__PURE__*/ _jsxs("select", {
value: usersRole,
onChange: (e)=>setUsersRole(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-2 text-sm",
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: t('admin.filter.all_roles')
}),
/*#__PURE__*/ _jsx("option", {
value: "customer",
children: t('profile.role.customer')
}),
/*#__PURE__*/ _jsx("option", {
value: "specialist",
children: t('profile.role.specialist')
}),
/*#__PURE__*/ _jsx("option", {
value: "admin",
children: t('profile.role.admin')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 overflow-hidden",
children: [
/*#__PURE__*/ _jsxs("table", {
className: "w-full text-sm",
children: [
/*#__PURE__*/ _jsx("thead", {
className: "bg-gray-50 text-left",
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.user')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.email')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.role')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: "Тариф"
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.registered')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.status')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3"
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
className: "divide-y divide-gray-100",
children: loading ? /*#__PURE__*/ _jsx("tr", {
children: /*#__PURE__*/ _jsx("td", {
colSpan: 6,
className: "px-4 py-8 text-center text-gray-400",
children: t('common.loading')
})
}) : users.length === 0 ? /*#__PURE__*/ _jsx("tr", {
children: /*#__PURE__*/ _jsx("td", {
colSpan: 6,
className: "px-4 py-8 text-center text-gray-400",
children: "—"
})
}) : users.map((u)=>/*#__PURE__*/ _jsxs("tr", {
className: "hover:bg-gray-50",
children: [
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 font-medium text-gray-800",
children: formatShortName(u.firstName, u.lastName, u.name)
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500",
children: u.email
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3",
children: /*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${u.role === 'admin' ? 'bg-red-100 text-red-700' : u.role === 'specialist' ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 text-gray-600'}`,
children: t(`profile.role.${u.role}`) || u.role
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-400 text-xs",
children: u.planId ? planRows.find((p)=>p.id === u.planId)?.name ?? /*#__PURE__*/ _jsxs("span", {
className: "font-mono",
children: [
u.planId.slice(0, 8),
"…"
]
}) : /*#__PURE__*/ _jsx("span", {
className: "text-gray-300",
children: "—"
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-400",
children: new Date(u.createdAt).toLocaleDateString(dateLocale)
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3",
children: /*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${u.isActive !== false ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-600'}`,
children: u.isActive !== false ? t('admin.users.active') : t('admin.users.inactive')
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-right",
children: /*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-end gap-1.5",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: ()=>openEditUser(u),
className: "text-xs px-2.5 py-1 rounded-lg font-medium bg-gray-50 text-gray-600 hover:bg-gray-100 border border-gray-200",
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: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
})
})
}),
u.role !== 'admin' && /*#__PURE__*/ _jsx("button", {
onClick: ()=>toggleUser(u.id, u.isActive !== false),
className: `text-xs px-3 py-1 rounded-lg font-medium ${u.isActive !== false ? 'bg-red-50 text-red-600 hover:bg-red-100' : 'bg-green-50 text-green-600 hover:bg-green-100'}`,
children: u.isActive !== false ? t('admin.users.deactivate') : t('admin.users.activate')
})
]
})
})
]
}, u.id))
})
]
}),
/*#__PURE__*/ _jsx(Pagination, {
page: usersPage,
total: usersTotal,
limit: 20,
onChange: setUsersPage,
totalLabel: t('admin.pagination.total')
})
]
})
]
}),
tab === 'balances' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex flex-wrap gap-3 mb-4",
children: [
/*#__PURE__*/ _jsx("input", {
value: balanceUserId,
onChange: (e)=>setBalanceUserId(e.target.value),
placeholder: t('admin.balance.filter.user_id', 'Фильтр по userId'),
className: "flex-1 min-w-72 border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400"
}),
/*#__PURE__*/ _jsxs("select", {
value: balanceKind,
onChange: (e)=>setBalanceKind(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-2 text-sm",
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: t('admin.balance.filter.all', 'Все операции')
}),
/*#__PURE__*/ _jsx("option", {
value: "topup",
children: t('admin.balance.kind.topup', 'Пополнение')
}),
/*#__PURE__*/ _jsx("option", {
value: "plan_purchase",
children: t('admin.balance.kind.plan_purchase', 'Списание за тариф')
}),
/*#__PURE__*/ _jsx("option", {
value: "admin_topup",
children: t('admin.balance.kind.admin_topup', 'Пополнение админом')
}),
/*#__PURE__*/ _jsx("option", {
value: "admin_adjustment",
children: t('admin.balance.kind.admin_adjustment', 'Корректировка')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 overflow-hidden",
children: [
/*#__PURE__*/ _jsxs("table", {
className: "w-full text-sm",
children: [
/*#__PURE__*/ _jsx("thead", {
className: "bg-gray-50 text-left",
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.user')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.balance.col.operation', 'Операция')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.balance.col.amount', 'Сумма')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.balance.col.result', 'Баланс')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.balance.col.description', 'Описание')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.balance.col.date', 'Дата')
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
className: "divide-y divide-gray-100",
children: loading ? /*#__PURE__*/ _jsx("tr", {
children: /*#__PURE__*/ _jsx("td", {
colSpan: 6,
className: "px-4 py-8 text-center text-gray-400",
children: t('common.loading')
})
}) : balanceRows.length === 0 ? /*#__PURE__*/ _jsx("tr", {
children: /*#__PURE__*/ _jsx("td", {
colSpan: 6,
className: "px-4 py-8 text-center text-gray-400",
children: t('admin.balance.empty', 'Записей пока нет')
})
}) : balanceRows.map((row)=>{
const isCredit = row.direction === 'credit';
const kindLabel = row.kind === 'topup' ? t('admin.balance.kind.topup', 'Пополнение') : row.kind === 'plan_purchase' ? t('admin.balance.kind.plan_purchase', 'Списание за тариф') : row.kind === 'admin_topup' ? t('admin.balance.kind.admin_topup', 'Пополнение админом') : t('admin.balance.kind.admin_adjustment', 'Корректировка');
return /*#__PURE__*/ _jsxs("tr", {
className: "hover:bg-gray-50 align-top",
children: [
/*#__PURE__*/ _jsxs("td", {
className: "px-4 py-3",
children: [
/*#__PURE__*/ _jsx("div", {
className: "font-medium text-gray-800",
children: row.userName || '—'
}),
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-gray-500 mt-0.5",
children: row.userEmail || row.userId
})
]
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3",
children: /*#__PURE__*/ _jsx("span", {
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${isCredit ? 'bg-emerald-50 text-emerald-700' : 'bg-rose-50 text-rose-700'}`,
children: kindLabel
})
}),
/*#__PURE__*/ _jsxs("td", {
className: `px-4 py-3 font-semibold ${isCredit ? 'text-emerald-700' : 'text-rose-700'}`,
children: [
isCredit ? '+' : '-',
Number(row.amount).toFixed(2),
" ",
row.currency
]
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-600",
children: /*#__PURE__*/ _jsxs("div", {
children: [
Number(row.balanceBefore).toFixed(2),
" → ",
Number(row.balanceAfter).toFixed(2),
" ",
row.currency
]
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500 max-w-sm",
children: row.description || '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500 whitespace-nowrap",
children: new Date(row.createdAt).toLocaleString(dateLocale)
})
]
}, row.id);
})
})
]
}),
/*#__PURE__*/ _jsx(Pagination, {
page: balancePage,
total: balanceTotal,
limit: 50,
onChange: setBalancePage,
totalLabel: t('admin.pagination.total')
})
]
})
]
}),
tab === 'tasks' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-3 mb-4",
children: [
/*#__PURE__*/ _jsxs("form", {
className: "flex gap-2 flex-1",
onSubmit: (e)=>{
e.preventDefault();
setTasksQ(tasksQInput);
},
children: [
/*#__PURE__*/ _jsx("input", {
value: tasksQInput,
onChange: (e)=>setTasksQInput(e.target.value),
placeholder: t('admin.tasks.search.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: "submit",
className: "px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700",
children: t('tasks.search.btn')
})
]
}),
/*#__PURE__*/ _jsxs("select", {
value: tasksStatus,
onChange: (e)=>setTasksStatus(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-2 text-sm",
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: t('admin.filter.all_statuses')
}),
[
'open',
'in_progress',
'completed',
'cancelled',
'draft'
].map((s)=>/*#__PURE__*/ _jsx("option", {
value: s,
children: t(`task.status.${s}`, s)
}, s))
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 overflow-hidden",
children: [
/*#__PURE__*/ _jsxs("table", {
className: "w-full text-sm",
children: [
/*#__PURE__*/ _jsx("thead", {
className: "bg-gray-50 text-left",
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.title')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.customer')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.status')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.budget')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 font-medium text-gray-600",
children: t('admin.col.created')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3"
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
className: "divide-y divide-gray-100",
children: loading ? /*#__PURE__*/ _jsx("tr", {
children: /*#__PURE__*/ _jsx("td", {
colSpan: 6,
className: "px-4 py-8 text-center text-gray-400",
children: t('common.loading')
})
}) : tasks.length === 0 ? /*#__PURE__*/ _jsx("tr", {
children: /*#__PURE__*/ _jsx("td", {
colSpan: 6,
className: "px-4 py-8 text-center text-gray-400",
children: "—"
})
}) : tasks.map((row)=>{
const task = row.task || row;
const customer = row.customer;
return /*#__PURE__*/ _jsxs("tr", {
className: "hover:bg-gray-50",
children: [
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 font-medium text-gray-800 max-w-xs",
children: /*#__PURE__*/ _jsx(Link, {
href: `/tasks/${task.id}`,
className: "hover:text-blue-600 truncate block",
target: "_blank",
children: task.title
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500 text-xs",
children: customer?.name ?? '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3",
children: /*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${statusColors[task.status] ?? 'bg-gray-100 text-gray-600'}`,
children: t(`task.status.${task.status}`, task.status)
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500",
children: task.budget ? `${formatPrice(task.budget)}€` : '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-400",
children: new Date(task.createdAt).toLocaleDateString(dateLocale)
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-right",
children: /*#__PURE__*/ _jsxs("div", {
className: "flex gap-1.5 justify-end",
children: [
task.status !== 'cancelled' && task.status !== 'completed' && /*#__PURE__*/ _jsx("button", {
onClick: ()=>cancelTask(task.id),
className: "text-xs px-2.5 py-1 rounded-lg font-medium bg-yellow-50 text-yellow-700 hover:bg-yellow-100",
children: t('admin.tasks.cancel')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>deleteTask(task.id, task.title),
className: "text-xs px-2.5 py-1 rounded-lg font-medium bg-red-50 text-red-600 hover:bg-red-100",
children: t('admin.tasks.delete')
})
]
})
})
]
}, task.id);
})
})
]
}),
/*#__PURE__*/ _jsx(Pagination, {
page: tasksPage,
total: tasksTotal,
limit: 20,
onChange: setTasksPage,
totalLabel: t('admin.pagination.total')
})
]
})
]
}),
tab === 'categories' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex justify-between items-center mb-4",
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-500",
children: t('admin.cat.hint')
}),
/*#__PURE__*/ _jsxs("button", {
onClick: ()=>openAddCat(null),
className: "px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700",
children: [
"+ ",
t('admin.cat.add_root')
]
})
]
}),
catForm && /*#__PURE__*/ _jsxs("div", {
className: "bg-blue-50 border border-blue-200 rounded-xl p-5 mb-4",
children: [
/*#__PURE__*/ _jsxs("h3", {
className: "font-semibold text-gray-800 mb-4",
children: [
catForm.id ? t('admin.cat.edit') : t('admin.cat.new'),
catForm.parentId && /*#__PURE__*/ _jsxs("span", {
className: "text-xs text-gray-400 ml-2",
children: [
"(",
t('admin.cat.subcategory'),
")"
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-2 md:grid-cols-3 gap-3 mb-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.cat.slug')
}),
/*#__PURE__*/ _jsx("input", {
value: catForm.slug,
onChange: (e)=>setCatForm((f)=>f && {
...f,
slug: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm",
placeholder: "e.g. repairs"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.cat.icon')
}),
/*#__PURE__*/ _jsx("input", {
value: catForm.icon,
onChange: (e)=>setCatForm((f)=>f && {
...f,
icon: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm",
placeholder: "\uD83D\uDCE6"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.cat.order')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
value: catForm.order,
onChange: (e)=>setCatForm((f)=>f && {
...f,
order: Number(e.target.value)
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: [
t('admin.cat.name_el'),
" \uD83C\uDDEC\uD83C\uDDF7"
]
}),
/*#__PURE__*/ _jsx("input", {
value: catForm.namesEl,
onChange: (e)=>setCatForm((f)=>f && {
...f,
namesEl: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: [
t('admin.cat.name_en'),
" \uD83C\uDDEC\uD83C\uDDE7"
]
}),
/*#__PURE__*/ _jsx("input", {
value: catForm.namesEn,
onChange: (e)=>setCatForm((f)=>f && {
...f,
namesEn: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: [
t('admin.cat.name_ru'),
" \uD83C\uDDF7\uD83C\uDDFA"
]
}),
/*#__PURE__*/ _jsx("input", {
value: catForm.namesRu,
onChange: (e)=>setCatForm((f)=>f && {
...f,
namesRu: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
})
]
}),
catForm.id && /*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 text-sm text-gray-700 mb-3",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: catForm.isActive,
onChange: (e)=>setCatForm((f)=>f && {
...f,
isActive: e.target.checked
})
}),
t('admin.cat.active')
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-2",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: saveCat,
disabled: catSaving,
className: "px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: catSaving ? t('common.saving') : t('common.save')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setCatForm(null),
className: "px-4 py-2 bg-white border border-gray-300 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-50",
children: t('common.cancel')
})
]
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "bg-white rounded-xl border border-gray-200 divide-y divide-gray-100",
children: catRows.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "px-4 py-8 text-center text-gray-400",
children: t('admin.cat.empty')
}) : /*#__PURE__*/ _jsx(CatTree, {
rows: catRows,
parentId: null,
depth: 0,
locale: locale,
expanded: catExpanded,
onToggle: toggleCatExpand,
onEdit: openEditCat,
onDelete: deleteCat,
onAddChild: openAddCat,
t: t
})
})
]
}),
tab === 'locations' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex justify-between items-center mb-4",
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-500",
children: t('admin.loc.hint')
}),
/*#__PURE__*/ _jsxs("button", {
onClick: ()=>openAddLoc(null),
className: "px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700",
children: [
"+ ",
t('admin.loc.add_city')
]
})
]
}),
locForm && /*#__PURE__*/ _jsxs("div", {
className: "bg-blue-50 border border-blue-200 rounded-xl p-5 mb-4",
children: [
/*#__PURE__*/ _jsxs("h3", {
className: "font-semibold text-gray-800 mb-4",
children: [
locForm.id ? t('admin.loc.edit') : t('admin.loc.new'),
locForm.parentId && /*#__PURE__*/ _jsxs("span", {
className: "text-xs text-gray-400 ml-2",
children: [
"(",
t('admin.loc.district'),
")"
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-2 md:grid-cols-4 gap-3 mb-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.cat.slug')
}),
/*#__PURE__*/ _jsx("input", {
value: locForm.slug,
onChange: (e)=>setLocForm((f)=>f && {
...f,
slug: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm",
placeholder: "e.g. athens-center"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: [
t('admin.cat.name_el'),
" \uD83C\uDDEC\uD83C\uDDF7"
]
}),
/*#__PURE__*/ _jsx("input", {
value: locForm.nameEl,
onChange: (e)=>setLocForm((f)=>f && {
...f,
nameEl: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: [
t('admin.cat.name_en'),
" \uD83C\uDDEC\uD83C\uDDE7"
]
}),
/*#__PURE__*/ _jsx("input", {
value: locForm.nameEn,
onChange: (e)=>setLocForm((f)=>f && {
...f,
nameEn: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: [
t('admin.cat.name_ru'),
" \uD83C\uDDF7\uD83C\uDDFA"
]
}),
/*#__PURE__*/ _jsx("input", {
value: locForm.nameRu,
onChange: (e)=>setLocForm((f)=>f && {
...f,
nameRu: e.target.value
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-4 mb-3",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "w-24",
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.cat.order')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
value: locForm.order,
onChange: (e)=>setLocForm((f)=>f && {
...f,
order: Number(e.target.value)
}),
className: "w-full border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
locForm.id && /*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 text-sm text-gray-700 mt-4",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: locForm.isActive,
onChange: (e)=>setLocForm((f)=>f && {
...f,
isActive: e.target.checked
})
}),
t('admin.cat.active')
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-2",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: saveLoc,
disabled: locSaving,
className: "px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: locSaving ? t('common.saving') : t('common.save')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setLocForm(null),
className: "px-4 py-2 bg-white border border-gray-300 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-50",
children: t('common.cancel')
})
]
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "bg-white rounded-xl border border-gray-200 divide-y divide-gray-100",
children: locRows.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "px-4 py-8 text-center text-gray-400",
children: t('admin.loc.empty')
}) : /*#__PURE__*/ _jsx(LocTree, {
rows: locRows,
parentId: null,
depth: 0,
locale: locale,
expanded: locExpanded,
onToggle: toggleLocExpand,
onEdit: openEditLoc,
onDelete: deleteLoc,
onAddChild: openAddLoc,
t: t
})
})
]
}),
tab === 'reports' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-3",
children: [
loading ? /*#__PURE__*/ _jsx("div", {
className: "text-center py-10 text-gray-400",
children: t('common.loading')
}) : reports.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "text-center py-10 text-gray-400",
children: t('admin.reports.none')
}) : reports.map((r)=>/*#__PURE__*/ _jsx("div", {
className: "bg-white rounded-xl border border-gray-200 p-5",
children: /*#__PURE__*/ _jsxs("div", {
className: "flex items-start justify-between gap-4",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 min-w-0",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-2 flex-wrap mb-2",
children: [
/*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${reportStatusColors[r.status] ?? 'bg-gray-100 text-gray-500'}`,
children: r.status
}),
/*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${reasonColors[r.reason] ?? 'bg-gray-100 text-gray-600'}`,
children: r.reason
}),
/*#__PURE__*/ _jsxs("span", {
className: "text-xs text-gray-400",
children: [
r.targetType === 'task' ? t('admin.reports.target.task') : t('admin.reports.target.user'),
":",
' ',
r.targetTitle ? /*#__PURE__*/ _jsx(Link, {
href: r.targetType === 'task' ? `/tasks/${r.targetId}` : `/users/${r.targetId}`,
className: "text-blue-600 hover:underline font-medium",
target: "_blank",
children: r.targetTitle
}) : /*#__PURE__*/ _jsxs("span", {
className: "font-mono",
children: [
"#",
r.targetId?.slice(0, 8)
]
})
]
})
]
}),
r.reporterName && /*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-400 mb-1",
children: [
t('admin.col.reporter'),
": ",
/*#__PURE__*/ _jsx("span", {
className: "font-medium text-gray-600",
children: r.reporterName
})
]
}),
r.description && /*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-700",
children: r.description
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-1.5",
children: new Date(r.createdAt).toLocaleString(dateLocale)
})
]
}),
r.status === 'pending' && /*#__PURE__*/ _jsxs("div", {
className: "flex gap-2 flex-shrink-0",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: ()=>handleReport(r.id, 'reviewed'),
className: "text-xs px-3 py-1.5 rounded-lg font-medium bg-green-50 text-green-700 hover:bg-green-100",
children: t('admin.reports.reviewed')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>handleReport(r.id, 'dismissed'),
className: "text-xs px-3 py-1.5 rounded-lg font-medium bg-gray-100 text-gray-600 hover:bg-gray-200",
children: t('admin.reports.dismiss')
})
]
})
]
})
}, r.id)),
/*#__PURE__*/ _jsx(Pagination, {
page: reportsPage,
total: reportsTotal,
limit: 20,
onChange: setReportsPage,
totalLabel: t('admin.pagination.total')
})
]
}),
tab === 'logs' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "flex gap-1 bg-gray-100 rounded-xl p-1 mb-5 w-fit",
children: [
{
key: 'ai',
label: t('admin.logs.subtab.ai')
},
{
key: 'activity',
label: t('admin.logs.subtab.activity')
},
{
key: 'mail',
label: t('admin.logs.subtab.mail')
},
{
key: 'notifications',
label: t('admin.logs.subtab.notifications')
}
].map(({ key, label })=>/*#__PURE__*/ _jsx("button", {
onClick: ()=>setLogsSubTab(key),
className: `px-4 py-1.5 rounded-lg text-sm font-medium transition-colors ${logsSubTab === key ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-500 hover:text-gray-700'}`,
children: label
}, key))
}),
logsSubTab === 'ai' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex justify-between items-center mb-4",
children: [
/*#__PURE__*/ _jsxs("p", {
className: "text-sm text-gray-500",
children: [
t('admin.pagination.total'),
": ",
logsTotal
]
}),
/*#__PURE__*/ _jsxs("button", {
onClick: ()=>{
setLogsPage(1);
api.getAdminAiLogs(1).then((d)=>{
setLogs(d.data);
setLogsTotal(d.total);
}).catch(()=>{});
},
className: "text-xs px-3 py-1.5 rounded-lg bg-gray-100 text-gray-600 hover:bg-gray-200 flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("polyline", {
points: "23 4 23 10 17 10"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M20.49 15a9 9 0 11-2.12-9.36L23 10"
})
]
}),
t('common.refresh')
]
})
]
}),
loading ? /*#__PURE__*/ _jsx("div", {
className: "text-center py-10 text-gray-400",
children: t('common.loading')
}) : logs.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "text-center py-10 text-gray-400",
children: t('admin.logs.empty')
}) : /*#__PURE__*/ _jsx("div", {
className: "overflow-x-auto rounded-xl border border-gray-200",
children: /*#__PURE__*/ _jsxs("table", {
className: "w-full text-sm",
children: [
/*#__PURE__*/ _jsx("thead", {
className: "bg-gray-50 text-gray-500 text-xs uppercase",
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.logs.date')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.logs.provider')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.logs.model')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.logs.action')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.logs.langs')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-right",
children: t('admin.logs.in')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-right",
children: t('admin.logs.out')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-right",
children: t('admin.logs.total')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-right",
children: t('admin.logs.ms')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-center",
children: t('admin.logs.status')
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
className: "divide-y divide-gray-100",
children: logs.map((log)=>/*#__PURE__*/ _jsxs("tr", {
className: "bg-white hover:bg-gray-50",
children: [
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500 whitespace-nowrap",
children: new Date(log.createdAt).toLocaleString(dateLocale)
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3",
children: /*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${log.provider === 'anthropic' ? 'bg-purple-100 text-purple-700' : 'bg-green-100 text-green-700'}`,
children: log.provider
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-600 font-mono text-xs",
children: log.model
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-600",
children: log.action
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500",
children: log.fromLocale && log.toLocale ? `${log.fromLocale} → ${log.toLocale}` : '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-right text-gray-600",
children: log.inputTokens ?? '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-right text-gray-600",
children: log.outputTokens ?? '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-right font-medium",
children: log.totalTokens ?? '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-right text-gray-500",
children: log.durationMs ?? '—'
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-center",
children: log.success ? /*#__PURE__*/ _jsx("span", {
className: "text-green-600 flex justify-center",
children: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "20 6 9 17 4 12"
})
})
}) : /*#__PURE__*/ _jsx("span", {
className: "text-red-500 flex justify-center",
title: log.error ?? '',
children: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: [
/*#__PURE__*/ _jsx("line", {
x1: "18",
y1: "6",
x2: "6",
y2: "18"
}),
/*#__PURE__*/ _jsx("line", {
x1: "6",
y1: "6",
x2: "18",
y2: "18"
})
]
})
})
})
]
}, log.id))
})
]
})
}),
/*#__PURE__*/ _jsx(Pagination, {
page: logsPage,
total: logsTotal,
limit: 50,
onChange: setLogsPage,
totalLabel: t('admin.pagination.total')
})
]
}),
logsSubTab === 'activity' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-4 mb-4 flex flex-wrap gap-3 items-end",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.activity.event')
}),
/*#__PURE__*/ _jsxs("select", {
value: activityEvent,
onChange: (e)=>setActivityEvent(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm min-w-[180px]",
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: t('admin.activity.all_events')
}),
activityEventTypes.map((ev)=>/*#__PURE__*/ _jsx("option", {
value: ev,
children: ev
}, ev))
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.activity.from')
}),
/*#__PURE__*/ _jsx("input", {
type: "date",
value: activityDateFrom,
onChange: (e)=>setActivityDateFrom(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.activity.to')
}),
/*#__PURE__*/ _jsx("input", {
type: "date",
value: activityDateTo,
onChange: (e)=>setActivityDateTo(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
(activityEvent || activityDateFrom || activityDateTo || activityUserId) && /*#__PURE__*/ _jsxs("button", {
onClick: ()=>{
setActivityEvent('');
setActivityDateFrom('');
setActivityDateTo('');
setActivityUserId('');
},
className: "text-xs px-3 py-1.5 rounded-lg bg-gray-100 text-gray-500 hover:bg-gray-200 self-end flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-3 h-3",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: [
/*#__PURE__*/ _jsx("line", {
x1: "18",
y1: "6",
x2: "6",
y2: "18"
}),
/*#__PURE__*/ _jsx("line", {
x1: "6",
y1: "6",
x2: "18",
y2: "18"
})
]
}),
t('admin.activity.reset')
]
}),
/*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-400 self-end ml-auto",
children: [
t('admin.activity.total'),
": ",
activityTotal
]
})
]
}),
activityLog.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "text-center py-10 text-gray-400",
children: t('admin.activity.empty')
}) : /*#__PURE__*/ _jsx("div", {
className: "space-y-2",
children: activityLog.map((entry)=>/*#__PURE__*/ _jsx(ActivityLogRow, {
entry: entry,
dateLocale: dateLocale,
onFilterUser: (id)=>{
setActivityUserId(id);
setActivityEvent('');
},
t: t
}, entry.id))
}),
/*#__PURE__*/ _jsx(Pagination, {
page: activityPage,
total: activityTotal,
limit: 50,
onChange: setActivityPage,
totalLabel: t('admin.pagination.total')
})
]
}),
logsSubTab === 'mail' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-4 mb-4 flex flex-wrap gap-3 items-end",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.mail.event')
}),
/*#__PURE__*/ _jsxs("select", {
value: mailEvent,
onChange: (e)=>setMailEvent(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm min-w-[200px]",
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: t('admin.mail.all_events')
}),
mailEventTypes.map((ev)=>/*#__PURE__*/ _jsx("option", {
value: ev,
children: t(`admin.event.${ev.replace(/\./g, '_')}`, ev)
}, ev))
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.mail.from')
}),
/*#__PURE__*/ _jsx("input", {
type: "date",
value: mailDateFrom,
onChange: (e)=>setMailDateFrom(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.mail.to')
}),
/*#__PURE__*/ _jsx("input", {
type: "date",
value: mailDateTo,
onChange: (e)=>setMailDateTo(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
(mailEvent || mailDateFrom || mailDateTo) && /*#__PURE__*/ _jsxs("button", {
onClick: ()=>{
setMailEvent('');
setMailDateFrom('');
setMailDateTo('');
},
className: "text-xs px-3 py-1.5 rounded-lg bg-gray-100 text-gray-500 hover:bg-gray-200 self-end flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-3 h-3",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: [
/*#__PURE__*/ _jsx("line", {
x1: "18",
y1: "6",
x2: "6",
y2: "18"
}),
/*#__PURE__*/ _jsx("line", {
x1: "6",
y1: "6",
x2: "18",
y2: "18"
})
]
}),
t('admin.mail.reset')
]
}),
/*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-400 self-end ml-auto",
children: [
t('admin.mail.total'),
": ",
mailTotal
]
})
]
}),
mailLog.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "text-center py-10 text-gray-400",
children: t('admin.mail.empty')
}) : /*#__PURE__*/ _jsx("div", {
className: "overflow-x-auto rounded-xl border border-gray-200",
children: /*#__PURE__*/ _jsxs("table", {
className: "w-full text-sm",
children: [
/*#__PURE__*/ _jsx("thead", {
className: "bg-gray-50 text-gray-500 text-xs uppercase",
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.logs.date')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.mail.recipient')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.mail.event')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.mail.provider')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.mail.details')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-center",
children: t('admin.mail.status')
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
className: "divide-y divide-gray-100",
children: mailLog.map((entry)=>{
const details = parseLogDetails(entry.details);
const provider = typeof details?.provider === 'string' ? details.provider : '—';
const recipient = typeof details?.to === 'string' ? details.to : entry.userEmail || '—';
const subject = typeof details?.subject === 'string' ? details.subject : '';
const error = typeof details?.error === 'string' ? details.error : '';
const success = entry.event === 'email.sent' || entry.event === 'admin.email.test.sent';
return /*#__PURE__*/ _jsxs("tr", {
className: "bg-white hover:bg-gray-50 align-top",
children: [
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500 whitespace-nowrap",
children: new Date(entry.createdAt).toLocaleString(dateLocale)
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-700",
children: recipient
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3",
children: /*#__PURE__*/ _jsx("span", {
className: "px-2 py-0.5 rounded-full text-xs font-medium bg-sky-50 text-sky-700",
children: t(`admin.event.${entry.event.replace(/\./g, '_')}`, entry.event)
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-600",
children: provider
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-600 max-w-md",
children: /*#__PURE__*/ _jsx("div", {
className: "truncate",
title: subject || error || undefined,
children: subject || error || '—'
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-center",
children: success ? /*#__PURE__*/ _jsx("span", {
className: "text-green-600 inline-flex justify-center",
title: t('admin.mail.success'),
children: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "20 6 9 17 4 12"
})
})
}) : /*#__PURE__*/ _jsx("span", {
className: "text-red-500 inline-flex justify-center",
title: error || t('admin.mail.failed'),
children: /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: [
/*#__PURE__*/ _jsx("line", {
x1: "18",
y1: "6",
x2: "6",
y2: "18"
}),
/*#__PURE__*/ _jsx("line", {
x1: "6",
y1: "6",
x2: "18",
y2: "18"
})
]
})
})
})
]
}, entry.id);
})
})
]
})
}),
/*#__PURE__*/ _jsx(Pagination, {
page: mailPage,
total: mailTotal,
limit: 50,
onChange: setMailPage,
totalLabel: t('admin.pagination.total')
})
]
}),
logsSubTab === 'notifications' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-4 mb-4 flex flex-wrap gap-3 items-end",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.notif_logs.type')
}),
/*#__PURE__*/ _jsxs("select", {
value: notifLogsType,
onChange: (e)=>setNotifLogsType(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm min-w-[200px]",
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: t('admin.filter.all')
}),
notifLogsTypes.map((tp)=>/*#__PURE__*/ _jsx("option", {
value: tp,
children: tp
}, tp))
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.activity.from')
}),
/*#__PURE__*/ _jsx("input", {
type: "date",
value: notifLogsDateFrom,
onChange: (e)=>setNotifLogsDateFrom(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-500 mb-1",
children: t('admin.activity.to')
}),
/*#__PURE__*/ _jsx("input", {
type: "date",
value: notifLogsDateTo,
onChange: (e)=>setNotifLogsDateTo(e.target.value),
className: "border border-gray-300 rounded-lg px-3 py-1.5 text-sm"
})
]
}),
(notifLogsType || notifLogsDateFrom || notifLogsDateTo) && /*#__PURE__*/ _jsxs("button", {
onClick: ()=>{
setNotifLogsType('');
setNotifLogsDateFrom('');
setNotifLogsDateTo('');
},
className: "text-xs px-3 py-1.5 rounded-lg bg-gray-100 text-gray-500 hover:bg-gray-200 self-end flex items-center gap-1.5",
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-3 h-3",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: [
/*#__PURE__*/ _jsx("line", {
x1: "18",
y1: "6",
x2: "6",
y2: "18"
}),
/*#__PURE__*/ _jsx("line", {
x1: "6",
y1: "6",
x2: "18",
y2: "18"
})
]
}),
t('admin.activity.reset')
]
}),
/*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-400 self-end ml-auto",
children: [
t('admin.pagination.total'),
": ",
notifLogsTotal
]
})
]
}),
notifLogs.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "text-center py-10 text-gray-400",
children: t('admin.notif_logs.empty')
}) : /*#__PURE__*/ _jsx("div", {
className: "overflow-x-auto rounded-xl border border-gray-200",
children: /*#__PURE__*/ _jsxs("table", {
className: "w-full text-sm",
children: [
/*#__PURE__*/ _jsx("thead", {
className: "bg-gray-50 text-gray-500 text-xs uppercase",
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.logs.date')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.col.user')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.notif_logs.type')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-left",
children: t('admin.notif_logs.title')
}),
/*#__PURE__*/ _jsx("th", {
className: "px-4 py-3 text-center",
children: t('admin.notif_logs.read')
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
className: "divide-y divide-gray-100",
children: notifLogs.map((n)=>/*#__PURE__*/ _jsxs("tr", {
className: "bg-white hover:bg-gray-50",
children: [
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-500 whitespace-nowrap",
children: new Date(n.createdAt).toLocaleString(dateLocale)
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-700",
children: n.recipientName ?? n.recipientEmail ?? n.recipientId
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3",
children: /*#__PURE__*/ _jsx("span", {
className: "px-2 py-0.5 rounded-full text-xs font-medium bg-blue-50 text-blue-700",
children: n.type
})
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-gray-600 max-w-xs truncate",
children: n.title
}),
/*#__PURE__*/ _jsx("td", {
className: "px-4 py-3 text-center",
children: n.isRead ? /*#__PURE__*/ _jsx("span", {
className: "text-green-600 flex justify-center",
children: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "20 6 9 17 4 12"
})
})
}) : /*#__PURE__*/ _jsx("span", {
className: "text-gray-400 flex justify-center",
children: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("circle", {
cx: "12",
cy: "12",
r: "10"
})
})
})
})
]
}, n.id))
})
]
})
}),
/*#__PURE__*/ _jsx(Pagination, {
page: notifLogsPage,
total: notifLogsTotal,
limit: 50,
onChange: setNotifLogsPage,
totalLabel: t('admin.pagination.total')
})
]
})
]
}),
tab === 'plans' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between mb-4",
children: [
/*#__PURE__*/ _jsxs("h2", {
className: "text-lg font-semibold text-gray-800 flex items-center gap-2",
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-5 h-5 text-blue-600",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: [
/*#__PURE__*/ _jsx("rect", {
x: "1",
y: "4",
width: "22",
height: "16",
rx: "2",
ry: "2"
}),
/*#__PURE__*/ _jsx("line", {
x1: "1",
y1: "10",
x2: "23",
y2: "10"
})
]
}),
t('admin.plans.title')
]
}),
/*#__PURE__*/ _jsx("button", {
onClick: openAddPlan,
className: "bg-blue-600 text-white text-sm px-4 py-2 rounded-lg hover:bg-blue-700 font-medium",
children: t('admin.plans.add')
})
]
}),
planForm && /*#__PURE__*/ _jsxs("div", {
className: "bg-white border border-gray-200 rounded-xl p-5 mb-4 space-y-3",
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800",
children: planForm.id ? t('admin.plans.form.edit') : t('admin.plans.form.new')
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-2 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.plans.form.name')
}),
/*#__PURE__*/ _jsx("input", {
value: planForm.name,
onChange: (e)=>setPlanForm({
...planForm,
name: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.price')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
step: "0.01",
value: planForm.price,
onChange: (e)=>setPlanForm({
...planForm,
price: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.old_price')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
step: "0.01",
value: planForm.oldPrice ?? '',
onChange: (e)=>setPlanForm({
...planForm,
oldPrice: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.role')
}),
/*#__PURE__*/ _jsxs("select", {
value: planForm.role,
onChange: (e)=>setPlanForm({
...planForm,
role: 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: "customer",
children: t('admin.plans.form.role.customer')
}),
/*#__PURE__*/ _jsx("option", {
value: "specialist",
children: t('admin.plans.form.role.specialist')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.plans.form.tier')
}),
/*#__PURE__*/ _jsxs("select", {
value: planForm.tier,
onChange: (e)=>setPlanForm({
...planForm,
tier: 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: "free",
children: t('admin.plans.form.tier.free')
}),
/*#__PURE__*/ _jsx("option", {
value: "pro",
children: t('admin.plans.form.tier.pro')
}),
/*#__PURE__*/ _jsx("option", {
value: "ultimate",
children: t('admin.plans.form.tier.ultimate')
})
]
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.plans.form.description')
}),
/*#__PURE__*/ _jsx("input", {
value: planForm.description,
onChange: (e)=>setPlanForm({
...planForm,
description: 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__*/ _jsx("p", {
className: "text-xs font-semibold text-gray-500 uppercase tracking-wide pt-1",
children: t('admin.plans.form.section.limits')
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-3 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_tasks')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxTasks,
onChange: (e)=>setPlanForm({
...planForm,
maxTasks: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_offers')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxOffers,
onChange: (e)=>setPlanForm({
...planForm,
maxOffers: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_cards')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxCards,
onChange: (e)=>setPlanForm({
...planForm,
maxCards: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_messages_day')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxMessagesPerDay,
onChange: (e)=>setPlanForm({
...planForm,
maxMessagesPerDay: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_orders_day')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxOrdersPerDay,
onChange: (e)=>setPlanForm({
...planForm,
maxOrdersPerDay: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_skills')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxSkills,
onChange: (e)=>setPlanForm({
...planForm,
maxSkills: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_profiles')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxProfiles,
onChange: (e)=>setPlanForm({
...planForm,
maxProfiles: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.max_portfolio')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.maxPortfolioItems,
onChange: (e)=>setPlanForm({
...planForm,
maxPortfolioItems: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.duration_days')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
placeholder: "∞",
value: planForm.durationDays,
onChange: (e)=>setPlanForm({
...planForm,
durationDays: 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__*/ _jsx("p", {
className: "text-xs font-semibold text-gray-500 uppercase tracking-wide pt-1",
children: t('admin.plans.form.section.boost')
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-2 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.plans.form.search_boost')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
value: planForm.searchBoost,
onChange: (e)=>setPlanForm({
...planForm,
searchBoost: Number(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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.offers_multiplier')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0",
step: "0.01",
value: planForm.offersMultiplier,
onChange: (e)=>setPlanForm({
...planForm,
offersMultiplier: 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 font-medium text-gray-600 mb-1",
children: t('admin.plans.form.features')
}),
/*#__PURE__*/ _jsx("textarea", {
rows: 3,
value: planForm.features,
onChange: (e)=>setPlanForm({
...planForm,
features: 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 resize-none"
})
]
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs font-semibold text-gray-500 uppercase tracking-wide pt-1",
children: t('admin.plans.form.section.contact')
}),
/*#__PURE__*/ _jsx("div", {
className: "grid grid-cols-2 gap-2",
children: [
[
'canContactFreePlan',
t('admin.plans.form.can_contact_free')
],
[
'canContactProPlan',
t('admin.plans.form.can_contact_pro')
],
[
'canContactAll',
t('admin.plans.form.can_contact_all')
],
[
'canShowContactInfo',
t('admin.plans.form.can_show_contact')
],
[
'canViewPhone',
t('admin.plans.form.can_view_phone')
]
].map(([key, label])=>/*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 cursor-pointer text-sm text-gray-700",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: planForm[key],
onChange: (e)=>setPlanForm({
...planForm,
[key]: e.target.checked
}),
className: "w-4 h-4 rounded text-blue-600"
}),
label
]
}, key))
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs font-semibold text-gray-500 uppercase tracking-wide pt-1",
children: t('admin.plans.form.section.features')
}),
/*#__PURE__*/ _jsx("div", {
className: "grid grid-cols-2 gap-2",
children: [
[
'notifyNewTasks',
t('admin.plans.form.notify')
],
[
'canUploadVideo',
t('admin.plans.form.upload_video')
],
[
'hasFavorites',
t('admin.plans.form.favorites')
],
[
'hasGoogleCalendar',
t('admin.plans.form.google_calendar')
],
[
'hasVerifiedBadge',
t('admin.plans.form.verified_badge')
],
[
'highlightedReviews',
t('admin.plans.form.highlighted_reviews')
],
[
'hasPersonalSite',
t('admin.plans.form.personal_site')
],
[
'hasCanHelpNowStatus',
t('admin.plans.form.can_help_now')
],
[
'hasNeedHelpStatus',
t('admin.plans.form.need_help')
],
[
'hasAutoResponse',
t('admin.plans.form.auto_response')
],
[
'hasAutoMatch',
t('admin.plans.form.auto_match')
],
[
'receiveInstantDispatchFree',
t('admin.plans.form.instant_dispatch_free')
],
[
'receiveInstantDispatchPro',
t('admin.plans.form.instant_dispatch_pro')
]
].map(([key, label])=>/*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 cursor-pointer text-sm text-gray-700",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: planForm[key],
onChange: (e)=>setPlanForm({
...planForm,
[key]: e.target.checked
}),
className: "w-4 h-4 rounded text-blue-600"
}),
label
]
}, key))
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-6 pt-1",
children: [
/*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 cursor-pointer text-sm text-gray-700",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: planForm.isDefault,
onChange: (e)=>setPlanForm({
...planForm,
isDefault: e.target.checked
}),
className: "w-4 h-4 rounded text-blue-600"
}),
t('admin.plans.form.default')
]
}),
/*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 cursor-pointer text-sm text-gray-700",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: planForm.isActive,
onChange: (e)=>setPlanForm({
...planForm,
isActive: e.target.checked
}),
className: "w-4 h-4 rounded text-blue-600"
}),
t('admin.plans.form.active')
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-2",
children: [
/*#__PURE__*/ _jsx("label", {
className: "text-xs text-gray-600",
children: t('admin.plans.form.order')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
value: planForm.order,
onChange: (e)=>setPlanForm({
...planForm,
order: Number(e.target.value)
}),
className: "w-16 border border-gray-300 rounded-lg px-2 py-1 text-sm focus:outline-none"
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-2 pt-1",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: savePlan,
disabled: planSaving || !planForm.name,
className: "bg-blue-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: planSaving ? '...' : t('common.save')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setPlanForm(null),
className: "px-4 py-2 rounded-lg text-sm font-medium text-gray-600 hover:bg-gray-100",
children: t('common.cancel')
})
]
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "bg-white rounded-xl border border-gray-200 overflow-hidden",
children: planRows.length === 0 ? /*#__PURE__*/ _jsx("div", {
className: "px-4 py-8 text-center text-gray-400 text-sm",
children: t('admin.plans.empty')
}) : /*#__PURE__*/ _jsx("div", {
className: "divide-y divide-gray-100",
children: planRows.sort((a, b)=>(a.order ?? 0) - (b.order ?? 0)).map((plan)=>/*#__PURE__*/ _jsxs("div", {
className: `flex items-start gap-4 px-4 py-4 ${!plan.isActive ? 'opacity-50' : ''}`,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 min-w-0",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-2 flex-wrap",
children: [
/*#__PURE__*/ _jsx("span", {
className: "font-semibold text-gray-900",
children: plan.name
}),
plan.isDefault && /*#__PURE__*/ _jsx("span", {
className: "bg-blue-100 text-blue-700 text-xs px-2 py-0.5 rounded-full font-medium",
children: t('admin.plans.badge.default')
}),
!plan.isActive && /*#__PURE__*/ _jsx("span", {
className: "bg-gray-100 text-gray-500 text-xs px-2 py-0.5 rounded-full",
children: t('admin.plans.badge.inactive')
})
]
}),
plan.description && /*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-500 mt-0.5",
children: plan.description
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex flex-wrap gap-3 mt-1 text-xs text-gray-500",
children: [
/*#__PURE__*/ _jsxs("span", {
className: "flex items-center gap-1.5 font-semibold text-gray-800",
children: [
plan.oldPrice && /*#__PURE__*/ _jsxs("span", {
className: "font-normal text-gray-400 line-through",
children: [
plan.oldPrice,
" ",
plan.currency
]
}),
/*#__PURE__*/ _jsxs("span", {
children: [
plan.price,
" ",
plan.currency
]
})
]
}),
plan.maxTasks != null && /*#__PURE__*/ _jsxs("span", {
children: [
t('admin.plans.tasks'),
": ",
plan.maxTasks
]
}),
plan.maxOffers != null && /*#__PURE__*/ _jsxs("span", {
children: [
t('admin.plans.offers'),
": ",
plan.maxOffers
]
}),
plan.maxCards != null && /*#__PURE__*/ _jsxs("span", {
children: [
t('admin.plans.cards'),
": ",
plan.maxCards
]
}),
plan.notifyNewTasks && /*#__PURE__*/ _jsxs("span", {
className: "text-green-700 flex items-center gap-1",
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: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
})
}),
t('admin.plans.notify_tasks')
]
})
]
}),
(plan.features ?? []).length > 0 && /*#__PURE__*/ _jsx("ul", {
className: "mt-1.5 space-y-0.5",
children: 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: /*#__PURE__*/ _jsx("svg", {
className: "w-3 h-3",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "20 6 9 17 4 12"
})
})
}),
" ",
f
]
}, i))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-1 shrink-0",
children: [
!plan.isDefault && /*#__PURE__*/ _jsx("button", {
onClick: ()=>api.updatePlan(plan.id, {
isDefault: true
}).then(()=>api.getAdminPlans().then(setPlanRows)).catch(()=>{}),
className: "text-xs px-2 py-1 rounded-lg bg-blue-50 text-blue-600 hover:bg-blue-100 font-medium",
title: t('admin.plans.make_default'),
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("polygon", {
points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
})
})
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>openEditPlan(plan),
className: "text-xs px-2 py-1 rounded-lg bg-gray-100 text-gray-600 hover:bg-gray-200 font-medium",
children: t('common.edit')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>deletePlan(plan.id, plan.name),
className: "text-xs px-2 py-1 rounded-lg bg-red-50 text-red-600 hover:bg-red-100 font-medium",
children: t('common.delete')
})
]
})
]
}, plan.id))
})
})
]
}),
tab === 'settings' && /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "flex gap-1 mb-6 bg-white rounded-xl border border-gray-200 p-1 w-fit",
children: [
'general',
'smtp',
'notifications',
'payment',
'referral',
'seo',
'socials'
].map((st)=>{
const labels = {
general: t('admin.settings.tab.general'),
smtp: t('admin.settings.tab.smtp'),
notifications: t('admin.settings.tab.notifications'),
payment: t('admin.settings.tab.payment'),
referral: t('admin.settings.tab.referral'),
seo: t('admin.settings.tab.seo'),
socials: t('admin.settings.tab.socials')
};
return /*#__PURE__*/ _jsx("button", {
onClick: ()=>setSettingsTab(st),
className: `px-4 py-2 rounded-lg text-sm font-medium transition ${settingsTab === st ? 'bg-blue-600 text-white shadow-sm' : 'text-gray-600 hover:bg-gray-100'}`,
children: labels[st]
}, st);
})
}),
settingsTab === 'general' && /*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-6 max-w-lg",
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800 mb-5",
children: t('admin.settings.general.title')
}),
/*#__PURE__*/ _jsxs("div", {
className: "space-y-4",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.general.site_name')
}),
/*#__PURE__*/ _jsx("input", {
value: generalForm.siteName,
onChange: (e)=>setGeneralForm((f)=>({
...f,
siteName: 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",
placeholder: "CanHelp"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.general.site_url')
}),
/*#__PURE__*/ _jsx("input", {
value: generalForm.siteUrl,
onChange: (e)=>setGeneralForm((f)=>({
...f,
siteUrl: 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",
placeholder: "https://canhelp.com"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.general.contact_email')
}),
/*#__PURE__*/ _jsx("input", {
type: "email",
value: generalForm.contactEmail,
onChange: (e)=>setGeneralForm((f)=>({
...f,
contactEmail: 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",
placeholder: "contact@canhelp.com"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.general.support_phone')
}),
/*#__PURE__*/ _jsx("input", {
value: generalForm.supportPhone,
onChange: (e)=>setGeneralForm((f)=>({
...f,
supportPhone: 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",
placeholder: "+30 21 000 0000"
})
]
}),
/*#__PURE__*/ _jsx("button", {
onClick: saveGeneralSettings,
disabled: generalSaving,
className: "w-full py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50 transition",
children: generalSaving ? t('admin.settings.saving') : generalSaved ? t('admin.settings.saved') : t('common.save')
})
]
})
]
}),
settingsTab === 'smtp' && /*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-6 max-w-lg",
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800 mb-1",
children: t('admin.settings.smtp.title')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-400 mb-5",
children: t('admin.settings.smtp.hint')
}),
/*#__PURE__*/ _jsxs("div", {
className: "space-y-4",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-3 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "col-span-2",
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.smtp.host')
}),
/*#__PURE__*/ _jsx("input", {
value: smtpForm.host,
onChange: (e)=>setSmtpForm((f)=>({
...f,
host: 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",
placeholder: "smtp.gmail.com"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.smtp.port')
}),
/*#__PURE__*/ _jsx("input", {
value: smtpForm.port,
onChange: (e)=>setSmtpForm((f)=>({
...f,
port: 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",
placeholder: "587"
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.smtp.encryption')
}),
/*#__PURE__*/ _jsxs("select", {
value: smtpForm.encryption,
onChange: (e)=>setSmtpForm((f)=>({
...f,
encryption: 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: "none",
children: t('admin.settings.smtp.enc.none')
}),
/*#__PURE__*/ _jsx("option", {
value: "tls",
children: "STARTTLS (587)"
}),
/*#__PURE__*/ _jsx("option", {
value: "ssl",
children: "SSL/TLS (465)"
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.smtp.username')
}),
/*#__PURE__*/ _jsx("input", {
value: smtpForm.username,
onChange: (e)=>setSmtpForm((f)=>({
...f,
username: 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",
placeholder: "user@gmail.com",
autoComplete: "off"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.smtp.password')
}),
/*#__PURE__*/ _jsx("input", {
type: "password",
value: smtpForm.password,
onChange: (e)=>setSmtpForm((f)=>({
...f,
password: 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",
autoComplete: "new-password",
placeholder: "••••••••••••"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-2 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.smtp.from_name')
}),
/*#__PURE__*/ _jsx("input", {
value: smtpForm.fromName,
onChange: (e)=>setSmtpForm((f)=>({
...f,
fromName: 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",
placeholder: "CanHelp"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.smtp.from_email')
}),
/*#__PURE__*/ _jsx("input", {
type: "email",
value: smtpForm.fromEmail,
onChange: (e)=>setSmtpForm((f)=>({
...f,
fromEmail: 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",
placeholder: "noreply@canhelp.com"
})
]
})
]
}),
/*#__PURE__*/ _jsx("button", {
onClick: saveSmtpSettings,
disabled: smtpSaving,
className: "w-full py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50 transition",
children: smtpSaving ? t('admin.settings.saving') : smtpSaved ? t('admin.settings.saved') : t('common.save')
}),
/*#__PURE__*/ _jsx("button", {
onClick: async ()=>{
setTestEmailSending(true);
setTestEmailResult(null);
try {
const res = await api.sendTestEmail();
setTestEmailResult(`✓ Отправлено на ${res.to}`);
} catch (e) {
setTestEmailResult(`✗ Ошибка: ${e.message}`);
} finally{
setTestEmailSending(false);
setTimeout(()=>setTestEmailResult(null), 5000);
}
},
disabled: testEmailSending,
className: "w-full py-2 bg-gray-100 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-200 disabled:opacity-50 transition",
children: testEmailSending ? t('admin.settings.smtp.sending') : /*#__PURE__*/ _jsxs("span", {
className: "flex items-center justify-center gap-2",
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: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
})
}),
t('admin.settings.smtp.test')
]
})
}),
testEmailResult && /*#__PURE__*/ _jsx("p", {
className: `text-sm text-center font-medium ${testEmailResult.startsWith('✓') ? 'text-green-600' : 'text-red-500'}`,
children: testEmailResult
})
]
})
]
}),
settingsTab === 'payment' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-6 max-w-lg",
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-5",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-3",
children: [
/*#__PURE__*/ _jsx("div", {
className: "w-10 h-10 rounded-lg bg-[#003087] flex items-center justify-center text-white text-xs font-bold shrink-0",
children: "PB"
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800",
children: "ePay — Piraeus Bank"
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400",
children: "Греческий платёжный шлюз"
})
]
})
]
}),
/*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 cursor-pointer",
children: [
/*#__PURE__*/ _jsx("span", {
className: "text-sm text-gray-500",
children: t('admin.settings.active')
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
onClick: ()=>setEPayForm((f)=>({
...f,
enabled: !f.enabled
})),
className: `relative w-10 h-6 rounded-full p-0 transition-colors cursor-pointer ${ePayForm.enabled ? 'bg-blue-600' : 'bg-gray-300'}`,
children: /*#__PURE__*/ _jsx("span", {
className: `absolute left-0 top-1 w-4 h-4 bg-white rounded-full shadow transition-transform ${ePayForm.enabled ? 'translate-x-5' : 'translate-x-1'}`
})
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "space-y-4",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.env.label')
}),
/*#__PURE__*/ _jsxs("select", {
value: ePayForm.environment,
onChange: (e)=>setEPayForm((f)=>({
...f,
environment: e.target.value
})),
className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm",
children: [
/*#__PURE__*/ _jsx("option", {
value: "test",
children: t('admin.settings.env.test')
}),
/*#__PURE__*/ _jsx("option", {
value: "production",
children: t('admin.settings.env.prod')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.merchant_id')
}),
/*#__PURE__*/ _jsx("input", {
value: ePayForm.merchantId,
onChange: (e)=>setEPayForm((f)=>({
...f,
merchantId: e.target.value
})),
placeholder: t('admin.settings.merchant_id'),
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: "grid grid-cols-2 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: "API User"
}),
/*#__PURE__*/ _jsx("input", {
value: ePayForm.apiUser,
onChange: (e)=>setEPayForm((f)=>({
...f,
apiUser: e.target.value
})),
autoComplete: "off",
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: "API Password"
}),
/*#__PURE__*/ _jsx("input", {
type: "password",
value: ePayForm.apiPassword,
onChange: (e)=>setEPayForm((f)=>({
...f,
apiPassword: e.target.value
})),
autoComplete: "new-password",
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: "Confirmation URL (webhook)"
}),
/*#__PURE__*/ _jsx("input", {
value: ePayForm.confirmationUrl,
onChange: (e)=>setEPayForm((f)=>({
...f,
confirmationUrl: e.target.value
})),
placeholder: "https://yoursite.com/api/payments/epay/confirm",
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: "Cancel URL"
}),
/*#__PURE__*/ _jsx("input", {
value: ePayForm.cancelUrl,
onChange: (e)=>setEPayForm((f)=>({
...f,
cancelUrl: e.target.value
})),
placeholder: "https://yoursite.com/payment/cancelled",
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 items-center gap-3 mt-5",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: saveEPaySettings,
disabled: ePaySaving,
className: "px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: ePaySaving ? t('admin.settings.saving') : t('common.save')
}),
ePaySaved && /*#__PURE__*/ _jsx("span", {
className: "text-sm text-green-600",
children: t('admin.settings.saved')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "p-3 bg-amber-50 border border-amber-200 rounded-xl text-xs text-amber-700 flex items-start gap-2",
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 shrink-0 mt-0.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("circle", {
cx: "12",
cy: "12",
r: "10"
}),
/*#__PURE__*/ _jsx("line", {
x1: "12",
y1: "8",
x2: "12",
y2: "12"
}),
/*#__PURE__*/ _jsx("line", {
x1: "12",
y1: "16",
x2: "12.01",
y2: "16"
})
]
}),
/*#__PURE__*/ _jsx("span", {
children: t('admin.settings.payment.hint')
})
]
})
]
}),
settingsTab === 'notifications' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-3 max-w-2xl",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-start gap-2 mb-4 p-3 bg-blue-50 border border-blue-100 rounded-xl text-sm text-blue-700",
children: [
/*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 shrink-0 mt-0.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("circle", {
cx: "12",
cy: "12",
r: "10"
}),
/*#__PURE__*/ _jsx("line", {
x1: "12",
y1: "8",
x2: "12",
y2: "12"
}),
/*#__PURE__*/ _jsx("line", {
x1: "12",
y1: "16",
x2: "12.01",
y2: "16"
})
]
}),
/*#__PURE__*/ _jsxs("p", {
children: [
t('admin.notif.vars_hint'),
' ',
TEMPLATE_HINT_VARS.map((name)=>{
const v = `{{${name}}}`;
return /*#__PURE__*/ _jsx("code", {
className: "mx-0.5 bg-blue-100 text-blue-800 px-1.5 py-0.5 rounded text-xs font-mono",
children: v
}, v);
})
]
})
]
}),
[
{
key: 'email_verification',
label: t('admin.notif.email_verification'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-blue-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
})
})
},
{
key: 'registration_success',
label: t('admin.notif.registration_success'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-green-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
})
})
},
{
key: 'password_reset',
label: t('admin.notif.password_reset'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-amber-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
})
})
},
{
key: 'new_offer',
label: t('admin.notif.new_offer'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-purple-500 shrink-0",
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.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"
})
})
},
{
key: 'new_task',
label: t('admin.notif.new_task'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-indigo-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
})
})
},
{
key: 'offer_accepted',
label: t('admin.notif.offer_accepted'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-green-600 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M5 13l4 4L19 7"
})
})
},
{
key: 'new_message',
label: t('admin.notif.new_message'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-pink-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
})
})
},
{
key: 'offer_declined',
label: t('admin.notif.offer_declined'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-red-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
})
})
},
{
key: 'offer_other_accepted',
label: t('admin.notif.offer_other_accepted'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-orange-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
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"
})
})
},
{
key: 'task_updated',
label: t('admin.notif.task_updated'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-blue-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
})
})
},
{
key: 'deadline_reminder',
label: t('admin.notif.deadline_reminder'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-yellow-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
})
})
},
{
key: 'task_archived',
label: t('admin.notif.task_archived'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-red-400 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8l1 12a2 2 0 002 2h8a2 2 0 002-2l1-12M10 12v6m4-6v6"
})
})
},
{
key: 'referral_reward',
label: t('admin.notif.referral_reward'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-emerald-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M12 8v13m0-13V6a2 2 0 112.83 2.83l-2.83 2.83zm0 0V5.5A2.5 2.5 0 119.27 8H12zm-7 4h14M5 12a2 2 0 110-4h3.586a1 1 0 01.707.293l2.414 2.414M19 12a2 2 0 110-4h-3.586a1 1 0 00-.707.293l-2.414 2.414"
})
})
},
// ── Plan / subscription emails ─────────────────────────────
{
key: 'plan_activated',
label: t('admin.email_template.plan_activated'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-blue-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
})
})
},
{
key: 'plan_upgraded',
label: t('admin.email_template.plan_upgraded'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-green-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M5 10l7-7m0 0l7 7m-7-7v18"
})
})
},
{
key: 'plan_downgrade_scheduled',
label: t('admin.email_template.plan_downgrade_scheduled'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-orange-400 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
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"
})
})
},
{
key: 'plan_downgrade_applied',
label: t('admin.email_template.plan_downgrade_applied'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-orange-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19 14l-7 7m0 0l-7-7m7 7V3"
})
})
},
{
key: 'plan_renewal_reminder',
label: t('admin.email_template.plan_renewal_reminder'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-yellow-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"
})
})
},
{
key: 'plan_insufficient_funds',
label: t('admin.email_template.plan_insufficient_funds'),
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-red-500 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
})
})
}
].map(({ key, label, icon })=>{
const localeKey = `${key}_${templateLocale}`;
const tmpl = notifTemplates[localeKey] ?? notifTemplates[key] ?? {
subject: '',
body: ''
};
const isEditing = editingTemplate === key;
const templateVars = TEMPLATE_VARS[key] ?? [];
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-5 py-4 cursor-pointer hover:bg-gray-50 select-none",
onClick: ()=>setEditingTemplate(isEditing ? null : key),
children: [
/*#__PURE__*/ _jsx("span", {
className: "text-xl shrink-0",
children: icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 min-w-0",
children: [
/*#__PURE__*/ _jsx("div", {
className: "font-medium text-gray-800 text-sm",
children: label
}),
tmpl.subject ? /*#__PURE__*/ _jsxs("div", {
className: "text-xs text-gray-400 mt-0.5 truncate",
children: [
t('admin.notif.tmpl.subject_label'),
": ",
tmpl.subject
]
}) : /*#__PURE__*/ _jsx("div", {
className: "text-xs text-gray-300 mt-0.5 italic",
children: t('admin.notif.tmpl.not_set')
})
]
}),
/*#__PURE__*/ _jsx("span", {
className: `text-gray-400 transition-transform ${isEditing ? 'rotate-90' : ''}`,
children: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "9 18 15 12 9 6"
})
})
})
]
}),
isEditing && /*#__PURE__*/ _jsxs("div", {
className: "px-5 pb-5 border-t border-gray-100 pt-4 space-y-3",
children: [
/*#__PURE__*/ _jsx("div", {
className: "flex gap-1 pb-2",
children: [
'el',
'en',
'ru'
].map((loc)=>/*#__PURE__*/ _jsx("button", {
type: "button",
onClick: ()=>setTemplateLocale(loc),
className: `px-3 py-1 text-xs font-medium rounded-md transition-colors ${templateLocale === loc ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`,
children: loc === 'el' ? 'Ελληνικά' : loc === 'en' ? 'English' : 'Русский'
}, loc))
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-xs font-medium text-gray-600 mb-1",
children: t('admin.notif.tmpl.subject_label')
}),
/*#__PURE__*/ _jsx("input", {
value: tmpl.subject,
onChange: (e)=>setNotifTemplates((prev)=>({
...prev,
[localeKey]: {
...prev[localeKey] ?? {
subject: '',
body: ''
},
subject: 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 font-medium text-gray-600 mb-1",
children: t('admin.notif.tmpl.body_label')
}),
/*#__PURE__*/ _jsx("textarea", {
rows: 7,
value: tmpl.body,
onChange: (e)=>setNotifTemplates((prev)=>({
...prev,
[localeKey]: {
...prev[localeKey] ?? {
subject: '',
body: ''
},
body: 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 font-mono resize-y",
placeholder: "
Уважаемый {{userName}},
..."
})
]
}),
templateVars.length > 0 && /*#__PURE__*/ _jsxs("div", {
className: "rounded-lg border border-amber-200 bg-amber-50 px-3 py-2",
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs font-medium text-amber-800 mb-1",
children: t('admin.notif.vars_hint')
}),
/*#__PURE__*/ _jsx("div", {
className: "flex flex-wrap gap-1.5",
children: templateVars.map((name)=>{
const variable = `{{${name}}}`;
return /*#__PURE__*/ _jsx("code", {
className: "bg-amber-100 text-amber-900 px-1.5 py-0.5 rounded text-xs font-mono",
children: variable
}, variable);
})
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-2 flex-wrap",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: ()=>saveTemplate(key),
disabled: templateSaving || templateTranslating,
className: "px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: templateSaving ? t('admin.notif.tmpl.saving') : t('admin.notif.tmpl.save')
}),
/*#__PURE__*/ _jsxs("button", {
onClick: ()=>autoTranslateTemplate(key),
disabled: templateSaving || templateTranslating,
className: "px-4 py-2 bg-purple-600 text-white rounded-lg text-sm font-medium hover:bg-purple-700 disabled:opacity-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: "M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129"
})
}),
templateTranslating ? t('admin.notif.tmpl.translating') : t('admin.notif.tmpl.translate')
]
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditingTemplate(null),
className: "px-4 py-2 bg-gray-100 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-200",
children: t('admin.notif.tmpl.close')
})
]
})
]
})
]
}, key);
})
]
}),
settingsTab === 'referral' && /*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-6 max-w-lg space-y-5",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800",
children: t('admin.settings.referral.title')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-400 mt-1",
children: t('admin.settings.referral.hint')
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-sm font-medium text-gray-700",
children: t('admin.settings.referral.enabled_label')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400",
children: t('admin.settings.referral.enabled_hint')
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
onClick: ()=>setReferralForm((f)=>({
...f,
enabled: !f.enabled
})),
className: `relative w-10 h-6 rounded-full p-0 transition-colors cursor-pointer ${referralForm.enabled ? 'bg-blue-600' : 'bg-gray-300'}`,
children: /*#__PURE__*/ _jsx("span", {
className: `absolute left-0 top-1 w-4 h-4 bg-white rounded-full shadow transition-transform ${referralForm.enabled ? 'translate-x-5' : 'translate-x-1'}`
})
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "border border-gray-100 rounded-lg p-4 space-y-4",
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-xs font-semibold text-gray-500 uppercase tracking-wide",
children: t('admin.settings.referral.customer_section')
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.referral.plan_label')
}),
/*#__PURE__*/ _jsxs("select", {
value: referralForm.customerPlanId,
onChange: (e)=>setReferralForm((f)=>({
...f,
customerPlanId: 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: "",
children: t('admin.settings.referral.no_plan')
}),
planRows.filter((p)=>p.role === 'customer').map((p)=>/*#__PURE__*/ _jsx("option", {
value: p.id,
children: p.name
}, p.id))
]
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-1",
children: t('admin.settings.referral.plan_hint')
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.referral.days_label')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "1",
max: "365",
value: referralForm.customerDays,
onChange: (e)=>setReferralForm((f)=>({
...f,
customerDays: 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__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-1",
children: t('admin.settings.referral.days_hint')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "border border-gray-100 rounded-lg p-4 space-y-4",
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-xs font-semibold text-gray-500 uppercase tracking-wide",
children: t('admin.settings.referral.specialist_section')
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.referral.plan_label')
}),
/*#__PURE__*/ _jsxs("select", {
value: referralForm.specialistPlanId,
onChange: (e)=>setReferralForm((f)=>({
...f,
specialistPlanId: 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: "",
children: t('admin.settings.referral.no_plan')
}),
planRows.filter((p)=>p.role === 'specialist').map((p)=>/*#__PURE__*/ _jsx("option", {
value: p.id,
children: p.name
}, p.id))
]
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-1",
children: t('admin.settings.referral.plan_hint')
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.referral.days_label')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "1",
max: "365",
value: referralForm.specialistDays,
onChange: (e)=>setReferralForm((f)=>({
...f,
specialistDays: 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__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-1",
children: t('admin.settings.referral.days_hint')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-3",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: saveReferralSettings,
disabled: referralSaving,
className: "px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: referralSaving ? t('admin.settings.saving') : t('common.save')
}),
referralSaved && /*#__PURE__*/ _jsx("span", {
className: "text-sm text-green-600",
children: t('admin.settings.saved')
})
]
})
]
}),
settingsTab === 'socials' && /*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-6 max-w-lg space-y-5",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800 mb-1",
children: t('admin.settings.socials.title')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400",
children: t('admin.settings.socials.hint')
})
]
}),
[
{
key: 'telegram',
label: 'Telegram',
placeholder: 'https://t.me/yourname',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"
})
})
},
{
key: 'instagram',
label: 'Instagram',
placeholder: 'https://instagram.com/yourname',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z"
})
})
},
{
key: 'facebook',
label: 'Facebook',
placeholder: 'https://facebook.com/yourpage',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"
})
})
},
{
key: 'twitter',
label: 'X (Twitter)',
placeholder: 'https://x.com/yourname',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
})
})
},
{
key: 'youtube',
label: 'YouTube',
placeholder: 'https://youtube.com/@yourchannel',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
})
})
},
{
key: 'tiktok',
label: 'TikTok',
placeholder: 'https://tiktok.com/@yourname',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-2.88 2.5 2.89 2.89 0 0 1-2.89-2.89 2.89 2.89 0 0 1 2.89-2.89c.28 0 .54.04.79.1V9.01a6.27 6.27 0 0 0-.79-.05 6.34 6.34 0 0 0-6.34 6.34 6.34 6.34 0 0 0 6.34 6.34 6.34 6.34 0 0 0 6.33-6.34V8.73a8.16 8.16 0 0 0 4.77 1.52V6.79a4.85 4.85 0 0 1-1-.1z"
})
})
},
{
key: 'whatsapp',
label: 'WhatsApp',
placeholder: 'https://wa.me/30xxxxxxxxxx',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413z"
})
})
},
{
key: 'viber',
label: 'Viber',
placeholder: 'viber://chat?number=30xxxxxxxxxx',
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
viewBox: "0 0 24 24",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
d: "M11.398.002C8.473.028 4.414.625 2.138 4.15.2 7.044-.054 10.74.009 13.092c.064 2.352.277 4.799 1.97 6.758 1.32 1.527 3.276 2.39 5.262 2.674l.006 1.92c0 .307.368.47.592.257l2.245-2.143c.666.037 1.338.046 2.001.023 3.05-.107 6.238-.671 8.39-2.988 2.27-2.45 2.476-5.915 2.515-9.093.038-3.178-.15-6.648-2.467-9.052C18.337.606 14.323-.024 11.398.002zm.11 1.55c2.73-.023 6.267.538 8.3 2.688 1.878 2.004 2.034 5.155 2.001 8.172-.033 3.017-.245 5.967-2.069 7.944-1.792 1.943-4.607 2.44-7.265 2.533a18.35 18.35 0 0 1-2.198-.051l-.301-.028L7.8 24.51l-.004-2.463-.359-.064c-1.875-.333-3.693-1.152-4.832-2.47-1.377-1.597-1.574-3.702-1.632-5.915-.058-2.213.173-5.593 1.85-8.145C4.519 2.967 8.03 1.576 11.508 1.552zm-.082 2.19a8.79 8.79 0 0 0-2.65.399c-1.567.494-2.953 1.497-3.9 2.786C3.67 8.347 3.19 10.01 3.16 11.704c-.03 1.695.392 3.435 1.465 4.754.767.94 1.833 1.603 2.978 1.95l.004 1.232 1.197-1.143c.545.094 1.102.139 1.655.134 1.614-.015 3.27-.444 4.584-1.46 1.314-1.016 2.14-2.578 2.355-4.217.216-1.64-.017-3.369-.85-4.773-.832-1.403-2.23-2.412-3.773-2.74a8.777 8.777 0 0 0-1.459-.12zm.076 1.56c.39.003.784.049 1.165.14 1.215.27 2.319 1.066 2.975 2.17.657 1.103.843 2.518.66 3.857-.183 1.339-.826 2.596-1.87 3.408-1.044.813-2.41 1.172-3.76 1.185a10.75 10.75 0 0 1-1.675-.131l-.395-.064-1.017.97-.003-1.02-.384-.117c-1.027-.314-1.95-.925-2.574-1.693-.893-1.095-1.225-2.58-1.198-4.017.028-1.437.427-2.866 1.236-3.98.809-1.113 1.959-1.905 3.236-2.296a7.298 7.298 0 0 1 1.609-.412z"
})
})
}
].map(({ key, label, placeholder, icon })=>/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("label", {
className: "block text-sm font-medium text-gray-700 mb-1 flex items-center gap-2",
children: [
/*#__PURE__*/ _jsx("span", {
className: `${socialForm[key] ? 'text-blue-600' : 'text-gray-300'}`,
children: icon
}),
label,
!socialForm[key] && /*#__PURE__*/ _jsx("span", {
className: "text-xs font-normal text-gray-400 ml-auto",
children: "не заполнено"
})
]
}),
/*#__PURE__*/ _jsx("input", {
type: "url",
value: socialForm[key],
onChange: (e)=>setSocialForm((f)=>({
...f,
[key]: e.target.value
})),
placeholder: placeholder,
className: `w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 ${socialForm[key] ? 'border-blue-300 bg-blue-50/30' : 'border-gray-300'}`
})
]
}, key)),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-3 pt-2",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: saveSocialSettings,
disabled: socialSaving,
className: "px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: socialSaving ? t('admin.settings.saving') : t('common.save')
}),
socialSaved && /*#__PURE__*/ _jsx("span", {
className: "text-sm text-green-600",
children: t('admin.settings.saved')
})
]
})
]
}),
settingsTab === 'seo' && /*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-6 max-w-lg space-y-6",
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800",
children: t('admin.settings.seo.title')
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-sm font-medium text-gray-700",
children: t('admin.settings.seo.maintenance_label')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-0.5",
children: t('admin.settings.seo.maintenance_hint')
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
onClick: ()=>setSeoForm((f)=>({
...f,
maintenanceMode: !f.maintenanceMode
})),
className: `relative w-10 h-6 rounded-full p-0 transition-colors cursor-pointer flex-shrink-0 ${seoForm.maintenanceMode ? 'bg-red-500' : 'bg-gray-300'}`,
children: /*#__PURE__*/ _jsx("span", {
className: `absolute left-0 top-1 w-4 h-4 bg-white rounded-full shadow transition-transform ${seoForm.maintenanceMode ? 'translate-x-5' : 'translate-x-1'}`
})
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-sm font-medium text-gray-700",
children: t('admin.settings.seo.indexing_label')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-0.5",
children: t('admin.settings.seo.indexing_hint')
})
]
}),
/*#__PURE__*/ _jsx("button", {
type: "button",
onClick: ()=>setSeoForm((f)=>({
...f,
indexingEnabled: !f.indexingEnabled
})),
className: `relative w-10 h-6 rounded-full p-0 transition-colors cursor-pointer flex-shrink-0 ${seoForm.indexingEnabled ? 'bg-blue-600' : 'bg-gray-300'}`,
children: /*#__PURE__*/ _jsx("span", {
className: `absolute left-0 top-1 w-4 h-4 bg-white rounded-full shadow transition-transform ${seoForm.indexingEnabled ? 'translate-x-5' : 'translate-x-1'}`
})
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.seo.site_title_label')
}),
/*#__PURE__*/ _jsx("input", {
value: seoForm.siteTitle,
onChange: (e)=>setSeoForm((f)=>({
...f,
siteTitle: 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",
placeholder: "CanHelp — Βρες ειδικό για κάθε δουλειά"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.seo.site_description_label')
}),
/*#__PURE__*/ _jsx("textarea", {
rows: 3,
value: seoForm.siteDescription,
onChange: (e)=>setSeoForm((f)=>({
...f,
siteDescription: 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 resize-none",
placeholder: "Η ελληνική πλατφόρμα για online ανάθεση εργασιών..."
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.settings.seo.head_scripts_label')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 mb-2",
children: t('admin.settings.seo.head_scripts_hint')
}),
/*#__PURE__*/ _jsx("textarea", {
rows: 6,
value: seoForm.headScripts,
onChange: (e)=>setSeoForm((f)=>({
...f,
headScripts: e.target.value
})),
className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-blue-400 resize-y",
placeholder: '\n',
spellCheck: false
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-3",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: saveSeoSettings,
disabled: seoSaving,
className: "px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",
children: seoSaving ? t('admin.settings.saving') : t('common.save')
}),
seoSaved && /*#__PURE__*/ _jsx("span", {
className: "text-sm text-green-600",
children: t('admin.settings.saved')
})
]
})
]
})
]
}),
tab === 'backup' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-6",
children: [
/*#__PURE__*/ _jsxs("h2", {
className: "text-lg font-semibold text-gray-800 flex items-center gap-2",
children: [
/*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-blue-600",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
})
}),
t('admin.backup.title', 'Backup')
]
}),
backupMsg && /*#__PURE__*/ _jsxs("div", {
className: `${backupMsgError ? 'bg-red-50 border-red-200 text-red-700' : 'bg-green-50 border-green-200 text-green-700'} border rounded-lg px-4 py-2 text-sm flex items-center justify-between`,
children: [
/*#__PURE__*/ _jsx("span", {
children: backupMsg
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setBackupMsg(null),
className: `${backupMsgError ? 'text-red-500 hover:text-red-700' : 'text-green-500 hover:text-green-700'} ml-4`,
children: "\xd7"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-5 flex items-center justify-between",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "font-medium text-gray-800 text-sm",
children: t('admin.backup.autoBackup', 'Auto Backup')
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-500 mt-0.5",
children: t('admin.backup.autoBackupDesc', 'Create a backup every day automatically')
})
]
}),
/*#__PURE__*/ _jsx("button", {
disabled: backupAutoSaving,
onClick: async ()=>{
setBackupAutoSaving(true);
try {
await request('/admin/backup/settings', {
method: 'PUT',
body: JSON.stringify({
autoEnabled: !backupAutoEnabled
})
});
setBackupAutoEnabled((v)=>!v);
} catch {}
setBackupAutoSaving(false);
},
className: `relative w-11 h-6 rounded-full transition-colors ${backupAutoEnabled ? 'bg-blue-600' : 'bg-gray-300'} ${backupAutoSaving ? 'opacity-50' : ''}`,
children: /*#__PURE__*/ _jsx("span", {
className: `absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-white shadow transition-transform ${backupAutoEnabled ? 'translate-x-5' : 'translate-x-0'}`
})
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-5",
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800 text-sm mb-4",
children: t('admin.backup.title', 'Database Backup')
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex flex-wrap gap-3",
children: [
/*#__PURE__*/ _jsxs("button", {
disabled: backupExporting,
onClick: async ()=>{
setBackupExporting(true);
try {
const BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';
const res = await fetch(`${BASE}/api/admin/backup/export`, {
credentials: 'include'
});
if (!res.ok) throw new Error('Export failed');
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `backup_${new Date().toISOString().slice(0, 10)}.sql.gz`;
a.click();
URL.revokeObjectURL(url);
setBackupSuccess(t('admin.backup.exportSuccess', 'Export successful'));
} catch (e) {
setBackupError(e.message || 'Error');
}
setBackupExporting(false);
},
className: "bg-blue-600 hover:bg-blue-700 text-white text-sm px-4 py-2 rounded-lg font-medium disabled:opacity-50 flex items-center gap-2",
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: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
})
}),
backupExporting ? t('admin.backup.exporting', 'Exporting...') : t('admin.backup.exportAll', 'Export Full DB')
]
}),
/*#__PURE__*/ _jsxs("label", {
className: `bg-gray-100 hover:bg-gray-200 text-gray-700 text-sm px-4 py-2 rounded-lg font-medium cursor-pointer flex items-center gap-2 ${backupImporting === 'full' ? 'opacity-50 pointer-events-none' : ''}`,
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: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l4-4m0 0l4 4m-4-4v12"
})
}),
backupImporting === 'full' ? t('admin.backup.importing', 'Importing...') : t('admin.backup.importAll', 'Import Full DB'),
/*#__PURE__*/ _jsx("input", {
type: "file",
accept: ".sql.gz,.gz",
className: "hidden",
onChange: async (e)=>{
const file = e.target.files?.[0];
if (!file) return;
if (!window.confirm(t('admin.backup.restoreConfirm', 'Restore from this backup?'))) return;
setBackupImporting('full');
try {
const fd = new FormData();
fd.append('file', file);
const BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';
const res = await fetch(`${BASE}/api/admin/backup/import`, {
method: 'POST',
credentials: 'include',
body: fd
});
if (!res.ok) throw new Error('Import failed');
setBackupSuccess(t('admin.backup.importSuccess', 'Import successful'));
} catch (err) {
setBackupError(err.message || 'Error');
}
setBackupImporting(null);
e.target.value = '';
}
})
]
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-5",
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800 text-sm mb-4",
children: t('admin.backup.storedBackups', 'Stored Backups')
}),
backupStoredFiles.length === 0 ? /*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-400",
children: t('admin.backup.noStoredBackups', 'No stored backups')
}) : /*#__PURE__*/ _jsx("div", {
className: "space-y-2",
children: backupStoredFiles.map((f)=>/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between py-2 px-3 bg-gray-50 rounded-lg border border-gray-100",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("p", {
className: "text-sm font-medium text-gray-800",
children: f.name === 'backup_today' ? t('admin.backup.today', 'Today') : t('admin.backup.yesterday', 'Yesterday')
}),
/*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-400",
children: [
t('admin.backup.size', 'Size'),
": ",
(f.size / 1024).toFixed(1),
" KB \xb7 ",
t('admin.backup.date', 'Date'),
": ",
new Date(f.date).toLocaleString()
]
})
]
}),
/*#__PURE__*/ _jsx("button", {
disabled: backupRestoring === f.name,
onClick: async ()=>{
if (!window.confirm(t('admin.backup.restoreConfirm', 'Restore from this backup?'))) return;
setBackupRestoring(f.name);
try {
await request('/admin/backup/restore', {
method: 'POST',
body: JSON.stringify({
name: f.name
})
});
setBackupSuccess(t('admin.backup.restoreSuccess', 'Restore successful'));
} catch (err) {
setBackupError(err.message || 'Error');
}
setBackupRestoring(null);
},
className: "text-sm text-blue-600 hover:text-blue-800 font-medium disabled:opacity-50",
children: backupRestoring === f.name ? t('admin.backup.restoring', 'Restoring...') : t('admin.backup.restore', 'Restore')
})
]
}, f.name))
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 p-5",
children: [
/*#__PURE__*/ _jsx("h3", {
className: "font-semibold text-gray-800 text-sm mb-4",
children: t('admin.backup.tables', 'Tables')
}),
backupTablesLoading ? /*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-2 text-sm text-gray-400",
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('common.loading', 'Loading...')
]
}) : backupTables.length === 0 ? /*#__PURE__*/ _jsx("p", {
className: "text-sm text-gray-400",
children: t('admin.noData', 'No data')
}) : /*#__PURE__*/ _jsx("div", {
className: "overflow-x-auto",
children: /*#__PURE__*/ _jsx("table", {
className: "w-full text-sm",
children: /*#__PURE__*/ _jsx("tbody", {
className: "divide-y divide-gray-100",
children: backupTables.map((tbl)=>/*#__PURE__*/ _jsxs("tr", {
className: "hover:bg-gray-50",
children: [
/*#__PURE__*/ _jsx("td", {
className: "py-2 pr-4 font-mono text-gray-700",
children: tbl
}),
/*#__PURE__*/ _jsx("td", {
className: "py-2 text-right",
children: /*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-end gap-2",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: async ()=>{
try {
const BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';
const res = await fetch(`${BASE}/api/admin/backup/export/${tbl}`, {
credentials: 'include'
});
if (!res.ok) throw new Error('Export failed');
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${tbl}_${new Date().toISOString().slice(0, 10)}.sql.gz`;
a.click();
URL.revokeObjectURL(url);
} catch (err) {
setBackupError(err.message || 'Error');
}
},
className: "text-blue-600 hover:text-blue-800 font-medium text-xs px-2 py-1 rounded border border-blue-200 hover:bg-blue-50",
children: t('admin.backup.exportTable', 'Export')
}),
/*#__PURE__*/ _jsxs("label", {
className: "text-gray-600 hover:text-gray-800 font-medium text-xs px-2 py-1 rounded border border-gray-200 hover:bg-gray-100 cursor-pointer",
children: [
backupImporting === tbl ? t('admin.backup.importing', 'Importing...') : t('admin.backup.importTable', 'Import'),
/*#__PURE__*/ _jsx("input", {
type: "file",
accept: ".sql.gz,.gz",
className: "hidden",
onChange: async (e)=>{
const file = e.target.files?.[0];
if (!file) return;
if (!window.confirm(t('admin.backup.restoreConfirm', 'Restore from this backup?'))) return;
setBackupImporting(tbl);
try {
const fd = new FormData();
fd.append('file', file);
const BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';
const res = await fetch(`${BASE}/api/admin/backup/import/${tbl}`, {
method: 'POST',
credentials: 'include',
body: fd
});
if (!res.ok) {
const errData = await res.json().catch(()=>({
error: 'Import failed'
}));
throw new Error(errData.error || 'Import failed');
}
setBackupSuccess(t('admin.backup.importSuccess', 'Import successful'));
} catch (err) {
setBackupError(err.message || 'Error');
}
setBackupImporting(null);
e.target.value = '';
}
})
]
})
]
})
})
]
}, tbl))
})
})
})
]
})
]
}),
editUser && /*#__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 w-full max-w-4xl max-h-[90vh] flex flex-col",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between px-6 py-4 border-b border-gray-100 flex-shrink-0",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h2", {
className: "text-base font-semibold text-gray-900",
children: t('admin.user_edit.title')
}),
/*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-400 mt-0.5",
children: [
editUser.email,
" \xb7 ID: ",
editUser.id
]
})
]
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditUser(null),
className: "text-gray-400 hover:text-gray-600 text-2xl leading-none",
children: "\xd7"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex flex-1 min-h-0",
children: [
/*#__PURE__*/ _jsx("nav", {
className: "w-44 flex-shrink-0 border-r border-gray-100 py-3 space-y-0.5 px-2",
children: [
{
id: 'profile',
label: t('admin.user_edit.tab.profile')
},
{
id: 'account',
label: t('admin.user_edit.tab.account')
},
{
id: 'balance',
label: t('admin.user_edit.tab.balance')
},
{
id: 'settings',
label: t('admin.user_edit.tab.settings')
},
{
id: 'site',
label: t('admin.user_edit.tab.site')
},
{
id: 'specialist',
label: t('admin.user_edit.tab.specialist')
}
].map((item)=>/*#__PURE__*/ _jsx("button", {
onClick: ()=>{
setEditUserTab(item.id);
if (item.id === 'specialist' && editUser) {
setEditUserCardsLoading(true);
const loadCards = api.getAdminUserSpecialistCards(editUser.id).then(setEditUserCards).catch(()=>{});
const loadCats = catRows.length === 0 ? api.getAdminCategories().then(setCatRows).catch(()=>{}) : Promise.resolve();
const loadLocs = locRows.length === 0 ? api.getAdminLocations().then(setLocRows).catch(()=>{}) : Promise.resolve();
Promise.all([
loadCards,
loadCats,
loadLocs
]).finally(()=>setEditUserCardsLoading(false));
}
},
className: `w-full text-left px-3 py-2.5 text-sm rounded-lg transition-colors ${editUserTab === item.id ? 'bg-blue-50 text-blue-700 font-medium' : 'text-gray-600 hover:bg-gray-50'}`,
children: item.label
}, item.id))
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 overflow-y-auto p-6",
children: [
editUserTab === 'profile' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-4",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "p-3 bg-gray-50 rounded-lg text-xs text-gray-500 space-y-0.5",
children: [
/*#__PURE__*/ _jsxs("p", {
children: [
/*#__PURE__*/ _jsxs("span", {
className: "font-medium",
children: [
t('admin.user_edit.registered'),
":"
]
}),
" ",
new Date(editUser.createdAt).toLocaleDateString(dateLocale)
]
}),
editUser.lastSeenAt && /*#__PURE__*/ _jsxs("p", {
children: [
/*#__PURE__*/ _jsxs("span", {
className: "font-medium",
children: [
t('admin.user_edit.last_seen'),
":"
]
}),
" ",
new Date(editUser.lastSeenAt).toLocaleDateString(dateLocale)
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-2 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.first_name')
}),
/*#__PURE__*/ _jsx("input", {
value: editUser.firstName ?? '',
onChange: (e)=>setEditUser((u)=>({
...u,
firstName: 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-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.last_name')
}),
/*#__PURE__*/ _jsx("input", {
value: editUser.lastName ?? '',
onChange: (e)=>setEditUser((u)=>({
...u,
lastName: 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-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.phone')
}),
/*#__PURE__*/ _jsx("input", {
value: editUser.phone ?? '',
onChange: (e)=>setEditUser((u)=>({
...u,
phone: 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-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.bio')
}),
/*#__PURE__*/ _jsx("textarea", {
value: editUser.bio ?? '',
onChange: (e)=>setEditUser((u)=>({
...u,
bio: e.target.value
})),
rows: 5,
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"
})
]
})
]
}),
editUserTab === 'account' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-4",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.email')
}),
/*#__PURE__*/ _jsx("div", {
className: "w-full border border-gray-200 bg-gray-50 rounded-lg px-3 py-2 text-sm text-gray-600 select-all",
children: editUser.email
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between rounded-lg border px-3 py-2 bg-gray-50",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-2",
children: [
editUser.emailVerified ? /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4 text-green-500 shrink-0",
viewBox: "0 0 20 20",
fill: "currentColor",
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"
})
}) : /*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4 text-red-400 shrink-0",
viewBox: "0 0 20 20",
fill: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
fillRule: "evenodd",
d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L10 8.586 7.707 6.293a1 1 0 00-1.414 1.414L8.586 10l-2.293 2.293a1 1 0 101.414 1.414L10 11.414l2.293 2.293a1 1 0 001.414-1.414L11.414 10l2.293-2.293z",
clipRule: "evenodd"
})
}),
/*#__PURE__*/ _jsx("span", {
className: `text-sm font-medium ${editUser.emailVerified ? 'text-green-700' : 'text-red-600'}`,
children: editUser.emailVerified ? t('admin.user_edit.email_verified') : t('admin.user_edit.email_not_verified')
})
]
}),
!editUser.emailVerified && /*#__PURE__*/ _jsx("button", {
onClick: verifyEmail,
disabled: verifyingEmail,
className: "text-xs px-3 py-1 rounded-md bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 transition-colors",
children: verifyingEmail ? '...' : t('admin.user_edit.verify_email_btn')
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid grid-cols-2 gap-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.role')
}),
/*#__PURE__*/ _jsxs("select", {
value: editUser.role,
onChange: (e)=>setEditUser((u)=>({
...u,
role: e.target.value
})),
className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm",
children: [
/*#__PURE__*/ _jsx("option", {
value: "customer",
children: t('admin.user_edit.role.customer')
}),
/*#__PURE__*/ _jsx("option", {
value: "specialist",
children: t('admin.user_edit.role.specialist')
}),
/*#__PURE__*/ _jsx("option", {
value: "admin",
children: t('admin.user_edit.role.admin')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.plan')
}),
/*#__PURE__*/ _jsxs("select", {
value: editUser.planId ?? '',
onChange: (e)=>setEditUser((u)=>({
...u,
planId: e.target.value || null
})),
className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm",
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: t('admin.user_edit.no_plan')
}),
planRows.map((p)=>/*#__PURE__*/ _jsx("option", {
value: p.id,
children: p.name
}, p.id))
]
})
]
})
]
}),
editUser.planExpiresAt && /*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-500",
children: [
t('admin.user_edit.plan_expires'),
": ",
new Date(editUser.planExpiresAt).toLocaleDateString(dateLocale)
]
}),
/*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-2 cursor-pointer",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: editUser.isActive !== false,
onChange: (e)=>setEditUser((u)=>({
...u,
isActive: e.target.checked
})),
className: "w-4 h-4 rounded border-gray-300 text-blue-600"
}),
/*#__PURE__*/ _jsx("span", {
className: "text-sm text-gray-700",
children: t('admin.user_edit.active')
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.interface_lang')
}),
/*#__PURE__*/ _jsxs("select", {
value: editUser.locale ?? 'el',
onChange: (e)=>setEditUser((u)=>({
...u,
locale: e.target.value
})),
className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm",
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-2",
children: t('admin.user_edit.comm_languages')
}),
/*#__PURE__*/ _jsx("div", {
className: "flex gap-5",
children: [
'el',
'en',
'ru'
].map((lang)=>/*#__PURE__*/ _jsxs("label", {
className: "flex items-center gap-1.5 cursor-pointer",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: (editUser.languages ?? []).includes(lang),
onChange: (e)=>{
const langs = editUser.languages ?? [];
setEditUser((u)=>({
...u,
languages: e.target.checked ? [
...langs.filter((l)=>l !== lang),
lang
] : langs.filter((l)=>l !== lang)
}));
},
className: "w-4 h-4 rounded border-gray-300 text-blue-600"
}),
/*#__PURE__*/ _jsx("span", {
className: "text-sm text-gray-700",
children: lang === 'el' ? 'Ελληνικά' : lang === 'en' ? 'English' : 'Русский'
})
]
}, lang))
})
]
})
]
}),
editUserTab === 'balance' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-6",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between p-5 bg-gray-50 rounded-xl border border-gray-200",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-gray-500 mb-1",
children: t('admin.user_edit.balance')
}),
/*#__PURE__*/ _jsxs("div", {
className: "text-2xl font-bold text-gray-900",
children: [
Number(editUser.balance ?? 0).toFixed(2),
" EUR"
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-2",
children: [
/*#__PURE__*/ _jsxs("button", {
onClick: ()=>setBalanceModal('topup'),
className: "flex items-center gap-1.5 px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg text-sm font-medium",
children: [
/*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
strokeWidth: 2,
d: "M12 4v16m8-8H4"
})
}),
t('admin.balance.topup.btn')
]
}),
/*#__PURE__*/ _jsxs("button", {
onClick: ()=>setBalanceModal('withdraw'),
className: "flex items-center gap-1.5 px-4 py-2 bg-rose-600 hover:bg-rose-700 text-white rounded-lg text-sm font-medium",
children: [
/*#__PURE__*/ _jsx("svg", {
className: "w-4 h-4",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
strokeWidth: 2,
d: "M20 12H4"
})
}),
t('admin.balance.withdraw.btn')
]
})
]
})
]
}),
/*#__PURE__*/ _jsx("p", {
className: "text-xs text-center text-gray-400",
children: t('admin.balance.modal_hint')
})
]
}),
editUserTab === 'settings' && /*#__PURE__*/ _jsx("div", {
className: "space-y-4",
children: /*#__PURE__*/ _jsxs("div", {
className: "space-y-3 pt-1 divide-y divide-gray-100",
children: [
/*#__PURE__*/ _jsxs("label", {
className: "flex items-center justify-between cursor-pointer py-2",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-sm font-medium text-gray-700",
children: t('admin.user_edit.show_contact_info')
}),
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-gray-400",
children: t('admin.user_edit.show_contact_info.hint')
})
]
}),
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: editUser.showContactInfo ?? false,
onChange: (e)=>setEditUser((u)=>({
...u,
showContactInfo: e.target.checked
})),
className: "w-4 h-4 rounded border-gray-300 text-blue-600"
})
]
}),
/*#__PURE__*/ _jsxs("label", {
className: "flex items-center justify-between cursor-pointer py-2",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-sm font-medium text-gray-700",
children: t('admin.user_edit.notify_new_tasks')
}),
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-gray-400",
children: t('admin.user_edit.notify_new_tasks.hint')
})
]
}),
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: editUser.notifyNewTasks ?? false,
onChange: (e)=>setEditUser((u)=>({
...u,
notifyNewTasks: e.target.checked
})),
className: "w-4 h-4 rounded border-gray-300 text-blue-600"
})
]
}),
/*#__PURE__*/ _jsxs("label", {
className: "flex items-center justify-between cursor-pointer py-2",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-sm font-medium text-gray-700",
children: t('admin.user_edit.notif_messages')
}),
/*#__PURE__*/ _jsx("div", {
className: "text-xs text-gray-400",
children: t('admin.user_edit.notif_messages.hint')
})
]
}),
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: editUser.notifMessages ?? true,
onChange: (e)=>setEditUser((u)=>({
...u,
notifMessages: e.target.checked
})),
className: "w-4 h-4 rounded border-gray-300 text-blue-600"
})
]
})
]
})
}),
editUserTab === 'site' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-4",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1",
children: t('admin.user_edit.personal_site_slug')
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-2",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex flex-1 items-center border border-gray-300 rounded-lg overflow-hidden focus-within:ring-2 focus-within:ring-blue-400",
children: [
/*#__PURE__*/ _jsx("span", {
className: "px-3 py-2 text-sm text-gray-400 bg-gray-50 border-r border-gray-300 flex-shrink-0",
children: "canhelp.gr/site/"
}),
/*#__PURE__*/ _jsx("input", {
value: editUser.personalSiteSlug ?? '',
onChange: (e)=>setEditUser((u)=>({
...u,
personalSiteSlug: e.target.value || null
})),
placeholder: "my-username",
className: "flex-1 px-3 py-2 text-sm focus:outline-none"
})
]
}),
editUser.personalSiteSlug && /*#__PURE__*/ _jsx("a", {
href: `/site/${editUser.personalSiteSlug}`,
target: "_blank",
rel: "noopener noreferrer",
className: "shrink-0 px-3 py-2 border border-gray-300 rounded-lg text-sm text-blue-600 hover:bg-blue-50 flex items-center gap-1",
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: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
})
})
})
]
})
]
}),
editUser.personalSiteSlug && /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx("h4", {
className: "text-sm font-semibold text-gray-800 pt-3 border-t border-gray-100",
children: t('profile.site.visible_title')
}),
/*#__PURE__*/ _jsx("div", {
className: "space-y-1",
children: [
{
key: 'showBio',
label: t('profile.site.visible.bio')
},
{
key: 'showRating',
label: t('profile.site.visible.rating')
},
{
key: 'showServices',
label: t('profile.site.visible.services')
},
{
key: 'showPortfolio',
label: t('profile.site.visible.portfolio')
},
{
key: 'showReviews',
label: t('profile.site.visible.reviews')
},
{
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((item)=>/*#__PURE__*/ _jsxs("label", {
className: "flex items-center justify-between cursor-pointer py-1.5",
children: [
/*#__PURE__*/ _jsx("span", {
className: "text-sm text-gray-700",
children: item.label
}),
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: (editUser.siteSettings ?? {})[item.key] !== false,
onChange: (e)=>setEditUser((u)=>({
...u,
siteSettings: {
...u.siteSettings ?? {},
[item.key]: e.target.checked
}
})),
className: "w-4 h-4 rounded border-gray-300 text-blue-600"
})
]
}, item.key))
}),
/*#__PURE__*/ _jsxs("div", {
className: "pt-2",
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-1.5",
children: t('profile.site.theme')
}),
/*#__PURE__*/ _jsxs("select", {
value: (editUser.siteSettings ?? {}).siteTheme ?? 'dark',
onChange: (e)=>setEditUser((u)=>({
...u,
siteSettings: {
...u.siteSettings ?? {},
siteTheme: e.target.value
}
})),
className: "w-full border border-gray-300 rounded-lg px-3 py-2 text-sm",
children: [
/*#__PURE__*/ _jsx("option", {
value: "dark",
children: t('profile.site.theme.dark')
}),
/*#__PURE__*/ _jsx("option", {
value: "light",
children: t('profile.site.theme.light')
})
]
})
]
})
]
})
]
}),
editUserTab === 'specialist' && /*#__PURE__*/ _jsxs("div", {
className: "space-y-6",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: "block text-sm font-medium text-gray-700 mb-2",
children: t('admin.user_edit.skills')
}),
/*#__PURE__*/ _jsx("div", {
className: "flex flex-wrap gap-1.5 mb-2 min-h-[28px]",
children: (editUser.skills ?? []).map((s)=>/*#__PURE__*/ _jsxs("span", {
className: "inline-flex items-center gap-1 text-xs bg-blue-50 text-blue-700 px-2 py-0.5 rounded-full",
children: [
s,
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditUser((u)=>({
...u,
skills: (u.skills ?? []).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.key === ',') && skillInput.trim()) {
e.preventDefault();
const val = skillInput.trim().replace(/,$/, '');
if (val && !(editUser.skills ?? []).includes(val)) {
setEditUser((u)=>({
...u,
skills: [
...u.skills ?? [],
val
]
}));
}
setSkillInput('');
}
},
placeholder: t('admin.user_edit.skill_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", {
onClick: ()=>{
const val = skillInput.trim();
if (val && !(editUser.skills ?? []).includes(val)) {
setEditUser((u)=>({
...u,
skills: [
...u.skills ?? [],
val
]
}));
}
setSkillInput('');
},
className: "px-3 py-2 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700",
children: t('common.add')
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "border-t border-gray-100 pt-4",
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-sm font-medium text-gray-700 mb-3",
children: t('admin.user_edit.specialist_cards')
}),
editUserCardsLoading ? /*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 py-2",
children: t('common.loading')
}) : editUserCards.length === 0 ? /*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 py-4 text-center",
children: t('admin.user_edit.no_cards')
}) : /*#__PURE__*/ _jsx("div", {
className: "space-y-4",
children: editUserCards.map((card)=>/*#__PURE__*/ _jsxs("div", {
className: "border border-gray-200 bg-gray-50 rounded-xl p-4 space-y-3",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-3",
children: [
/*#__PURE__*/ _jsx("input", {
value: card.title ?? '',
onChange: (e)=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
title: e.target.value
} : c)),
placeholder: t('admin.user_edit.card_title'),
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__*/ _jsxs("label", {
className: "flex items-center gap-1.5 cursor-pointer flex-shrink-0",
children: [
/*#__PURE__*/ _jsx("input", {
type: "checkbox",
checked: card.isActive !== false,
onChange: (e)=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
isActive: e.target.checked
} : c)),
className: "w-4 h-4 rounded border-gray-300 text-blue-600"
}),
/*#__PURE__*/ _jsx("span", {
className: "text-xs text-gray-600",
children: t('admin.user_edit.active')
})
]
})
]
}),
/*#__PURE__*/ _jsx("textarea", {
value: card.description ?? '',
onChange: (e)=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
description: e.target.value
} : c)),
rows: 3,
placeholder: t('admin.user_edit.card_description'),
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", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs font-medium text-gray-500 mb-1.5",
children: t('admin.user_edit.skills')
}),
/*#__PURE__*/ _jsx("div", {
className: "flex flex-wrap gap-1.5 mb-1.5 min-h-[24px]",
children: (card.skills ?? []).map((s)=>/*#__PURE__*/ _jsxs("span", {
className: "inline-flex items-center gap-1 text-xs bg-blue-50 text-blue-700 px-2 py-0.5 rounded-full",
children: [
s,
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
skills: (c.skills ?? []).filter((x)=>x !== s)
} : c)),
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: cardSkillInputs[card.id] ?? '',
onChange: (e)=>setCardSkillInputs((prev)=>({
...prev,
[card.id]: e.target.value
})),
onKeyDown: (e)=>{
if ((e.key === 'Enter' || e.key === ',') && (cardSkillInputs[card.id] ?? '').trim()) {
e.preventDefault();
const val = (cardSkillInputs[card.id] ?? '').trim().replace(/,$/, '');
if (val && !(card.skills ?? []).includes(val)) {
setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
skills: [
...c.skills ?? [],
val
]
} : c));
}
setCardSkillInputs((prev)=>({
...prev,
[card.id]: ''
}));
}
},
placeholder: t('admin.user_edit.skill_placeholder'),
className: "flex-1 border border-gray-300 rounded-lg px-3 py-1.5 text-xs focus:outline-none focus:ring-2 focus:ring-blue-400"
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>{
const val = (cardSkillInputs[card.id] ?? '').trim();
if (val && !(card.skills ?? []).includes(val)) {
setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
skills: [
...c.skills ?? [],
val
]
} : c));
}
setCardSkillInputs((prev)=>({
...prev,
[card.id]: ''
}));
},
className: "px-2.5 py-1.5 bg-blue-600 text-white rounded-lg text-xs hover:bg-blue-700",
children: "+"
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs font-medium text-gray-500 mb-1.5",
children: t('admin.user_edit.categories')
}),
/*#__PURE__*/ _jsx("div", {
className: "flex flex-wrap gap-1.5 mb-1.5 min-h-[24px]",
children: (card.categories ?? []).map((slug)=>/*#__PURE__*/ _jsxs("span", {
className: "inline-flex items-center gap-1 text-xs bg-purple-50 text-purple-700 px-2 py-0.5 rounded-full",
children: [
getCatLabel(catRows.find((c)=>c.slug === slug) ?? {
slug
}, locale),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
categories: (c.categories ?? []).filter((x)=>x !== slug)
} : c)),
className: "text-purple-400 hover:text-purple-700 leading-none",
children: "\xd7"
})
]
}, slug))
}),
/*#__PURE__*/ _jsx(AdminCatPicker, {
catRows: catRows,
locale: locale,
selected: card.categories ?? [],
onAdd: (id)=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
categories: [
...c.categories ?? [],
id
]
} : c)),
addLabel: t('admin.user_edit.add_category')
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("div", {
className: "text-xs font-medium text-gray-500 mb-1.5",
children: t('admin.user_edit.locations')
}),
/*#__PURE__*/ _jsx("div", {
className: "flex flex-wrap gap-1.5 mb-1.5 min-h-[24px]",
children: (card.locations ?? []).map((slug)=>/*#__PURE__*/ _jsxs("span", {
className: "inline-flex items-center gap-1 text-xs bg-green-50 text-green-700 px-2 py-0.5 rounded-full",
children: [
getLocLabel(locRows.find((l)=>l.slug === slug) ?? {
slug
}, locale),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
locations: (c.locations ?? []).filter((x)=>x !== slug)
} : c)),
className: "text-green-400 hover:text-green-700 leading-none",
children: "\xd7"
})
]
}, slug))
}),
/*#__PURE__*/ _jsx(AdminLocPicker, {
locRows: locRows,
locale: locale,
selected: card.locations ?? [],
onAdd: (id)=>setEditUserCards((prev)=>prev.map((c)=>c.id === card.id ? {
...c,
locations: [
...c.locations ?? [],
id
]
} : c)),
addLabel: t('admin.user_edit.add_location')
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "flex justify-end pt-1",
children: /*#__PURE__*/ _jsx("button", {
onClick: ()=>saveCard(card.id),
disabled: cardSaving[card.id],
className: "px-4 py-1.5 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-xs font-medium disabled:opacity-50",
children: cardSaving[card.id] ? '...' : t('common.save')
})
})
]
}, card.id))
})
]
})
]
})
]
})
]
}),
editUserTab !== 'balance' ? /*#__PURE__*/ _jsxs("div", {
className: "border-t border-gray-100 px-6 py-4 flex gap-3 flex-shrink-0",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: saveEditUser,
disabled: editUserSaving,
className: "flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 rounded-lg text-sm font-semibold disabled:opacity-50",
children: editUserSaving ? '...' : t('common.save')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditUser(null),
className: "flex-1 bg-gray-100 hover:bg-gray-200 text-gray-700 py-2 rounded-lg text-sm font-medium",
children: t('common.cancel')
})
]
}) : /*#__PURE__*/ _jsx("div", {
className: "border-t border-gray-100 px-6 py-4 flex-shrink-0",
children: /*#__PURE__*/ _jsx("button", {
onClick: ()=>setEditUser(null),
className: "w-full bg-gray-100 hover:bg-gray-200 text-gray-700 py-2 rounded-lg text-sm font-medium",
children: t('common.close')
})
})
]
})
}),
editUser && balanceModal && /*#__PURE__*/ _jsx("div", {
className: "fixed inset-0 z-[60] flex items-center justify-center bg-black/40 px-4",
children: /*#__PURE__*/ _jsxs("div", {
className: `bg-white rounded-2xl shadow-2xl p-6 w-full max-w-sm border-t-4 ${balanceModal === 'topup' ? 'border-emerald-500' : 'border-rose-500'}`,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between mb-4",
children: [
/*#__PURE__*/ _jsx("h3", {
className: `text-base font-semibold ${balanceModal === 'topup' ? 'text-emerald-900' : 'text-rose-900'}`,
children: balanceModal === 'topup' ? t('admin.balance.topup.title') : t('admin.balance.withdraw.title')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setBalanceModal(null),
className: "text-gray-400 hover:text-gray-600 text-2xl leading-none",
children: "\xd7"
})
]
}),
/*#__PURE__*/ _jsxs("p", {
className: "text-xs text-gray-500 mb-4",
children: [
t('admin.user_edit.balance'),
": ",
/*#__PURE__*/ _jsxs("span", {
className: "font-semibold text-gray-700",
children: [
Number(editUser.balance ?? 0).toFixed(2),
" EUR"
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "space-y-3",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: `block text-sm font-medium mb-1 ${balanceModal === 'topup' ? 'text-emerald-800' : 'text-rose-800'}`,
children: balanceModal === 'topup' ? t('admin.balance.topup.amount') : t('admin.balance.withdraw.amount')
}),
/*#__PURE__*/ _jsx("input", {
type: "number",
min: "0.01",
step: "0.01",
value: balanceModal === 'topup' ? editUser.topUpAmount ?? '' : editUser.withdrawAmount ?? '',
onChange: (e)=>setEditUser((u)=>balanceModal === 'topup' ? {
...u,
topUpAmount: e.target.value
} : {
...u,
withdrawAmount: e.target.value
}),
className: `w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 ${balanceModal === 'topup' ? 'border-emerald-300 focus:ring-emerald-400' : 'border-rose-300 focus:ring-rose-400'}`
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("label", {
className: `block text-sm font-medium mb-1 ${balanceModal === 'topup' ? 'text-emerald-800' : 'text-rose-800'}`,
children: balanceModal === 'topup' ? t('admin.balance.topup.description') : t('admin.balance.withdraw.description')
}),
/*#__PURE__*/ _jsx("input", {
value: balanceModal === 'topup' ? editUser.topUpDescription ?? '' : editUser.withdrawDescription ?? '',
onChange: (e)=>setEditUser((u)=>balanceModal === 'topup' ? {
...u,
topUpDescription: e.target.value
} : {
...u,
withdrawDescription: e.target.value
}),
placeholder: balanceModal === 'topup' ? t('admin.balance.topup.description.placeholder') : t('admin.balance.withdraw.description.placeholder'),
className: `w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 ${balanceModal === 'topup' ? 'border-emerald-300 focus:ring-emerald-400' : 'border-rose-300 focus:ring-rose-400'}`
})
]
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-2 mt-5",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: async ()=>{
if (balanceModal === 'topup') {
await handleAdminTopUp();
} else {
await handleAdminWithdraw();
}
setBalanceModal(null);
},
disabled: balanceModal === 'topup' ? topUpSaving || !Number(editUser.topUpAmount) : withdrawSaving || !Number(editUser.withdrawAmount),
className: `flex-1 text-white py-2 rounded-lg text-sm font-semibold disabled:opacity-50 ${balanceModal === 'topup' ? 'bg-emerald-600 hover:bg-emerald-700' : 'bg-rose-600 hover:bg-rose-700'}`,
children: (balanceModal === 'topup' ? topUpSaving : withdrawSaving) ? t('common.loading') : balanceModal === 'topup' ? t('admin.balance.topup.submit') : t('admin.balance.withdraw.submit')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>setBalanceModal(null),
className: "flex-1 bg-gray-100 hover:bg-gray-200 text-gray-700 py-2 rounded-lg text-sm font-medium",
children: t('common.cancel')
})
]
})
]
})
})
]
})
]
})
]
})
});
}
function LocTree({ rows, parentId, depth, locale, expanded, onToggle, onEdit, onDelete, onAddChild, t }) {
const children = rows.filter((r)=>(r.parentId ?? null) === parentId);
if (children.length === 0) return null;
return /*#__PURE__*/ _jsx(_Fragment, {
children: children.sort((a, b)=>(a.order ?? 0) - (b.order ?? 0)).map((loc)=>{
const hasChildren = rows.some((r)=>r.parentId === loc.id);
const isOpen = expanded.has(loc.id);
const name = (locale === 'en' ? loc.nameEn : locale === 'ru' ? loc.nameRu : loc.nameEl) || loc.nameEl || loc.slug;
return /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: `flex items-center gap-2 px-4 py-3 hover:bg-gray-50 ${!loc.isActive ? 'opacity-50' : ''}`,
style: {
paddingLeft: `${16 + depth * 24}px`
},
children: [
/*#__PURE__*/ _jsx("button", {
onClick: ()=>hasChildren && onToggle(loc.id),
className: `w-5 h-5 flex items-center justify-center text-gray-400 rounded ${hasChildren ? 'hover:bg-gray-200 cursor-pointer' : 'cursor-default'}`,
children: hasChildren ? isOpen ? /*#__PURE__*/ _jsx("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "6 9 12 15 18 9"
})
}) : /*#__PURE__*/ _jsx("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "9 18 15 12 9 6"
})
}) : /*#__PURE__*/ _jsx("span", {
className: "w-3.5 h-3.5 block"
})
}),
depth === 0 ? /*#__PURE__*/ _jsx("svg", {
className: "w-5 h-5 text-blue-400 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: /*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"
})
}) : /*#__PURE__*/ _jsxs("svg", {
className: "w-4 h-4 text-gray-400 shrink-0",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 1.5,
children: [
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M15 11a3 3 0 11-6 0 3 3 0 016 0z"
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 min-w-0",
children: [
/*#__PURE__*/ _jsx("span", {
className: "font-medium text-gray-800 text-sm",
children: name
}),
/*#__PURE__*/ _jsx("span", {
className: "ml-2 text-xs text-gray-400",
children: loc.nameEn
}),
/*#__PURE__*/ _jsxs("span", {
className: "ml-1.5 font-mono text-xs text-gray-300",
children: [
"/",
loc.slug
]
})
]
}),
/*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${loc.isActive ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'}`,
children: loc.isActive ? t('admin.cat.active') : t('admin.cat.inactive')
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-1 flex-shrink-0",
children: [
depth === 0 && /*#__PURE__*/ _jsx("button", {
onClick: ()=>onAddChild(loc.id),
className: "text-xs px-2 py-1 rounded-lg bg-blue-50 text-blue-600 hover:bg-blue-100 font-medium",
title: t('admin.loc.add_district'),
children: "+"
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>onEdit(loc),
className: "text-xs px-2 py-1 rounded-lg bg-gray-100 text-gray-600 hover:bg-gray-200 font-medium",
children: t('common.edit')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>onDelete(loc.id, name),
className: "text-xs px-2 py-1 rounded-lg bg-red-50 text-red-600 hover:bg-red-100 font-medium",
children: t('common.delete')
})
]
})
]
}),
hasChildren && isOpen && /*#__PURE__*/ _jsx(LocTree, {
rows: rows,
parentId: loc.id,
depth: depth + 1,
locale: locale,
expanded: expanded,
onToggle: onToggle,
onEdit: onEdit,
onDelete: onDelete,
onAddChild: onAddChild,
t: t
})
]
}, loc.id);
})
});
}
function CatTree({ rows, parentId, depth, locale, expanded, onToggle, onEdit, onDelete, onAddChild, t }) {
const children = rows.filter((r)=>(r.parentId ?? null) === parentId);
if (children.length === 0) return null;
return /*#__PURE__*/ _jsx(_Fragment, {
children: children.sort((a, b)=>(a.order ?? 0) - (b.order ?? 0)).map((cat)=>{
const hasChildren = rows.some((r)=>r.parentId === cat.id);
const isOpen = expanded.has(cat.id);
const name = (locale === 'en' ? cat.namesEn : locale === 'ru' ? cat.namesRu : cat.namesEl) || cat.namesEl || cat.slug;
return /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
className: `flex items-center gap-2 px-4 py-3 hover:bg-gray-50 ${!cat.isActive ? 'opacity-50' : ''}`,
style: {
paddingLeft: `${16 + depth * 24}px`
},
children: [
/*#__PURE__*/ _jsx("button", {
onClick: ()=>hasChildren && onToggle(cat.id),
className: `w-5 h-5 flex items-center justify-center text-gray-400 rounded ${hasChildren ? 'hover:bg-gray-200 cursor-pointer' : 'cursor-default'}`,
children: hasChildren ? isOpen ? /*#__PURE__*/ _jsx("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "6 9 12 15 18 9"
})
}) : /*#__PURE__*/ _jsx("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2.5,
children: /*#__PURE__*/ _jsx("polyline", {
points: "9 18 15 12 9 6"
})
}) : /*#__PURE__*/ _jsx("span", {
className: "w-3.5 h-3.5 block"
})
}),
/*#__PURE__*/ _jsx("span", {
className: "text-lg w-7 text-center",
children: cat.icon
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 min-w-0",
children: [
/*#__PURE__*/ _jsx("span", {
className: "font-medium text-gray-800 text-sm",
children: name
}),
/*#__PURE__*/ _jsx("span", {
className: "ml-2 text-xs text-gray-400",
children: cat.namesEn || cat.names?.en
}),
/*#__PURE__*/ _jsxs("span", {
className: "ml-1.5 font-mono text-xs text-gray-300",
children: [
"/",
cat.slug
]
})
]
}),
/*#__PURE__*/ _jsx("span", {
className: `px-2 py-0.5 rounded-full text-xs font-medium ${cat.isActive ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'}`,
children: cat.isActive ? t('admin.cat.active') : t('admin.cat.inactive')
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-1 flex-shrink-0",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: ()=>onAddChild(cat.id),
className: "text-xs px-2 py-1 rounded-lg bg-blue-50 text-blue-600 hover:bg-blue-100 font-medium",
title: t('admin.cat.add_child'),
children: "+"
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>onEdit(cat),
className: "text-xs px-2 py-1 rounded-lg bg-gray-100 text-gray-600 hover:bg-gray-200 font-medium",
children: t('common.edit')
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>onDelete(cat.id, name),
className: "text-xs px-2 py-1 rounded-lg bg-red-50 text-red-600 hover:bg-red-100 font-medium",
children: t('common.delete')
})
]
})
]
}),
hasChildren && isOpen && /*#__PURE__*/ _jsx(CatTree, {
rows: rows,
parentId: cat.id,
depth: depth + 1,
locale: locale,
expanded: expanded,
onToggle: onToggle,
onEdit: onEdit,
onDelete: onDelete,
onAddChild: onAddChild,
t: t
})
]
}, cat.id);
})
});
}
function Pagination({ page, total, limit, onChange, totalLabel }) {
const pages = Math.ceil(total / limit);
if (pages <= 1) return null;
return /*#__PURE__*/ _jsxs("div", {
className: "flex items-center justify-between px-4 py-3 border-t border-gray-100 text-sm text-gray-500",
children: [
/*#__PURE__*/ _jsxs("span", {
children: [
totalLabel,
": ",
total
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex gap-1",
children: [
/*#__PURE__*/ _jsx("button", {
onClick: ()=>onChange(page - 1),
disabled: page === 1,
className: "px-3 py-1 rounded-lg border border-gray-200 disabled:opacity-40 hover:bg-gray-50",
children: "←"
}),
/*#__PURE__*/ _jsxs("span", {
className: "px-3 py-1",
children: [
page,
" / ",
pages
]
}),
/*#__PURE__*/ _jsx("button", {
onClick: ()=>onChange(page + 1),
disabled: page >= pages,
className: "px-3 py-1 rounded-lg border border-gray-200 disabled:opacity-40 hover:bg-gray-50",
children: "→"
})
]
})
]
});
}
// ── Activity log helpers ──────────────────────────────────────────────────
function parseLogDetails(details) {
try {
return details ? JSON.parse(details) : null;
} catch {
return null;
}
}
const EVENT_META = {
'user.login': {
icon: /*#__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: "M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
})
}),
labelKey: 'admin.event.user_login',
color: 'bg-blue-50 text-blue-700 border-blue-100'
},
'user.register': {
icon: /*#__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: "M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"
})
}),
labelKey: 'admin.event.user_register',
color: 'bg-green-50 text-green-700 border-green-100'
},
'admin.user.deactivate': {
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("circle", {
cx: "12",
cy: "12",
r: "10"
}),
/*#__PURE__*/ _jsx("line", {
x1: "4.93",
y1: "4.93",
x2: "19.07",
y2: "19.07"
})
]
}),
labelKey: 'admin.event.admin_user_deactivate',
color: 'bg-red-50 text-red-700 border-red-100'
},
'admin.user.activate': {
icon: /*#__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: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
})
}),
labelKey: 'admin.event.admin_user_activate',
color: 'bg-emerald-50 text-emerald-700 border-emerald-100'
},
'admin.user.role_changed': {
icon: /*#__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 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
})
}),
labelKey: 'admin.event.admin_user_role_changed',
color: 'bg-purple-50 text-purple-700 border-purple-100'
},
'admin.task.cancelled': {
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("circle", {
cx: "12",
cy: "12",
r: "10"
}),
/*#__PURE__*/ _jsx("line", {
x1: "15",
y1: "9",
x2: "9",
y2: "15"
}),
/*#__PURE__*/ _jsx("line", {
x1: "9",
y1: "9",
x2: "15",
y2: "15"
})
]
}),
labelKey: 'admin.event.admin_task_cancelled',
color: 'bg-orange-50 text-orange-700 border-orange-100'
},
'admin.task.deleted': {
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("polyline", {
points: "3 6 5 6 21 6"
}),
/*#__PURE__*/ _jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6m5 0V4a1 1 0 011-1h2a1 1 0 011 1v2"
})
]
}),
labelKey: 'admin.event.admin_task_deleted',
color: 'bg-red-50 text-red-700 border-red-100'
},
'admin.report.reviewed': {
icon: /*#__PURE__*/ _jsx("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: /*#__PURE__*/ _jsx("polyline", {
points: "20 6 9 17 4 12"
})
}),
labelKey: 'admin.event.admin_report_reviewed',
color: 'bg-teal-50 text-teal-700 border-teal-100'
},
'admin.report.dismissed': {
icon: /*#__PURE__*/ _jsxs("svg", {
className: "w-3.5 h-3.5",
fill: "none",
viewBox: "0 0 24 24",
stroke: "currentColor",
strokeWidth: 2,
children: [
/*#__PURE__*/ _jsx("line", {
x1: "18",
y1: "6",
x2: "6",
y2: "18"
}),
/*#__PURE__*/ _jsx("line", {
x1: "6",
y1: "6",
x2: "18",
y2: "18"
})
]
}),
labelKey: 'admin.event.admin_report_dismissed',
color: 'bg-gray-50 text-gray-600 border-gray-200'
},
'task.created': {
icon: /*#__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: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
})
}),
labelKey: 'admin.event.task_created',
color: 'bg-indigo-50 text-indigo-700 border-indigo-100'
}
};
function ActivityLogRow({ entry, dateLocale, onFilterUser, t }) {
const meta = EVENT_META[entry.event] ?? {
icon: /*#__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: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
})
}),
labelKey: entry.event,
color: 'bg-gray-50 text-gray-700 border-gray-200'
};
const details = parseLogDetails(entry.details);
return /*#__PURE__*/ _jsxs("div", {
className: "bg-white rounded-xl border border-gray-200 px-4 py-3 flex items-start gap-3",
children: [
/*#__PURE__*/ _jsxs("span", {
className: `shrink-0 mt-0.5 px-2.5 py-1 rounded-lg border text-xs font-semibold flex items-center gap-1.5 ${meta.color}`,
children: [
meta.icon,
" ",
t(meta.labelKey, meta.labelKey)
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "flex-1 min-w-0",
children: [
/*#__PURE__*/ _jsxs("div", {
className: "flex items-center gap-2 flex-wrap",
children: [
entry.userName && /*#__PURE__*/ _jsx("button", {
onClick: ()=>entry.userId && onFilterUser(entry.userId),
className: "text-sm font-medium text-gray-800 hover:text-blue-600",
children: entry.userName
}),
entry.userEmail && /*#__PURE__*/ _jsx("span", {
className: "text-xs text-gray-400",
children: entry.userEmail
})
]
}),
details && Object.keys(details).length > 0 && /*#__PURE__*/ _jsx("div", {
className: "mt-1 flex flex-wrap gap-2",
children: Object.entries(details).map(([k, v])=>/*#__PURE__*/ _jsxs("span", {
className: "text-xs bg-gray-100 text-gray-600 px-2 py-0.5 rounded",
children: [
k,
": ",
/*#__PURE__*/ _jsx("span", {
className: "font-medium",
children: String(v)
})
]
}, k))
}),
entry.ipAddress && /*#__PURE__*/ _jsx("p", {
className: "text-xs text-gray-400 mt-0.5",
children: entry.ipAddress
})
]
}),
/*#__PURE__*/ _jsx("time", {
className: "shrink-0 text-xs text-gray-400 whitespace-nowrap",
children: new Date(entry.createdAt).toLocaleString(dateLocale)
})
]
});
}
const MONTH_NAMES = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
function AdminMonthChart({ series, dateLocale = 'en-US' }) {
// Collect all unique months from all series, sorted
const monthSet = new Set();
series.forEach((s)=>s.data.forEach((r)=>monthSet.add(r.month)));
const months = Array.from(monthSet).sort();
if (months.length === 0) return null;
// Build lookup maps
const seriesVals = series.map((s)=>{
const map = {};
s.data.forEach((r)=>{
map[r.month] = Number(r.count);
});
return months.map((m)=>map[m] ?? 0);
});
const allVals = seriesVals.flat();
const maxVal = Math.max(...allVals, 1);
const W = 700;
const H = 160;
const padL = maxVal >= 1000000 ? 50 : maxVal >= 10000 ? 44 : maxVal >= 1000 ? 40 : 36;
const padB = 24;
const chartH = H - padB;
const totalBars = months.length * series.length;
const groupW = (W - padL - 8) / months.length;
const barW = Math.max(4, Math.min(20, groupW / series.length - 2));
const yTicks = [
0,
Math.round(maxVal / 3),
Math.round(maxVal * 2 / 3),
maxVal
];
function barX(mi, si) {
const groupStart = padL + mi * groupW + (groupW - series.length * (barW + 1)) / 2;
return groupStart + si * (barW + 1);
}
function barHeight(v) {
return v / maxVal * chartH;
}
return /*#__PURE__*/ _jsx("div", {
className: "overflow-x-auto",
children: /*#__PURE__*/ _jsxs("svg", {
viewBox: `0 0 ${W} ${H + 14}`,
className: "w-full",
style: {
minWidth: Math.max(360, months.length * 40)
},
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: fmtYLabel(v)
})
]
}, v);
}),
months.map((m, mi)=>series.map((s, si)=>{
const v = seriesVals[si][mi];
const bh = barHeight(v);
const x = barX(mi, si);
return /*#__PURE__*/ _jsx("rect", {
x: x,
y: chartH - bh,
width: barW,
height: bh,
fill: s.color,
opacity: 0.8,
rx: 2
}, `bar-${mi}-${si}`);
})),
months.map((m, mi)=>{
const [yr, mo] = m.slice(0, 7).split('-').map(Number);
const d = new Date(Date.UTC(yr, mo - 1, 2));
const label = new Intl.DateTimeFormat(dateLocale, {
month: 'short'
}).format(d) + (mi === 0 || mo === 1 ? ` ${yr}` : '');
const cx = padL + mi * groupW + groupW / 2;
return /*#__PURE__*/ _jsx("text", {
x: cx,
y: H + 12,
textAnchor: "middle",
fontSize: 9,
fill: "#9ca3af",
children: label
}, `xl-${mi}`);
}),
/*#__PURE__*/ _jsx("line", {
x1: padL,
y1: chartH,
x2: W - 4,
y2: chartH,
stroke: "#e5e7eb",
strokeWidth: 1
})
]
})
});
}
function getLast30Days() {
const days = [];
for(let i = 29; i >= 0; i--){
const d = new Date(Date.now() - i * 86400000);
days.push(d.toISOString().slice(0, 10));
}
return days;
}
function smoothPath(pts) {
if (pts.length < 2) return '';
let d = `M ${pts[0][0].toFixed(1)} ${pts[0][1].toFixed(1)}`;
for(let i = 1; i < pts.length; i++){
const cpx = ((pts[i - 1][0] + pts[i][0]) / 2).toFixed(1);
d += ` C ${cpx} ${pts[i - 1][1].toFixed(1)} ${cpx} ${pts[i][1].toFixed(1)} ${pts[i][0].toFixed(1)} ${pts[i][1].toFixed(1)}`;
}
return d;
}
function fmtYLabel(v) {
if (v >= 1000000) return `${+(v / 1000000).toFixed(1)}M`;
if (v >= 1000) return `${Math.round(v / 1000)}K`;
return String(v);
}
function AdminAreaChart({ series, days: daysProp }) {
const days = daysProp ?? getLast30Days();
const seriesVals = series.map((s)=>{
const map = {};
s.data.forEach((r)=>{
map[r.day] = Number(r.count);
});
return days.map((d)=>map[d] ?? 0);
});
const allVals = seriesVals.flat();
const maxVal = Math.max(...allVals, 1);
const W = 700;
const H = 160;
const padL = maxVal >= 10000 ? 44 : maxVal >= 1000 ? 40 : 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 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`;
}
// Y-axis: 4 labels (0, 1/3, 2/3, max)
const yTicks = [
0,
Math.round(maxVal / 3),
Math.round(maxVal * 2 / 3),
maxVal
];
// X-axis: every 7 days + last
const xTicks = days.map((d, i)=>({
i,
label: d.slice(8)
})).filter((_, i)=>i % 7 === 0 || i === days.length - 1);
return /*#__PURE__*/ _jsx("div", {
className: "overflow-x-auto",
children: /*#__PURE__*/ _jsxs("svg", {
viewBox: `0 0 ${W} ${H + 12}`,
className: "w-full",
style: {
minWidth: 360
},
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: fmtYLabel(v)
})
]
}, v);
}),
xTicks.map(({ i })=>{
const x = padL + i * stepX;
return /*#__PURE__*/ _jsx("line", {
x1: x,
y1: 0,
x2: x,
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)),
series.map((s, si)=>/*#__PURE__*/ _jsx("path", {
d: areaPath(seriesVals[si]),
fill: s.fill
}, `fill-${si}`)),
series.map((s, si)=>/*#__PURE__*/ _jsx("path", {
d: smoothPath(pts(seriesVals[si])),
fill: "none",
stroke: s.color,
strokeWidth: 2,
strokeLinecap: "round",
strokeLinejoin: "round"
}, `line-${si}`)),
series.map((s, si)=>{
const points = pts(seriesVals[si]);
const last = points[points.length - 1];
return /*#__PURE__*/ _jsx("g", {
children: /*#__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
})
]
})
});
}
`
kl
m*
no
`$qrtnext/dist/compiled/server-onlytuvwxyz{|}~next/dist/compiled/server-only/indexnext/dist/compiled/client-only/indexnext/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-domnext/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
/opt/canhelp/node_modules/next/dist/build/webpack/loaders/next-flight-client-module-loader.jswebpack/DefinePlugin process.env.NEXT_PUBLIC_API_URL"https://api.canhelp.gr"1b8f472a63b0fd54
`getCatLabelgetLocLabelAdminCatPickerAdminLocPickerLocTreeCatTreePaginationparseLogDetailsActivityLogRowAdminMonthChartgetLast30DayssmoothPathfmtYLabelAdminAreaChartTEMPLATE_VARSTEMPLATE_HINT_VARSAdminPageEVENT_METAMONTH_NAMES ԬyB`
d `=@
a=@ A
`4A
`,A
`A <
`(A= j
`-Ak
`!A
`$A
`3A
`/AGP 4
A8P 4
@ @ A\ {
@ `Q@ `p0A
@ `QA A\ {
@2 `Y@2 `x0A
@2 `YA2 A# $
@ `mA 0A $ 7$
@ `mA A)6 H6
@ `uA 0AL6 c6
@ `uA @ react/jsx-runtime
a=@
`4next/navigation
`,next/link
`@/lib/auth
`(@/context/locale
`-@/lib/api
`!
`$ @/lib/formatName
`3
@/lib/taskLocale
`/useStateA
l
@ `@ `$A
@ ` @ `(A
@ `0@ `8useRefA !
@ `@ `useEffectA` i
@ `7@ `@jsxs_jsxsA
@ `@ `A( -
@ `@ `jsx_jsxA
@ `"@ `&A
@ `0@ `4A
@ `"@ `&A
@ `"@ `&A, 0
@ `0@ `4AJ O
@ `"@ `'AC G
@ `"@ `&A
@ `0@ `4AU Z
@ `-@ `2A
@ `.@ `3A!" %"
@ `D@ `HA3# 7#
@ `6@ `:AL$ P$
@ `O@ `SA/&