@open-mercato/core 0.6.7-develop.6795.1.8a3f27921c → 0.6.7-develop.6824.1.21fff90682
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/.turbo/turbo-build.log +1 -1
- package/dist/generated/entities/customer_deal_person_link/index.js +2 -0
- package/dist/generated/entities/customer_deal_person_link/index.js.map +2 -2
- package/dist/generated/entities/customer_user_invitation/index.js +2 -0
- package/dist/generated/entities/customer_user_invitation/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/auth/lib/backendChrome.js +10 -9
- package/dist/modules/auth/lib/backendChrome.js.map +2 -2
- package/dist/modules/auth/lib/tenantAccess.js +7 -0
- package/dist/modules/auth/lib/tenantAccess.js.map +2 -2
- package/dist/modules/business_rules/api/openmercato-call-options/route.js +85 -0
- package/dist/modules/business_rules/api/openmercato-call-options/route.js.map +7 -0
- package/dist/modules/business_rules/api/rules/route.js +71 -4
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/components/ActionBuilder.js +47 -4
- package/dist/modules/business_rules/components/ActionBuilder.js.map +3 -3
- package/dist/modules/business_rules/components/ActionRow.js +106 -16
- package/dist/modules/business_rules/components/ActionRow.js.map +2 -2
- package/dist/modules/business_rules/components/utils/actionValidation.js +6 -0
- package/dist/modules/business_rules/components/utils/actionValidation.js.map +2 -2
- package/dist/modules/business_rules/lib/action-executor.js +148 -0
- package/dist/modules/business_rules/lib/action-executor.js.map +2 -2
- package/dist/modules/business_rules/lib/openmercato-call-options-types.js +5 -0
- package/dist/modules/business_rules/lib/openmercato-call-options-types.js.map +7 -0
- package/dist/modules/business_rules/lib/openmercato-call-options.js +231 -0
- package/dist/modules/business_rules/lib/openmercato-call-options.js.map +7 -0
- package/dist/modules/business_rules/lib/rule-engine.js +5 -1
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js +11 -1
- package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js +11 -6
- package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +12 -0
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id].js +10 -1
- package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users-invite.js +61 -4
- package/dist/modules/customer_accounts/api/admin/users-invite.js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users-invite.js +20 -2
- package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
- package/dist/modules/customer_accounts/data/entities.js +3 -0
- package/dist/modules/customer_accounts/data/entities.js.map +2 -2
- package/dist/modules/customer_accounts/data/validators.js +1 -0
- package/dist/modules/customer_accounts/data/validators.js.map +2 -2
- package/dist/modules/customer_accounts/emails/CustomerInvitationEmail.js +26 -0
- package/dist/modules/customer_accounts/emails/CustomerInvitationEmail.js.map +7 -0
- package/dist/modules/customer_accounts/lib/customerEntityOwnership.js +29 -3
- package/dist/modules/customer_accounts/lib/customerEntityOwnership.js.map +2 -2
- package/dist/modules/customer_accounts/lib/customerUrl.js +19 -10
- package/dist/modules/customer_accounts/lib/customerUrl.js.map +2 -2
- package/dist/modules/customer_accounts/lib/invitationEmail.js +35 -0
- package/dist/modules/customer_accounts/lib/invitationEmail.js.map +7 -0
- package/dist/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.js +13 -0
- package/dist/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.js.map +7 -0
- package/dist/modules/customer_accounts/services/customerInvitationService.js +32 -2
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js +47 -7
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection-table.js +1 -1
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +4 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/route.js +7 -3
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +11 -1
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +14 -8
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +21 -6
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +48 -10
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/people.js +2 -0
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js +26 -6
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DealDetailTabs.js +30 -8
- package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailTabs.js +30 -8
- package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
- package/dist/modules/customers/data/entities.js +8 -0
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/data/validators.js +2 -1
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/migrations/Migration20260723210000_customers.js +15 -0
- package/dist/modules/customers/migrations/Migration20260723210000_customers.js.map +7 -0
- package/dist/modules/directory/api/tenants/route.js +8 -2
- package/dist/modules/directory/api/tenants/route.js.map +2 -2
- package/dist/modules/directory/commands/tenants.js +6 -0
- package/dist/modules/directory/commands/tenants.js.map +2 -2
- package/dist/modules/entities/api/entity-settings.js +59 -9
- package/dist/modules/entities/api/entity-settings.js.map +2 -2
- package/dist/modules/entities/backend/config/settings/page.js +10 -0
- package/dist/modules/entities/backend/config/settings/page.js.map +7 -0
- package/dist/modules/entities/backend/config/settings/page.meta.js +36 -0
- package/dist/modules/entities/backend/config/settings/page.meta.js.map +7 -0
- package/dist/modules/entities/backend/entities/user/create/page.js +16 -7
- package/dist/modules/entities/backend/entities/user/create/page.js.map +2 -2
- package/dist/modules/entities/components/EntitySettingsManager.js +136 -0
- package/dist/modules/entities/components/EntitySettingsManager.js.map +7 -0
- package/dist/modules/inbox_ops/api/webhook/inbound.js +14 -10
- package/dist/modules/inbox_ops/api/webhook/inbound.js.map +2 -2
- package/dist/modules/payment_gateways/api/sessions/route.js +1 -3
- package/dist/modules/payment_gateways/api/sessions/route.js.map +2 -2
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +11 -1
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/payment_gateways/data/entities.js +4 -0
- package/dist/modules/payment_gateways/data/entities.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +15 -6
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
- package/dist/modules/payment_gateways/lib/session-idempotency.js +33 -0
- package/dist/modules/payment_gateways/lib/session-idempotency.js.map +2 -2
- package/dist/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.js +18 -0
- package/dist/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.js.map +7 -0
- package/dist/modules/payment_gateways/setup.js +47 -0
- package/dist/modules/payment_gateways/setup.js.map +2 -2
- package/dist/modules/payment_gateways/workers/session-initialization-prune.js +50 -0
- package/dist/modules/payment_gateways/workers/session-initialization-prune.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js +134 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.js +11 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.js.map +7 -0
- package/dist/modules/portal/lib/navigation.js +7 -0
- package/dist/modules/portal/lib/navigation.js.map +7 -0
- package/dist/modules/query_index/lib/engine.js +43 -0
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +15 -5
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +11 -1
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +2 -2
- package/generated/entities/customer_deal_person_link/index.ts +1 -0
- package/generated/entities/customer_user_invitation/index.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +7 -7
- package/src/modules/auth/lib/backendChrome.tsx +15 -9
- package/src/modules/auth/lib/tenantAccess.ts +8 -0
- package/src/modules/business_rules/api/openmercato-call-options/route.ts +94 -0
- package/src/modules/business_rules/api/rules/route.ts +92 -4
- package/src/modules/business_rules/components/ActionBuilder.tsx +54 -5
- package/src/modules/business_rules/components/ActionRow.tsx +156 -18
- package/src/modules/business_rules/components/utils/actionValidation.ts +6 -0
- package/src/modules/business_rules/i18n/de.json +12 -0
- package/src/modules/business_rules/i18n/en.json +12 -0
- package/src/modules/business_rules/i18n/es.json +12 -0
- package/src/modules/business_rules/i18n/pl.json +12 -0
- package/src/modules/business_rules/lib/action-executor.ts +198 -0
- package/src/modules/business_rules/lib/openmercato-call-options-types.ts +31 -0
- package/src/modules/business_rules/lib/openmercato-call-options.ts +297 -0
- package/src/modules/business_rules/lib/rule-engine.ts +4 -0
- package/src/modules/communication_channels/api/post/webhook/[provider]/route.ts +11 -1
- package/src/modules/communication_channels/api/post/webhooks/gmail/route.ts +17 -11
- package/src/modules/configs/lib/upgrade-actions.ts +14 -0
- package/src/modules/customer_accounts/api/admin/users/[id].ts +16 -1
- package/src/modules/customer_accounts/api/admin/users-invite.ts +78 -3
- package/src/modules/customer_accounts/api/portal/users-invite.ts +22 -1
- package/src/modules/customer_accounts/data/entities.ts +3 -0
- package/src/modules/customer_accounts/data/validators.ts +1 -0
- package/src/modules/customer_accounts/emails/CustomerInvitationEmail.tsx +45 -0
- package/src/modules/customer_accounts/i18n/de.json +6 -0
- package/src/modules/customer_accounts/i18n/en.json +6 -0
- package/src/modules/customer_accounts/i18n/es.json +6 -0
- package/src/modules/customer_accounts/i18n/pl.json +6 -0
- package/src/modules/customer_accounts/lib/customerEntityOwnership.ts +68 -2
- package/src/modules/customer_accounts/lib/customerUrl.ts +27 -11
- package/src/modules/customer_accounts/lib/invitationEmail.ts +42 -0
- package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +16 -0
- package/src/modules/customer_accounts/migrations/Migration20260723120000_customer_accounts.ts +13 -0
- package/src/modules/customer_accounts/services/customerInvitationService.ts +56 -3
- package/src/modules/customer_accounts/subscribers/autoLinkCrm.ts +75 -8
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +2 -2
- package/src/modules/customer_accounts/widgets/injection-table.ts +4 -1
- package/src/modules/customers/api/deals/[id]/people/route.ts +3 -0
- package/src/modules/customers/api/deals/[id]/route.ts +10 -2
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +12 -1
- package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +1 -0
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +15 -9
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +24 -6
- package/src/modules/customers/commands/deals.ts +50 -9
- package/src/modules/customers/commands/people.ts +3 -0
- package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +30 -7
- package/src/modules/customers/components/detail/DealDetailTabs.tsx +34 -9
- package/src/modules/customers/components/detail/PersonDetailTabs.tsx +34 -9
- package/src/modules/customers/data/entities.ts +9 -1
- package/src/modules/customers/data/validators.ts +1 -0
- package/src/modules/customers/i18n/de.json +1 -0
- package/src/modules/customers/i18n/en.json +1 -0
- package/src/modules/customers/i18n/es.json +1 -0
- package/src/modules/customers/i18n/pl.json +1 -0
- package/src/modules/customers/migrations/.snapshot-open-mercato.json +27 -1
- package/src/modules/customers/migrations/Migration20260723210000_customers.ts +15 -0
- package/src/modules/directory/api/tenants/route.ts +9 -1
- package/src/modules/directory/commands/tenants.ts +6 -0
- package/src/modules/entities/api/entity-settings.ts +66 -22
- package/src/modules/entities/backend/config/settings/page.meta.ts +34 -0
- package/src/modules/entities/backend/config/settings/page.tsx +12 -0
- package/src/modules/entities/backend/entities/user/create/page.tsx +16 -7
- package/src/modules/entities/components/EntitySettingsManager.tsx +160 -0
- package/src/modules/entities/i18n/de.json +9 -0
- package/src/modules/entities/i18n/en.json +9 -0
- package/src/modules/entities/i18n/es.json +9 -0
- package/src/modules/entities/i18n/pl.json +9 -0
- package/src/modules/inbox_ops/api/webhook/inbound.ts +14 -12
- package/src/modules/payment_gateways/api/sessions/route.ts +1 -3
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +13 -1
- package/src/modules/payment_gateways/data/entities.ts +5 -0
- package/src/modules/payment_gateways/i18n/de.json +5 -1
- package/src/modules/payment_gateways/i18n/en.json +5 -1
- package/src/modules/payment_gateways/i18n/es.json +5 -1
- package/src/modules/payment_gateways/i18n/pl.json +5 -1
- package/src/modules/payment_gateways/lib/gateway-service.ts +17 -8
- package/src/modules/payment_gateways/lib/session-idempotency.ts +36 -0
- package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +10 -1
- package/src/modules/payment_gateways/migrations/Migration20260803103035_payment_gateways.ts +17 -0
- package/src/modules/payment_gateways/setup.ts +62 -0
- package/src/modules/payment_gateways/workers/session-initialization-prune.ts +63 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.meta.ts +9 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.tsx +164 -0
- package/src/modules/portal/i18n/de.json +18 -0
- package/src/modules/portal/i18n/en.json +18 -0
- package/src/modules/portal/i18n/es.json +18 -0
- package/src/modules/portal/i18n/pl.json +18 -0
- package/src/modules/portal/lib/navigation.ts +3 -0
- package/src/modules/query_index/lib/engine.ts +52 -0
- package/src/modules/query_index/lib/search-tokens.ts +16 -4
- package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +11 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useMemo, useState, useEffect } from "react";
|
|
4
|
+
import { useSearchParams } from "next/navigation";
|
|
5
|
+
import Link from "next/link";
|
|
6
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
|
+
import { PasswordInput } from "@open-mercato/ui/primitives/password-input";
|
|
8
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
9
|
+
import { Label } from "@open-mercato/ui/primitives/label";
|
|
10
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
11
|
+
import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
|
|
12
|
+
import { EmptyState } from "@open-mercato/ui/primitives/empty-state";
|
|
13
|
+
import { SearchX } from "lucide-react";
|
|
14
|
+
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
15
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
16
|
+
import { usePortalContext } from "@open-mercato/ui/portal/PortalContext";
|
|
17
|
+
import { InjectionSpot } from "@open-mercato/ui/backend/injection/InjectionSpot";
|
|
18
|
+
import { PortalInjectionSpots } from "@open-mercato/ui/backend/injection/spotIds";
|
|
19
|
+
import { navigateWithPageReload } from "@open-mercato/core/modules/portal/lib/navigation";
|
|
20
|
+
function PortalInvitePage({ params }) {
|
|
21
|
+
const t = useT();
|
|
22
|
+
const orgSlug = params.orgSlug;
|
|
23
|
+
const { tenant } = usePortalContext();
|
|
24
|
+
const searchParams = useSearchParams();
|
|
25
|
+
const [displayName, setDisplayName] = useState("");
|
|
26
|
+
const [password, setPassword] = useState("");
|
|
27
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
28
|
+
const [error, setError] = useState(null);
|
|
29
|
+
const [submitting, setSubmitting] = useState(false);
|
|
30
|
+
const [token, setToken] = useState(null);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const tokenParam = searchParams.get("token");
|
|
33
|
+
if (!tokenParam) {
|
|
34
|
+
setError(t("portal.invite.error.noToken", "Invalid or missing invitation token."));
|
|
35
|
+
} else {
|
|
36
|
+
setToken(tokenParam);
|
|
37
|
+
}
|
|
38
|
+
}, [searchParams, t]);
|
|
39
|
+
const handleSubmit = useCallback(
|
|
40
|
+
async (event) => {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
setError(null);
|
|
43
|
+
if (!token) {
|
|
44
|
+
setError(t("portal.invite.error.noToken", "Invalid or missing invitation token."));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!displayName.trim()) {
|
|
48
|
+
setError(t("portal.invite.error.displayNameRequired", "Display name is required."));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (password !== confirmPassword) {
|
|
52
|
+
setError(t("portal.invite.error.passwordMismatch", "Passwords do not match."));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (password.length < 8) {
|
|
56
|
+
setError(t("portal.invite.error.passwordTooShort", "Password must be at least 8 characters long."));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
setSubmitting(true);
|
|
60
|
+
try {
|
|
61
|
+
const result = await apiCall("/api/customer_accounts/invitations/accept", {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: { "Content-Type": "application/json" },
|
|
64
|
+
body: JSON.stringify({ token, password, displayName: displayName.trim() })
|
|
65
|
+
});
|
|
66
|
+
if (result.ok && result.result?.ok) {
|
|
67
|
+
navigateWithPageReload(`/${orgSlug}/portal/dashboard`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (result.status === 400) {
|
|
71
|
+
setError(t("portal.invite.error.invalidToken", "Invalid or expired invitation."));
|
|
72
|
+
} else {
|
|
73
|
+
setError(result.result?.error || t("portal.invite.error.generic", "Invitation acceptance failed. Please try again."));
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
setError(t("portal.invite.error.generic", "Invitation acceptance failed. Please try again."));
|
|
77
|
+
} finally {
|
|
78
|
+
setSubmitting(false);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
[token, password, confirmPassword, displayName, orgSlug, t]
|
|
82
|
+
);
|
|
83
|
+
const injectionContext = useMemo(
|
|
84
|
+
() => ({ orgSlug }),
|
|
85
|
+
[orgSlug]
|
|
86
|
+
);
|
|
87
|
+
if (tenant.loading) {
|
|
88
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx(Spinner, {}) });
|
|
89
|
+
}
|
|
90
|
+
if (tenant.error) {
|
|
91
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-md py-12", children: /* @__PURE__ */ jsx(
|
|
92
|
+
EmptyState,
|
|
93
|
+
{
|
|
94
|
+
variant: "subtle",
|
|
95
|
+
size: "lg",
|
|
96
|
+
icon: /* @__PURE__ */ jsx(SearchX, { className: "h-6 w-6", "aria-hidden": true }),
|
|
97
|
+
title: t("portal.org.invalid", "Organization not found.")
|
|
98
|
+
}
|
|
99
|
+
) });
|
|
100
|
+
}
|
|
101
|
+
return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-sm", children: [
|
|
102
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-8 text-center", children: [
|
|
103
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: t("portal.invite.title", "Accept Invitation") }),
|
|
104
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground", children: t("portal.invite.description", "Create your portal account to accept this invitation.") })
|
|
105
|
+
] }),
|
|
106
|
+
/* @__PURE__ */ jsx(InjectionSpot, { spotId: PortalInjectionSpots.pageBefore("invite"), context: injectionContext }),
|
|
107
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [
|
|
108
|
+
error ? /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }) : null,
|
|
109
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
110
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "invite-display-name", className: "text-overline font-semibold uppercase tracking-wider text-muted-foreground/70", children: t("portal.invite.displayName", "Display Name") }),
|
|
111
|
+
/* @__PURE__ */ jsx(Input, { id: "invite-display-name", autoComplete: "name", required: true, value: displayName, onChange: (e) => setDisplayName(e.target.value), disabled: submitting || !token, className: "rounded-lg" })
|
|
112
|
+
] }),
|
|
113
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
114
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "invite-password", className: "text-overline font-semibold uppercase tracking-wider text-muted-foreground/70", children: t("portal.invite.password", "Password") }),
|
|
115
|
+
/* @__PURE__ */ jsx(PasswordInput, { id: "invite-password", autoComplete: "new-password", required: true, placeholder: t("portal.invite.password.placeholder", "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"), value: password, onChange: (e) => setPassword(e.target.value), disabled: submitting || !token, className: "rounded-lg" })
|
|
116
|
+
] }),
|
|
117
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
118
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "invite-confirm-password", className: "text-overline font-semibold uppercase tracking-wider text-muted-foreground/70", children: t("portal.invite.confirmPassword", "Confirm Password") }),
|
|
119
|
+
/* @__PURE__ */ jsx(PasswordInput, { id: "invite-confirm-password", autoComplete: "new-password", required: true, placeholder: t("portal.invite.confirmPassword.placeholder", "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"), value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), disabled: submitting || !token, className: "rounded-lg" })
|
|
120
|
+
] }),
|
|
121
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", disabled: submitting || !token, className: "mt-1 w-full rounded-lg", children: submitting ? t("portal.invite.submitting", "Accepting invitation...") : t("portal.invite.submit", "Accept Invitation") }),
|
|
122
|
+
/* @__PURE__ */ jsxs("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
123
|
+
t("portal.invite.backToLogin", "Already have an account?"),
|
|
124
|
+
" ",
|
|
125
|
+
/* @__PURE__ */ jsx(Link, { href: `/${orgSlug}/portal/login`, className: "font-medium text-foreground underline underline-offset-4 hover:opacity-80", children: t("portal.invite.loginLink", "Sign in") })
|
|
126
|
+
] })
|
|
127
|
+
] }),
|
|
128
|
+
/* @__PURE__ */ jsx(InjectionSpot, { spotId: PortalInjectionSpots.pageAfter("invite"), context: injectionContext })
|
|
129
|
+
] });
|
|
130
|
+
}
|
|
131
|
+
export {
|
|
132
|
+
PortalInvitePage as default
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/invite/page.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport { useCallback, useMemo, useState, useEffect } from 'react'\nimport { useSearchParams } from 'next/navigation'\nimport Link from 'next/link'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { PasswordInput } from '@open-mercato/ui/primitives/password-input'\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 { EmptyState } from '@open-mercato/ui/primitives/empty-state'\nimport { SearchX } from 'lucide-react'\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'\nimport { navigateWithPageReload } from '@open-mercato/core/modules/portal/lib/navigation'\n\ntype Props = { params: { orgSlug: string } }\n\nexport default function PortalInvitePage({ params }: Props) {\n const t = useT()\n const orgSlug = params.orgSlug\n const { tenant } = usePortalContext()\n const searchParams = useSearchParams()\n\n const [displayName, setDisplayName] = useState('')\n const [password, setPassword] = useState('')\n const [confirmPassword, setConfirmPassword] = useState('')\n const [error, setError] = useState<string | null>(null)\n const [submitting, setSubmitting] = useState(false)\n const [token, setToken] = useState<string | null>(null)\n\n useEffect(() => {\n const tokenParam = searchParams.get('token')\n if (!tokenParam) {\n setError(t('portal.invite.error.noToken', 'Invalid or missing invitation token.'))\n } else {\n setToken(tokenParam)\n }\n }, [searchParams, t])\n\n const handleSubmit = useCallback(\n async (event: React.FormEvent) => {\n event.preventDefault()\n setError(null)\n\n if (!token) {\n setError(t('portal.invite.error.noToken', 'Invalid or missing invitation token.'))\n return\n }\n\n if (!displayName.trim()) {\n setError(t('portal.invite.error.displayNameRequired', 'Display name is required.'))\n return\n }\n\n if (password !== confirmPassword) {\n setError(t('portal.invite.error.passwordMismatch', 'Passwords do not match.'))\n return\n }\n\n if (password.length < 8) {\n setError(t('portal.invite.error.passwordTooShort', 'Password must be at least 8 characters long.'))\n return\n }\n\n setSubmitting(true)\n try {\n const result = await apiCall<{ ok: boolean; error?: string }>('/api/customer_accounts/invitations/accept', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token, password, displayName: displayName.trim() }),\n })\n\n if (result.ok && result.result?.ok) {\n navigateWithPageReload(`/${orgSlug}/portal/dashboard`)\n return\n }\n\n if (result.status === 400) {\n setError(t('portal.invite.error.invalidToken', 'Invalid or expired invitation.'))\n } else {\n setError(result.result?.error || t('portal.invite.error.generic', 'Invitation acceptance failed. Please try again.'))\n }\n } catch {\n setError(t('portal.invite.error.generic', 'Invitation acceptance failed. Please try again.'))\n } finally {\n setSubmitting(false)\n }\n },\n [token, password, confirmPassword, displayName, 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 <EmptyState\n variant=\"subtle\"\n size=\"lg\"\n icon={<SearchX className=\"h-6 w-6\" aria-hidden />}\n title={t('portal.org.invalid', 'Organization not found.')}\n />\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.invite.title', 'Accept Invitation')}</h1>\n <p className=\"mt-1.5 text-sm text-muted-foreground\">{t('portal.invite.description', 'Create your portal account to accept this invitation.')}</p>\n </div>\n\n <InjectionSpot spotId={PortalInjectionSpots.pageBefore('invite')} 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=\"invite-display-name\" className=\"text-overline font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.invite.displayName', 'Display Name')}</Label>\n <Input id=\"invite-display-name\" autoComplete=\"name\" required value={displayName} onChange={(e) => setDisplayName(e.target.value)} disabled={submitting || !token} className=\"rounded-lg\" />\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"invite-password\" className=\"text-overline font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.invite.password', 'Password')}</Label>\n <PasswordInput id=\"invite-password\" autoComplete=\"new-password\" required placeholder={t('portal.invite.password.placeholder', '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022')} value={password} onChange={(e) => setPassword(e.target.value)} disabled={submitting || !token} className=\"rounded-lg\" />\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <Label htmlFor=\"invite-confirm-password\" className=\"text-overline font-semibold uppercase tracking-wider text-muted-foreground/70\">{t('portal.invite.confirmPassword', 'Confirm Password')}</Label>\n <PasswordInput id=\"invite-confirm-password\" autoComplete=\"new-password\" required placeholder={t('portal.invite.confirmPassword.placeholder', '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022')} value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} disabled={submitting || !token} className=\"rounded-lg\" />\n </div>\n\n <Button type=\"submit\" disabled={submitting || !token} className=\"mt-1 w-full rounded-lg\">\n {submitting ? t('portal.invite.submitting', 'Accepting invitation...') : t('portal.invite.submit', 'Accept Invitation')}\n </Button>\n\n <p className=\"text-center text-sm text-muted-foreground\">\n {t('portal.invite.backToLogin', '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.invite.loginLink', 'Sign in')}\n </Link>\n </p>\n </form>\n\n <InjectionSpot spotId={PortalInjectionSpots.pageAfter('invite')} context={injectionContext} />\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/invite/page.meta.ts"],
|
|
4
|
+
"sourcesContent": ["import type { PageMetadata } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: PageMetadata = {\n titleKey: 'portal.nav.invite',\n title: 'Accept Invitation',\n navHidden: true,\n}\n\nexport default metadata\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,WAAyB;AAAA,EACpC,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AACb;AAEA,IAAO,oBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/portal/lib/navigation.ts"],
|
|
4
|
+
"sourcesContent": ["export function navigateWithPageReload(path: string): void {\n window.location.assign(path)\n}\n"],
|
|
5
|
+
"mappings": "AAAO,SAAS,uBAAuB,MAAoB;AACzD,SAAO,SAAS,OAAO,IAAI;AAC7B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -24,8 +24,36 @@ import { warnOnCiphertextLikeFallback } from "@open-mercato/shared/lib/query/cip
|
|
|
24
24
|
import { resolveEncryptedSortFields, resolveEncryptedSortMaxRows, sortRowsInMemory } from "@open-mercato/shared/lib/query/encrypted-sort";
|
|
25
25
|
import { mapWithConcurrency } from "@open-mercato/shared/lib/query/bounded-decrypt";
|
|
26
26
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
27
|
+
import { parseNumberWithDefault } from "@open-mercato/shared/lib/number";
|
|
27
28
|
const logger = createLogger("query_index").child({ component: "engine" });
|
|
28
29
|
const DECRYPT_CONCURRENCY = 8;
|
|
30
|
+
const AUTO_REINDEX_DEBOUNCE_DEFAULT_MS = 3e4;
|
|
31
|
+
const AUTO_REINDEX_DEBOUNCE_MAX_SCOPES = 1e4;
|
|
32
|
+
const AUTO_REINDEX_SCHEDULED_AT_KEY = /* @__PURE__ */ Symbol.for("@open-mercato/query-index/auto-reindex-scheduled-at");
|
|
33
|
+
function getAutoReindexScheduledAt() {
|
|
34
|
+
const globalScope = globalThis;
|
|
35
|
+
if (!globalScope[AUTO_REINDEX_SCHEDULED_AT_KEY]) {
|
|
36
|
+
globalScope[AUTO_REINDEX_SCHEDULED_AT_KEY] = /* @__PURE__ */ new Map();
|
|
37
|
+
}
|
|
38
|
+
return globalScope[AUTO_REINDEX_SCHEDULED_AT_KEY];
|
|
39
|
+
}
|
|
40
|
+
function markAutoReindexScheduled(key, debounceMs, now) {
|
|
41
|
+
const autoReindexScheduledAt = getAutoReindexScheduledAt();
|
|
42
|
+
const previous = autoReindexScheduledAt.get(key);
|
|
43
|
+
if (previous !== void 0 && now - previous < debounceMs) return false;
|
|
44
|
+
if (autoReindexScheduledAt.size >= AUTO_REINDEX_DEBOUNCE_MAX_SCOPES) {
|
|
45
|
+
for (const [scopeKey, scheduledAt] of autoReindexScheduledAt) {
|
|
46
|
+
if (now - scheduledAt >= debounceMs) autoReindexScheduledAt.delete(scopeKey);
|
|
47
|
+
}
|
|
48
|
+
if (autoReindexScheduledAt.size >= AUTO_REINDEX_DEBOUNCE_MAX_SCOPES) {
|
|
49
|
+
const oldestKey = autoReindexScheduledAt.keys().next().value;
|
|
50
|
+
if (oldestKey !== void 0) autoReindexScheduledAt.delete(oldestKey);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
autoReindexScheduledAt.delete(key);
|
|
54
|
+
autoReindexScheduledAt.set(key, now);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
29
57
|
function buildFilterableCustomFieldJoins(sources) {
|
|
30
58
|
if (!sources || sources.length === 0) return [];
|
|
31
59
|
return sources.flatMap((source, index) => {
|
|
@@ -88,6 +116,7 @@ class HybridQueryEngine {
|
|
|
88
116
|
this.sqlDebugEnabled = null;
|
|
89
117
|
this.forcePartialIndexEnabled = null;
|
|
90
118
|
this.autoReindexEnabled = null;
|
|
119
|
+
this.autoReindexDebounceMs = null;
|
|
91
120
|
this.coverageOptimizationEnabled = null;
|
|
92
121
|
this.pendingCoverageRefreshKeys = /* @__PURE__ */ new Set();
|
|
93
122
|
this.searchAvailabilityInstance = null;
|
|
@@ -1642,6 +1671,11 @@ class HybridQueryEngine {
|
|
|
1642
1671
|
organizationId: organizationIdOverride ?? opts.organizationId ?? null,
|
|
1643
1672
|
force: false
|
|
1644
1673
|
};
|
|
1674
|
+
const debounceMs = this.getAutoReindexDebounceMs();
|
|
1675
|
+
if (debounceMs > 0) {
|
|
1676
|
+
const key = [payload.entityType, payload.tenantId ?? "__tenant__", payload.organizationId ?? "__org__"].join("|");
|
|
1677
|
+
if (!markAutoReindexScheduled(key, debounceMs, Date.now())) return;
|
|
1678
|
+
}
|
|
1645
1679
|
const context = stats ? { entity, tenantId: payload.tenantId, organizationId: payload.organizationId, baseCount: stats.baseCount, indexedCount: stats.indexedCount } : { entity, tenantId: payload.tenantId, organizationId: payload.organizationId };
|
|
1646
1680
|
void Promise.resolve().then(async () => {
|
|
1647
1681
|
try {
|
|
@@ -1710,6 +1744,15 @@ class HybridQueryEngine {
|
|
|
1710
1744
|
this.autoReindexEnabled = parsed === null ? true : parsed;
|
|
1711
1745
|
return this.autoReindexEnabled;
|
|
1712
1746
|
}
|
|
1747
|
+
getAutoReindexDebounceMs() {
|
|
1748
|
+
if (this.autoReindexDebounceMs != null) return this.autoReindexDebounceMs;
|
|
1749
|
+
this.autoReindexDebounceMs = parseNumberWithDefault(
|
|
1750
|
+
process.env.OM_QUERY_INDEX_AUTO_REINDEX_DEBOUNCE_MS,
|
|
1751
|
+
AUTO_REINDEX_DEBOUNCE_DEFAULT_MS,
|
|
1752
|
+
{ integer: true, min: 0 }
|
|
1753
|
+
);
|
|
1754
|
+
return this.autoReindexDebounceMs;
|
|
1755
|
+
}
|
|
1713
1756
|
isCoverageOptimizationEnabled() {
|
|
1714
1757
|
if (this.coverageOptimizationEnabled != null) return this.coverageOptimizationEnabled;
|
|
1715
1758
|
const raw = (process.env.OPTIMIZE_INDEX_COVERAGE_STATS ?? "").trim().toLowerCase();
|