@open-mercato/core 0.5.1-develop.2681.c559bb2bc3 → 0.5.1-develop.2683.4878a05b8e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/audit_logs/components/AuditLogsActions.js +2 -2
- package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
- package/dist/modules/auth/frontend/login.js +5 -5
- package/dist/modules/auth/frontend/login.js.map +2 -2
- package/dist/modules/customer_accounts/api/signup.js +3 -3
- package/dist/modules/customer_accounts/api/signup.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -3
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +5 -5
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/verify/page.js +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/verify/page.js.map +2 -2
- package/package.json +3 -3
- package/src/modules/audit_logs/components/AuditLogsActions.tsx +6 -4
- package/src/modules/auth/frontend/login.tsx +19 -15
- package/src/modules/customer_accounts/api/signup.ts +3 -4
- package/src/modules/data_sync/backend/data-sync/page.tsx +9 -9
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +21 -13
- package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +9 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +4 -2
- package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +9 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/verify/page.tsx +4 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/login/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport { useCallback, useMemo, useState } from 'react'\nimport Link from 'next/link'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {
|
|
5
|
-
"mappings": ";AAuEmE,
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport { useCallback, useMemo, useState } from 'react'\nimport Link from 'next/link'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { usePortalContext } from '@open-mercato/ui/portal/PortalContext'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { PortalInjectionSpots } from '@open-mercato/ui/backend/injection/spotIds'\n\ntype Props = { params: { orgSlug: string } }\n\nexport default function PortalLoginPage({ params }: Props) {\n const t = useT()\n const orgSlug = params.orgSlug\n const { tenant } = usePortalContext()\n\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const [error, setError] = useState<string | null>(null)\n const [submitting, setSubmitting] = useState(false)\n\n const handleSubmit = useCallback(\n async (event: React.FormEvent) => {\n event.preventDefault()\n setError(null)\n\n if (!tenant.tenantId) {\n setError(t('portal.org.invalid', 'Organization not found.'))\n return\n }\n\n setSubmitting(true)\n try {\n const result = await apiCall<{ ok: boolean; error?: string }>('/api/customer_accounts/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password, tenantId: tenant.tenantId }),\n })\n\n if (result.ok && result.result?.ok) {\n window.location.assign(`/${orgSlug}/portal/dashboard`)\n return\n }\n\n if (result.status === 423) {\n setError(t('portal.login.error.locked', 'Account locked. Try again later.'))\n } else if (result.status === 401) {\n setError(t('portal.login.error.invalidCredentials', 'Invalid email or password.'))\n } else {\n setError(result.result?.error || t('portal.login.error.generic', 'Login failed. Please try again.'))\n }\n } catch {\n setError(t('portal.login.error.generic', 'Login failed. Please try again.'))\n } finally {\n setSubmitting(false)\n }\n },\n [email, password, tenant.tenantId, orgSlug, t],\n )\n\n const injectionContext = useMemo(\n () => ({ orgSlug }),\n [orgSlug],\n )\n\n if (tenant.loading) {\n return <div className=\"flex items-center justify-center py-20\"><Spinner /></div>\n }\n\n if (tenant.error) {\n return (\n <div className=\"mx-auto w-full max-w-md py-12\">\n <Alert variant=\"destructive\">\n <AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>\n </Alert>\n </div>\n )\n }\n\n return (\n <div className=\"mx-auto w-full max-w-sm\">\n <div className=\"mb-8 text-center\">\n <h1 className=\"text-2xl font-bold tracking-tight\">{t('portal.login.title', 'Sign In')}</h1>\n <p className=\"mt-1.5 text-sm text-muted-foreground\">{t('portal.login.description', 'Enter your credentials to access the portal.')}</p>\n </div>\n\n <InjectionSpot spotId={PortalInjectionSpots.pageBefore('login')} context={injectionContext} />\n\n <form onSubmit={handleSubmit} className=\"flex flex-col gap-4\">\n {error ? (\n <Alert variant=\"destructive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n ) : null}\n\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"login-email\" className=\"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.login.email', 'Email')}</Label>\n <Input id=\"login-email\" type=\"email\" autoComplete=\"email\" required placeholder={t('portal.login.email.placeholder', 'you@example.com')} value={email} onChange={(e) => setEmail(e.target.value)} disabled={submitting} className=\"rounded-lg\" />\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"login-password\" className=\"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.login.password', 'Password')}</Label>\n <Input id=\"login-password\" type=\"password\" autoComplete=\"current-password\" required placeholder={t('portal.login.password.placeholder', '\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022')} value={password} onChange={(e) => setPassword(e.target.value)} disabled={submitting} className=\"rounded-lg\" />\n </div>\n\n <Button type=\"submit\" disabled={submitting} className=\"mt-1 w-full rounded-lg\">\n {submitting ? t('portal.login.submitting', 'Signing in...') : t('portal.login.submit', 'Sign In')}\n </Button>\n\n <p className=\"text-center text-[13px] text-muted-foreground\">\n {t('portal.login.noAccount', \"Don't have an account?\")}{' '}\n <Link href={`/${orgSlug}/portal/signup`} className=\"font-medium text-foreground underline underline-offset-4 hover:opacity-80\">\n {t('portal.login.signupLink', 'Sign up')}\n </Link>\n </p>\n </form>\n\n <InjectionSpot spotId={PortalInjectionSpots.pageAfter('login')} context={injectionContext} />\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -6,7 +6,7 @@ import { useRouter } from "next/navigation";
|
|
|
6
6
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
7
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
8
8
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
9
|
-
import {
|
|
9
|
+
import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
|
|
10
10
|
import { usePortalContext } from "@open-mercato/ui/portal/PortalContext";
|
|
11
11
|
import { PortalFeatureCard } from "@open-mercato/ui/portal/components/PortalFeatureCard";
|
|
12
12
|
import { InjectionSpot } from "@open-mercato/ui/backend/injection/InjectionSpot";
|
|
@@ -45,7 +45,7 @@ function PortalLandingPage({ params }) {
|
|
|
45
45
|
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx(Spinner, {}) });
|
|
46
46
|
}
|
|
47
47
|
if (tenant.error) {
|
|
48
|
-
return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-md py-12", children: /* @__PURE__ */ jsx(
|
|
48
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-md py-12", children: /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: t("portal.org.invalid", "Organization not found.") }) }) });
|
|
49
49
|
}
|
|
50
50
|
if (auth.user) return null;
|
|
51
51
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport { useEffect, useMemo } from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport {
|
|
5
|
-
"mappings": ";AAiBI,
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport { useEffect, useMemo } from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { usePortalContext } from '@open-mercato/ui/portal/PortalContext'\nimport { PortalFeatureCard } from '@open-mercato/ui/portal/components/PortalFeatureCard'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { PortalInjectionSpots } from '@open-mercato/ui/backend/injection/spotIds'\n\ntype Props = { params: { orgSlug: string } }\n\nfunction ShoppingBagIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z\" /><line x1=\"3\" x2=\"21\" y1=\"6\" y2=\"6\" /><path d=\"M16 10a4 4 0 0 1-8 0\" />\n </svg>\n )\n}\n\nfunction UserIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2\" /><circle cx=\"12\" cy=\"7\" r=\"4\" />\n </svg>\n )\n}\n\nfunction ShieldIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\" />\n </svg>\n )\n}\n\nexport default function PortalLandingPage({ params }: Props) {\n const t = useT()\n const router = useRouter()\n const orgSlug = params.orgSlug\n const { auth, tenant } = usePortalContext()\n\n // Redirect authenticated users to dashboard\n useEffect(() => {\n if (!auth.loading && auth.user) {\n router.replace(`/${orgSlug}/portal/dashboard`)\n }\n }, [auth.loading, auth.user, router, orgSlug])\n\n const injectionContext = useMemo(\n () => ({ orgSlug }),\n [orgSlug],\n )\n\n if (auth.loading || tenant.loading) {\n return <div className=\"flex items-center justify-center py-20\"><Spinner /></div>\n }\n\n if (tenant.error) {\n return (\n <div className=\"mx-auto w-full max-w-md py-12\">\n <Alert variant=\"destructive\">\n <AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>\n </Alert>\n </div>\n )\n }\n\n // Authenticated user \u2014 redirect is in progress\n if (auth.user) return null\n\n return (\n <>\n <InjectionSpot spotId={PortalInjectionSpots.pageBefore('home')} context={injectionContext} />\n\n <section className=\"flex flex-col items-center gap-5 py-8 text-center sm:py-16\">\n <p className=\"text-[11px] font-semibold uppercase tracking-[0.15em] text-muted-foreground/60\">\n {t('portal.nav.home', 'Customer Portal')}\n </p>\n <h1 className=\"max-w-2xl text-4xl font-bold tracking-tight text-foreground sm:text-5xl lg:text-6xl\">\n {t('portal.landing.hero.title', 'Welcome to your portal')}\n </h1>\n <p className=\"max-w-lg text-base leading-relaxed text-muted-foreground sm:text-lg\">\n {t('portal.landing.hero.description', 'Access your account, manage orders, and stay up to date.')}\n </p>\n <div className=\"mt-2 flex items-center gap-3\">\n <Button asChild size=\"lg\" className=\"rounded-lg px-6 text-[14px]\">\n <Link href={`/${orgSlug}/portal/login`}>{t('portal.landing.cta.login', 'Sign In')}</Link>\n </Button>\n <Button asChild variant=\"outline\" size=\"lg\" className=\"rounded-lg px-6 text-[14px]\">\n <Link href={`/${orgSlug}/portal/signup`}>{t('portal.landing.cta.signup', 'Create Account')}</Link>\n </Button>\n </div>\n </section>\n\n <section className=\"grid gap-4 sm:grid-cols-3\">\n <PortalFeatureCard\n icon={<ShoppingBagIcon className=\"size-5\" />}\n title={t('portal.landing.feature.orders', 'Orders & Invoices')}\n description={t('portal.landing.feature.orders.description', 'Track your orders, download invoices, and view delivery status in real time.')}\n />\n <PortalFeatureCard\n icon={<UserIcon className=\"size-5\" />}\n title={t('portal.landing.feature.account', 'Account Management')}\n description={t('portal.landing.feature.account.description', 'Update your profile, manage team members, and configure your preferences.')}\n />\n <PortalFeatureCard\n icon={<ShieldIcon className=\"size-5\" />}\n title={t('portal.landing.feature.security', 'Secure Access')}\n description={t('portal.landing.feature.security.description', 'Role-based permissions, session management, and full audit trail.')}\n />\n </section>\n\n <InjectionSpot spotId={PortalInjectionSpots.pageAfter('home')} context={injectionContext} />\n </>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -6,7 +6,7 @@ import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
|
6
6
|
import { Input } from "@open-mercato/ui/primitives/input";
|
|
7
7
|
import { Label } from "@open-mercato/ui/primitives/label";
|
|
8
8
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
9
|
-
import {
|
|
9
|
+
import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
|
|
10
10
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
11
11
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
12
12
|
import { usePortalContext } from "@open-mercato/ui/portal/PortalContext";
|
|
@@ -58,7 +58,7 @@ function PortalSignupPage({ params }) {
|
|
|
58
58
|
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx(Spinner, {}) });
|
|
59
59
|
}
|
|
60
60
|
if (tenant.error) {
|
|
61
|
-
return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-md py-12", children: /* @__PURE__ */ jsx(
|
|
61
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-md py-12", children: /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: t("portal.org.invalid", "Organization not found.") }) }) });
|
|
62
62
|
}
|
|
63
63
|
if (success) {
|
|
64
64
|
return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-sm text-center", children: [
|
|
@@ -75,7 +75,7 @@ function PortalSignupPage({ params }) {
|
|
|
75
75
|
] }),
|
|
76
76
|
/* @__PURE__ */ jsx(InjectionSpot, { spotId: PortalInjectionSpots.pageBefore("signup"), context: injectionContext }),
|
|
77
77
|
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [
|
|
78
|
-
error ? /* @__PURE__ */ jsx(
|
|
78
|
+
error ? /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }) : null,
|
|
79
79
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
80
80
|
/* @__PURE__ */ jsx(Label, { htmlFor: "signup-name", className: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70", children: t("portal.signup.displayName", "Full Name") }),
|
|
81
81
|
/* @__PURE__ */ jsx(Input, { id: "signup-name", type: "text", autoComplete: "name", required: true, placeholder: t("portal.signup.displayName.placeholder", "Jane Smith"), value: displayName, onChange: (e) => setDisplayName(e.target.value), disabled: submitting, className: "rounded-lg" })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/signup/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport { useCallback, useMemo, useState } from 'react'\nimport Link from 'next/link'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {
|
|
5
|
-
"mappings": ";AAmEmE,
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport { useCallback, useMemo, useState } from 'react'\nimport Link from 'next/link'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { usePortalContext } from '@open-mercato/ui/portal/PortalContext'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { PortalInjectionSpots } from '@open-mercato/ui/backend/injection/spotIds'\n\ntype Props = { params: { orgSlug: string } }\n\nexport default function PortalSignupPage({ params }: Props) {\n const t = useT()\n const orgSlug = params.orgSlug\n const { tenant } = usePortalContext()\n\n const [displayName, setDisplayName] = useState('')\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const [error, setError] = useState<string | null>(null)\n const [success, setSuccess] = useState(false)\n const [submitting, setSubmitting] = useState(false)\n\n const handleSubmit = useCallback(\n async (event: React.FormEvent) => {\n event.preventDefault()\n setError(null)\n\n if (!tenant.tenantId || !tenant.organizationId) {\n setError(t('portal.org.invalid', 'Organization not found.'))\n return\n }\n\n setSubmitting(true)\n try {\n const result = await apiCall<{ ok: boolean; error?: string }>('/api/customer_accounts/signup', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password, displayName, tenantId: tenant.tenantId, organizationId: tenant.organizationId }),\n })\n\n if (result.status === 202 && result.result?.ok) {\n setSuccess(true)\n return\n }\n\n setError(result.result?.error || t('portal.signup.error.generic', 'Signup failed. Please try again.'))\n } catch {\n setError(t('portal.signup.error.generic', 'Signup failed. Please try again.'))\n } finally {\n setSubmitting(false)\n }\n },\n [displayName, email, password, tenant.tenantId, tenant.organizationId, t],\n )\n\n const injectionContext = useMemo(\n () => ({ orgSlug }),\n [orgSlug],\n )\n\n if (tenant.loading) {\n return <div className=\"flex items-center justify-center py-20\"><Spinner /></div>\n }\n\n if (tenant.error) {\n return (\n <div className=\"mx-auto w-full max-w-md py-12\">\n <Alert variant=\"destructive\">\n <AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>\n </Alert>\n </div>\n )\n }\n\n if (success) {\n return (\n <div className=\"mx-auto w-full max-w-sm text-center\">\n <div className=\"mx-auto mb-4 flex size-12 items-center justify-center rounded-full bg-foreground text-background\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"size-6\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{t('portal.signup.success.title', 'Account Created')}</h1>\n <p className=\"mt-1.5 text-sm text-muted-foreground\">{t('portal.signup.success.description', 'Your account has been created. You can now sign in.')}</p>\n <Button asChild className=\"mt-6 w-full rounded-lg\">\n <Link href={`/${orgSlug}/portal/login`}>{t('portal.signup.success.loginLink', 'Sign In')}</Link>\n </Button>\n </div>\n )\n }\n\n return (\n <div className=\"mx-auto w-full max-w-sm\">\n <div className=\"mb-8 text-center\">\n <h1 className=\"text-2xl font-bold tracking-tight\">{t('portal.signup.title', 'Create Account')}</h1>\n <p className=\"mt-1.5 text-sm text-muted-foreground\">{t('portal.signup.description', 'Sign up for a portal account.')}</p>\n </div>\n\n <InjectionSpot spotId={PortalInjectionSpots.pageBefore('signup')} context={injectionContext} />\n\n <form onSubmit={handleSubmit} className=\"flex flex-col gap-4\">\n {error ? (\n <Alert variant=\"destructive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n ) : null}\n\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"signup-name\" className=\"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.signup.displayName', 'Full Name')}</Label>\n <Input id=\"signup-name\" type=\"text\" autoComplete=\"name\" required placeholder={t('portal.signup.displayName.placeholder', 'Jane Smith')} value={displayName} onChange={(e) => setDisplayName(e.target.value)} disabled={submitting} className=\"rounded-lg\" />\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"signup-email\" className=\"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.signup.email', 'Email')}</Label>\n <Input id=\"signup-email\" type=\"email\" autoComplete=\"email\" required placeholder={t('portal.signup.email.placeholder', 'you@example.com')} value={email} onChange={(e) => setEmail(e.target.value)} disabled={submitting} className=\"rounded-lg\" />\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"signup-password\" className=\"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.signup.password', 'Password')}</Label>\n <Input id=\"signup-password\" type=\"password\" autoComplete=\"new-password\" required placeholder={t('portal.signup.password.placeholder', '\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022')} value={password} onChange={(e) => setPassword(e.target.value)} disabled={submitting} className=\"rounded-lg\" />\n </div>\n\n <Button type=\"submit\" disabled={submitting} className=\"mt-1 w-full rounded-lg\">\n {submitting ? t('portal.signup.submitting', 'Creating account...') : t('portal.signup.submit', 'Create Account')}\n </Button>\n\n <p className=\"text-center text-[13px] text-muted-foreground\">\n {t('portal.signup.hasAccount', 'Already have an account?')}{' '}\n <Link href={`/${orgSlug}/portal/login`} className=\"font-medium text-foreground underline underline-offset-4 hover:opacity-80\">\n {t('portal.signup.loginLink', 'Sign in')}\n </Link>\n </p>\n </form>\n\n <InjectionSpot spotId={PortalInjectionSpots.pageAfter('signup')} context={injectionContext} />\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -6,7 +6,7 @@ import { useSearchParams } from "next/navigation";
|
|
|
6
6
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
7
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
8
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
9
|
-
import {
|
|
9
|
+
import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
|
|
10
10
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
11
11
|
function PortalVerifyPage({ params }) {
|
|
12
12
|
const t = useT();
|
|
@@ -58,7 +58,7 @@ function PortalVerifyPage({ params }) {
|
|
|
58
58
|
] });
|
|
59
59
|
}
|
|
60
60
|
return /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-sm flex-col gap-4 py-12", children: [
|
|
61
|
-
/* @__PURE__ */ jsx(
|
|
61
|
+
/* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error || t("portal.verify.error.generic", "Email verification failed. Please try again.") }) }),
|
|
62
62
|
/* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", className: "rounded-lg", children: /* @__PURE__ */ jsx(Link, { href: `/${params.orgSlug}/portal/login`, children: t("portal.verify.error.backToLogin", "Back to sign in") }) })
|
|
63
63
|
] });
|
|
64
64
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/verify/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport { useEffect, useState } from 'react'\nimport Link from 'next/link'\nimport { useSearchParams } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {
|
|
5
|
-
"mappings": ";AAqDQ,cACA,YADA;AApDR,SAAS,WAAW,gBAAgB;AACpC,OAAO,UAAU;AACjB,SAAS,uBAAuB;AAChC,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport { useEffect, useState } from 'react'\nimport Link from 'next/link'\nimport { useSearchParams } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\ntype Props = { params: { orgSlug: string } }\n\ntype VerifyState = 'verifying' | 'success' | 'error'\n\nexport default function PortalVerifyPage({ params }: Props) {\n const t = useT()\n const searchParams = useSearchParams()\n const token = searchParams.get('token') ?? ''\n const [state, setState] = useState<VerifyState>(token ? 'verifying' : 'error')\n const [error, setError] = useState<string | null>(token ? null : t('portal.verify.error.invalidToken', 'Verification token is missing.'))\n\n useEffect(() => {\n if (!token) return\n\n let active = true\n\n void apiCall<{ ok: boolean; error?: string }>('/api/customer_accounts/email/verify', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token }),\n }).then((result) => {\n if (!active) return\n if (result.ok && result.result?.ok) {\n setState('success')\n return\n }\n\n setState('error')\n setError(result.result?.error || t('portal.verify.error.generic', 'Email verification failed. Please try again.'))\n }).catch(() => {\n if (!active) return\n setState('error')\n setError(t('portal.verify.error.generic', 'Email verification failed. Please try again.'))\n })\n\n return () => {\n active = false\n }\n }, [token, t])\n\n if (state === 'verifying') {\n return (\n <div className=\"mx-auto flex max-w-sm flex-col items-center gap-4 py-12 text-center\">\n <Spinner />\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{t('portal.verify.title', 'Verifying email')}</h1>\n <p className=\"mt-1.5 text-sm text-muted-foreground\">{t('portal.verify.description', 'Please wait while we verify your email address.')}</p>\n </div>\n </div>\n )\n }\n\n if (state === 'success') {\n return (\n <div className=\"mx-auto flex max-w-sm flex-col items-center gap-4 py-12 text-center\">\n <div className=\"mx-auto flex size-12 items-center justify-center rounded-full bg-foreground text-background\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"size-6\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{t('portal.verify.success.title', 'Email verified')}</h1>\n <p className=\"mt-1.5 text-sm text-muted-foreground\">{t('portal.verify.success.description', 'Your email has been verified. You can now sign in to the portal.')}</p>\n </div>\n <Button asChild className=\"w-full rounded-lg\">\n <Link href={`/${params.orgSlug}/portal/login`}>{t('portal.verify.success.loginLink', 'Sign In')}</Link>\n </Button>\n </div>\n )\n }\n\n return (\n <div className=\"mx-auto flex max-w-sm flex-col gap-4 py-12\">\n <Alert variant=\"destructive\">\n <AlertDescription>{error || t('portal.verify.error.generic', 'Email verification failed. Please try again.')}</AlertDescription>\n </Alert>\n <Button asChild variant=\"outline\" className=\"rounded-lg\">\n <Link href={`/${params.orgSlug}/portal/login`}>{t('portal.verify.error.backToLogin', 'Back to sign in')}</Link>\n </Button>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAqDQ,cACA,YADA;AApDR,SAAS,WAAW,gBAAgB;AACpC,OAAO,UAAU;AACjB,SAAS,uBAAuB;AAChC,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,OAAO,wBAAwB;AACxC,SAAS,eAAe;AAMT,SAAR,iBAAkC,EAAE,OAAO,GAAU;AAC1D,QAAM,IAAI,KAAK;AACf,QAAM,eAAe,gBAAgB;AACrC,QAAM,QAAQ,aAAa,IAAI,OAAO,KAAK;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAsB,QAAQ,cAAc,OAAO;AAC7E,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,QAAQ,OAAO,EAAE,oCAAoC,gCAAgC,CAAC;AAExI,YAAU,MAAM;AACd,QAAI,CAAC,MAAO;AAEZ,QAAI,SAAS;AAEb,SAAK,QAAyC,uCAAuC;AAAA,MACnF,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,IAChC,CAAC,EAAE,KAAK,CAAC,WAAW;AAClB,UAAI,CAAC,OAAQ;AACb,UAAI,OAAO,MAAM,OAAO,QAAQ,IAAI;AAClC,iBAAS,SAAS;AAClB;AAAA,MACF;AAEA,eAAS,OAAO;AAChB,eAAS,OAAO,QAAQ,SAAS,EAAE,+BAA+B,8CAA8C,CAAC;AAAA,IACnH,CAAC,EAAE,MAAM,MAAM;AACb,UAAI,CAAC,OAAQ;AACb,eAAS,OAAO;AAChB,eAAS,EAAE,+BAA+B,8CAA8C,CAAC;AAAA,IAC3F,CAAC;AAED,WAAO,MAAM;AACX,eAAS;AAAA,IACX;AAAA,EACF,GAAG,CAAC,OAAO,CAAC,CAAC;AAEb,MAAI,UAAU,aAAa;AACzB,WACE,qBAAC,SAAI,WAAU,uEACb;AAAA,0BAAC,WAAQ;AAAA,MACT,qBAAC,SACC;AAAA,4BAAC,QAAG,WAAU,qCAAqC,YAAE,uBAAuB,iBAAiB,GAAE;AAAA,QAC/F,oBAAC,OAAE,WAAU,wCAAwC,YAAE,6BAA6B,iDAAiD,GAAE;AAAA,SACzI;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,UAAU,WAAW;AACvB,WACE,qBAAC,SAAI,WAAU,uEACb;AAAA,0BAAC,SAAI,WAAU,+FACb,8BAAC,SAAI,OAAM,8BAA6B,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,WAAU,UACnK,8BAAC,cAAS,QAAO,kBAAiB,GACpC,GACF;AAAA,MACA,qBAAC,SACC;AAAA,4BAAC,QAAG,WAAU,qCAAqC,YAAE,+BAA+B,gBAAgB,GAAE;AAAA,QACtG,oBAAC,OAAE,WAAU,wCAAwC,YAAE,qCAAqC,kEAAkE,GAAE;AAAA,SAClK;AAAA,MACA,oBAAC,UAAO,SAAO,MAAC,WAAU,qBACxB,8BAAC,QAAK,MAAM,IAAI,OAAO,OAAO,iBAAkB,YAAE,mCAAmC,SAAS,GAAE,GAClG;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,8CACb;AAAA,wBAAC,SAAM,SAAQ,eACb,8BAAC,oBAAkB,mBAAS,EAAE,+BAA+B,8CAA8C,GAAE,GAC/G;AAAA,IACA,oBAAC,UAAO,SAAO,MAAC,SAAQ,WAAU,WAAU,cAC1C,8BAAC,QAAK,MAAM,IAAI,OAAO,OAAO,iBAAkB,YAAE,mCAAmC,iBAAiB,GAAE,GAC1G;AAAA,KACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.5.1-develop.
|
|
3
|
+
"version": "0.5.1-develop.2683.4878a05b8e",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -234,10 +234,10 @@
|
|
|
234
234
|
"ts-pattern": "^5.0.0"
|
|
235
235
|
},
|
|
236
236
|
"peerDependencies": {
|
|
237
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
237
|
+
"@open-mercato/shared": "0.5.1-develop.2683.4878a05b8e"
|
|
238
238
|
},
|
|
239
239
|
"devDependencies": {
|
|
240
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
240
|
+
"@open-mercato/shared": "0.5.1-develop.2683.4878a05b8e",
|
|
241
241
|
"@testing-library/dom": "^10.4.1",
|
|
242
242
|
"@testing-library/jest-dom": "^6.9.1",
|
|
243
243
|
"@testing-library/react": "^16.3.1",
|
|
@@ -10,7 +10,7 @@ import { ActionLogDetailsDialog } from './ActionLogDetailsDialog'
|
|
|
10
10
|
import { Undo2, RotateCcw } from 'lucide-react'
|
|
11
11
|
import { markRedoConsumed, markUndoSuccess } from '@open-mercato/ui/backend/operations/store'
|
|
12
12
|
import { useAuditPermissions, canUndoEntry, canRedoEntry } from '@open-mercato/ui/backend/version-history'
|
|
13
|
-
import {
|
|
13
|
+
import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
|
|
14
14
|
|
|
15
15
|
export type ActionLogItem = {
|
|
16
16
|
id: string
|
|
@@ -231,9 +231,11 @@ export function AuditLogsActions({
|
|
|
231
231
|
return (
|
|
232
232
|
<>
|
|
233
233
|
{showSelfOnlyHint ? (
|
|
234
|
-
<
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
<Alert variant="info" className="mb-4">
|
|
235
|
+
<AlertDescription>
|
|
236
|
+
{t('audit_logs.hint.view_self_only', 'Showing only your own changes. Contact an administrator for broader access.')}
|
|
237
|
+
</AlertDescription>
|
|
238
|
+
</Alert>
|
|
237
239
|
) : null}
|
|
238
240
|
<DataTable<ActionLogItem>
|
|
239
241
|
title={t('audit_logs.actions.title')}
|
|
@@ -13,7 +13,7 @@ import { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'
|
|
|
13
13
|
import { clearAllOperations } from '@open-mercato/ui/backend/operations/store'
|
|
14
14
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
15
15
|
import { X } from 'lucide-react'
|
|
16
|
-
import {
|
|
16
|
+
import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
|
|
17
17
|
import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
|
|
18
18
|
import { useRegisteredComponent } from '@open-mercato/ui/backend/injection/useRegisteredComponent'
|
|
19
19
|
import type { AuthOverride, LoginFormWidgetContext } from './login-injection'
|
|
@@ -301,22 +301,26 @@ export default function LoginPage() {
|
|
|
301
301
|
<input type="hidden" name="tenantId" value={tenantId} />
|
|
302
302
|
) : null}
|
|
303
303
|
{!!translatedRoles.length && (
|
|
304
|
-
<
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
304
|
+
<Alert variant="info" className="text-center">
|
|
305
|
+
<AlertDescription>
|
|
306
|
+
{translate(
|
|
307
|
+
translatedRoles.length > 1 ? 'auth.login.requireRolesMessage' : 'auth.login.requireRoleMessage',
|
|
308
|
+
translatedRoles.length > 1
|
|
309
|
+
? 'Access requires one of the following roles: {roles}'
|
|
310
|
+
: 'Access requires role: {roles}',
|
|
311
|
+
{ roles: translatedRoles.join(', ') },
|
|
312
|
+
)}
|
|
313
|
+
</AlertDescription>
|
|
314
|
+
</Alert>
|
|
313
315
|
)}
|
|
314
316
|
{!!translatedFeatures.length && (
|
|
315
|
-
<
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
317
|
+
<Alert variant="info" className="text-center">
|
|
318
|
+
<AlertDescription>
|
|
319
|
+
{translate('auth.login.featureDenied', "You don't have access to this feature ({feature}). Please contact your administrator.", {
|
|
320
|
+
feature: translatedFeatures.join(', '),
|
|
321
|
+
})}
|
|
322
|
+
</AlertDescription>
|
|
323
|
+
</Alert>
|
|
320
324
|
)}
|
|
321
325
|
{showTenantInvalid ? (
|
|
322
326
|
<div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-center text-xs text-red-700">
|
|
@@ -28,7 +28,6 @@ export const metadata: { path?: string; requireAuth?: boolean } = { requireAuth:
|
|
|
28
28
|
// response latency between the existing-user and new-user signup branches so the endpoint's
|
|
29
29
|
// 202-for-both contract is not undone by a timing side channel.
|
|
30
30
|
const TIMING_EQUALIZATION_HASH = '$2b$10$.F2A6UHFzk.d8trNdfqt4OLz05Nf3IOuMmN6VJKflhD4.rz.prR8i'
|
|
31
|
-
|
|
32
31
|
function resolvePortalLoginUrl(baseUrl: string, organizationSlug?: string | null): string {
|
|
33
32
|
return organizationSlug
|
|
34
33
|
? `${baseUrl}/${organizationSlug}/portal/login`
|
|
@@ -71,13 +70,13 @@ export async function POST(req: Request) {
|
|
|
71
70
|
|
|
72
71
|
let baseUrl: string
|
|
73
72
|
try {
|
|
74
|
-
baseUrl = getSecurityEmailBaseUrl(req
|
|
73
|
+
baseUrl = getSecurityEmailBaseUrl(req)
|
|
75
74
|
} catch (error) {
|
|
76
75
|
const mapped = mapSecurityEmailUrlError(error, {
|
|
77
76
|
scope: 'customer_accounts.signup',
|
|
78
|
-
configMessage: '
|
|
77
|
+
configMessage: 'Customer signup is not configured',
|
|
79
78
|
})
|
|
80
|
-
if (mapped) return NextResponse.json(
|
|
79
|
+
if (mapped) return NextResponse.json(mapped.body, { status: mapped.status })
|
|
81
80
|
throw error
|
|
82
81
|
}
|
|
83
82
|
|
|
@@ -12,7 +12,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@open-mercato/ui/primi
|
|
|
12
12
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
13
13
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
14
14
|
import { Label } from '@open-mercato/ui/primitives/label'
|
|
15
|
-
import {
|
|
15
|
+
import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
|
|
16
16
|
import { Separator } from '@open-mercato/ui/primitives/separator'
|
|
17
17
|
import { Switch } from '@open-mercato/ui/primitives/switch'
|
|
18
18
|
import { RowActions } from '@open-mercato/ui/backend/RowActions'
|
|
@@ -937,20 +937,20 @@ export default function SyncRunsDashboardPage() {
|
|
|
937
937
|
</div>
|
|
938
938
|
|
|
939
939
|
{selectedIntegration && !selectedIntegration.isEnabled ? (
|
|
940
|
-
<
|
|
941
|
-
<
|
|
940
|
+
<Alert variant="warning">
|
|
941
|
+
<AlertDescription className="inline-flex items-center gap-2">
|
|
942
942
|
<CircleAlert className="size-4" />
|
|
943
943
|
<span>{t('integrations.detail.state.disabled', 'This integration is disabled. Enable it on the integration settings page before starting a sync.')}</span>
|
|
944
|
-
</
|
|
945
|
-
</
|
|
944
|
+
</AlertDescription>
|
|
945
|
+
</Alert>
|
|
946
946
|
) : null}
|
|
947
947
|
{selectedIntegration && !selectedIntegration.hasCredentials ? (
|
|
948
|
-
<
|
|
949
|
-
<
|
|
948
|
+
<Alert variant="warning">
|
|
949
|
+
<AlertDescription className="inline-flex items-center gap-2">
|
|
950
950
|
<CircleAlert className="size-4" />
|
|
951
951
|
<span>{t('integrations.detail.credentials.notConfigured', 'Credentials are not configured yet. Save the integration credentials before starting a sync.')}</span>
|
|
952
|
-
</
|
|
953
|
-
</
|
|
952
|
+
</AlertDescription>
|
|
953
|
+
</Alert>
|
|
954
954
|
) : null}
|
|
955
955
|
</CardContent>
|
|
956
956
|
</Card>
|
|
@@ -7,7 +7,7 @@ import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
|
7
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
8
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
9
9
|
import { Label } from '@open-mercato/ui/primitives/label'
|
|
10
|
-
import {
|
|
10
|
+
import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
|
|
11
11
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
12
12
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
13
13
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -307,9 +307,11 @@ export function IntegrationScheduleTab(props: IntegrationScheduleTabProps) {
|
|
|
307
307
|
|
|
308
308
|
if (!option) {
|
|
309
309
|
return (
|
|
310
|
-
<
|
|
311
|
-
|
|
312
|
-
|
|
310
|
+
<Alert variant="warning">
|
|
311
|
+
<AlertDescription>
|
|
312
|
+
{t('data_sync.integrationTab.notAvailable', 'This integration is not registered as a data sync provider.')}
|
|
313
|
+
</AlertDescription>
|
|
314
|
+
</Alert>
|
|
313
315
|
)
|
|
314
316
|
}
|
|
315
317
|
|
|
@@ -345,21 +347,27 @@ export function IntegrationScheduleTab(props: IntegrationScheduleTabProps) {
|
|
|
345
347
|
</div>
|
|
346
348
|
|
|
347
349
|
{!props.isEnabled ? (
|
|
348
|
-
<
|
|
349
|
-
|
|
350
|
-
|
|
350
|
+
<Alert variant="warning">
|
|
351
|
+
<AlertDescription>
|
|
352
|
+
{t('data_sync.integrationTab.integrationDisabledNotice', 'The integration is disabled. You can save schedules now, but runs will stay blocked until the integration is enabled.')}
|
|
353
|
+
</AlertDescription>
|
|
354
|
+
</Alert>
|
|
351
355
|
) : null}
|
|
352
356
|
|
|
353
357
|
{!props.hasCredentials ? (
|
|
354
|
-
<
|
|
355
|
-
|
|
356
|
-
|
|
358
|
+
<Alert variant="warning">
|
|
359
|
+
<AlertDescription>
|
|
360
|
+
{t('data_sync.integrationTab.credentialsMissingNotice', 'Credentials are still missing. Save schedules first if you want, but manual and scheduled runs will fail until credentials are configured.')}
|
|
361
|
+
</AlertDescription>
|
|
362
|
+
</Alert>
|
|
357
363
|
) : null}
|
|
358
364
|
|
|
359
365
|
{rows.length === 0 ? (
|
|
360
|
-
<
|
|
361
|
-
|
|
362
|
-
|
|
366
|
+
<Alert variant="info">
|
|
367
|
+
<AlertDescription>
|
|
368
|
+
{t('data_sync.integrationTab.empty', 'This provider does not expose any schedulable sync entities yet.')}
|
|
369
|
+
</AlertDescription>
|
|
370
|
+
</Alert>
|
|
363
371
|
) : (
|
|
364
372
|
<div className="overflow-x-auto rounded-lg border">
|
|
365
373
|
<table className="w-full min-w-[1080px] text-sm">
|
|
@@ -5,7 +5,7 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
|
5
5
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
6
6
|
import { Label } from '@open-mercato/ui/primitives/label'
|
|
7
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
|
-
import {
|
|
8
|
+
import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
|
|
9
9
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
10
10
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
11
|
import { usePortalContext } from '@open-mercato/ui/portal/PortalContext'
|
|
@@ -75,7 +75,9 @@ export default function PortalLoginPage({ params }: Props) {
|
|
|
75
75
|
if (tenant.error) {
|
|
76
76
|
return (
|
|
77
77
|
<div className="mx-auto w-full max-w-md py-12">
|
|
78
|
-
<
|
|
78
|
+
<Alert variant="destructive">
|
|
79
|
+
<AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>
|
|
80
|
+
</Alert>
|
|
79
81
|
</div>
|
|
80
82
|
)
|
|
81
83
|
}
|
|
@@ -90,7 +92,11 @@ export default function PortalLoginPage({ params }: Props) {
|
|
|
90
92
|
<InjectionSpot spotId={PortalInjectionSpots.pageBefore('login')} context={injectionContext} />
|
|
91
93
|
|
|
92
94
|
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
|
|
93
|
-
{error ?
|
|
95
|
+
{error ? (
|
|
96
|
+
<Alert variant="destructive">
|
|
97
|
+
<AlertDescription>{error}</AlertDescription>
|
|
98
|
+
</Alert>
|
|
99
|
+
) : null}
|
|
94
100
|
|
|
95
101
|
<div className="flex flex-col gap-1.5">
|
|
96
102
|
<Label htmlFor="login-email" className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">{t('portal.login.email', 'Email')}</Label>
|
|
@@ -5,7 +5,7 @@ import { useRouter } from 'next/navigation'
|
|
|
5
5
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
6
6
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
7
7
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
8
|
-
import {
|
|
8
|
+
import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
|
|
9
9
|
import { usePortalContext } from '@open-mercato/ui/portal/PortalContext'
|
|
10
10
|
import { PortalFeatureCard } from '@open-mercato/ui/portal/components/PortalFeatureCard'
|
|
11
11
|
import { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'
|
|
@@ -62,7 +62,9 @@ export default function PortalLandingPage({ params }: Props) {
|
|
|
62
62
|
if (tenant.error) {
|
|
63
63
|
return (
|
|
64
64
|
<div className="mx-auto w-full max-w-md py-12">
|
|
65
|
-
<
|
|
65
|
+
<Alert variant="destructive">
|
|
66
|
+
<AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>
|
|
67
|
+
</Alert>
|
|
66
68
|
</div>
|
|
67
69
|
)
|
|
68
70
|
}
|
|
@@ -5,7 +5,7 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
|
5
5
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
6
6
|
import { Label } from '@open-mercato/ui/primitives/label'
|
|
7
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
|
-
import {
|
|
8
|
+
import { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'
|
|
9
9
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
10
10
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
11
|
import { usePortalContext } from '@open-mercato/ui/portal/PortalContext'
|
|
@@ -71,7 +71,9 @@ export default function PortalSignupPage({ params }: Props) {
|
|
|
71
71
|
if (tenant.error) {
|
|
72
72
|
return (
|
|
73
73
|
<div className="mx-auto w-full max-w-md py-12">
|
|
74
|
-
<
|
|
74
|
+
<Alert variant="destructive">
|
|
75
|
+
<AlertDescription>{t('portal.org.invalid', 'Organization not found.')}</AlertDescription>
|
|
76
|
+
</Alert>
|
|
75
77
|
</div>
|
|
76
78
|
)
|
|
77
79
|
}
|
|
@@ -103,7 +105,11 @@ export default function PortalSignupPage({ params }: Props) {
|
|
|
103
105
|
<InjectionSpot spotId={PortalInjectionSpots.pageBefore('signup')} context={injectionContext} />
|
|
104
106
|
|
|
105
107
|
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
|
|
106
|
-
{error ?
|
|
108
|
+
{error ? (
|
|
109
|
+
<Alert variant="destructive">
|
|
110
|
+
<AlertDescription>{error}</AlertDescription>
|
|
111
|
+
</Alert>
|
|
112
|
+
) : null}
|
|
107
113
|
|
|
108
114
|
<div className="flex flex-col gap-1.5">
|
|
109
115
|
<Label htmlFor="signup-name" className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70">{t('portal.signup.displayName', 'Full Name')}</Label>
|