@payloadcms/plugin-multi-tenant 3.59.0 → 3.59.1
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAI3C,OAAO,KAAwB,MAAM,OAAO,CAAA;AAI5C,KAAK,WAAW,GAAG;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB;;OAEG;IACH,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC7C;;OAEG;IACH,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAA;IACtF;;OAEG;IACH,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;IAC1D;;;;;OAKG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IACjF;;OAEG;IACH,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC;;OAEG;IACH,aAAa,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE,CAAA;
|
|
1
|
+
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAI3C,OAAO,KAAwB,MAAM,OAAO,CAAA;AAI5C,KAAK,WAAW,GAAG;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB;;OAEG;IACH,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC7C;;OAEG;IACH,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAA;IACtF;;OAEG;IACH,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;IAC1D;;;;;OAKG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IACjF;;OAEG;IACH,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC;;OAEG;IACH,aAAa,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE,CAAA;AA+CD,eAAO,MAAM,6BAA6B,6EAKvC;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,oBAAoB,EAAE,YAAY,EAAE,CAAA;IACpC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,qBAAqB,EAAE,MAAM,CAAA;CAC9B,sBAqKA,CAAA;AAED,eAAO,MAAM,kBAAkB,mBAA2B,CAAA"}
|
|
@@ -14,24 +14,36 @@ const Context = /*#__PURE__*/ createContext({
|
|
|
14
14
|
syncTenants: ()=>Promise.resolve(),
|
|
15
15
|
updateTenants: ()=>null
|
|
16
16
|
});
|
|
17
|
-
const
|
|
17
|
+
const DEFAULT_COOKIE_NAME = 'payload-tenant';
|
|
18
|
+
const setTenantCookie = (args)=>{
|
|
19
|
+
const { cookieName = DEFAULT_COOKIE_NAME, value } = args;
|
|
18
20
|
document.cookie = generateCookie({
|
|
19
|
-
name:
|
|
21
|
+
name: cookieName,
|
|
20
22
|
maxAge: 60 * 60 * 24 * 365,
|
|
21
23
|
path: '/',
|
|
22
24
|
returnCookieAsObject: false,
|
|
23
25
|
value: value || ''
|
|
24
26
|
});
|
|
25
27
|
};
|
|
26
|
-
const
|
|
28
|
+
const deleteTenantCookie = (args = {})=>{
|
|
29
|
+
const { cookieName = DEFAULT_COOKIE_NAME } = args;
|
|
27
30
|
document.cookie = generateCookie({
|
|
28
|
-
name:
|
|
31
|
+
name: cookieName,
|
|
29
32
|
maxAge: -1,
|
|
30
33
|
path: '/',
|
|
31
34
|
returnCookieAsObject: false,
|
|
32
35
|
value: ''
|
|
33
36
|
});
|
|
34
37
|
};
|
|
38
|
+
const getTenantCookie = (args = {})=>{
|
|
39
|
+
const { cookieName = DEFAULT_COOKIE_NAME } = args;
|
|
40
|
+
const value = `; ${document.cookie}`;
|
|
41
|
+
const parts = value.split(`; ${cookieName}=`);
|
|
42
|
+
if (parts.length === 2) {
|
|
43
|
+
return parts.pop()?.split(';').shift();
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
};
|
|
35
47
|
export const TenantSelectionProviderClient = ({ children, initialTenantOptions, initialValue, tenantsCollectionSlug })=>{
|
|
36
48
|
const [selectedTenantID, setSelectedTenantID] = React.useState(initialValue);
|
|
37
49
|
const [modified, setModified] = React.useState(false);
|
|
@@ -52,9 +64,11 @@ export const TenantSelectionProviderClient = ({ children, initialTenantOptions,
|
|
|
52
64
|
const setTenantAndCookie = React.useCallback(({ id, refresh })=>{
|
|
53
65
|
setSelectedTenantID(id);
|
|
54
66
|
if (id !== undefined) {
|
|
55
|
-
|
|
67
|
+
setTenantCookie({
|
|
68
|
+
value: String(id)
|
|
69
|
+
});
|
|
56
70
|
} else {
|
|
57
|
-
|
|
71
|
+
deleteTenantCookie();
|
|
58
72
|
}
|
|
59
73
|
if (refresh) {
|
|
60
74
|
router.refresh();
|
|
@@ -105,7 +119,9 @@ export const TenantSelectionProviderClient = ({ children, initialTenantOptions,
|
|
|
105
119
|
setTenantOptions(result.tenantOptions);
|
|
106
120
|
if (result.tenantOptions.length === 1) {
|
|
107
121
|
setSelectedTenantID(result.tenantOptions[0].value);
|
|
108
|
-
|
|
122
|
+
setTenantCookie({
|
|
123
|
+
value: String(result.tenantOptions[0].value)
|
|
124
|
+
});
|
|
109
125
|
}
|
|
110
126
|
}
|
|
111
127
|
} catch (e) {
|
|
@@ -134,14 +150,14 @@ export const TenantSelectionProviderClient = ({ children, initialTenantOptions,
|
|
|
134
150
|
syncTenants
|
|
135
151
|
]);
|
|
136
152
|
React.useEffect(()=>{
|
|
137
|
-
if (userChanged) {
|
|
153
|
+
if (userChanged || initialValue && String(initialValue) !== getTenantCookie()) {
|
|
138
154
|
if (userID) {
|
|
139
155
|
// user logging in
|
|
140
156
|
void syncTenants();
|
|
141
157
|
} else {
|
|
142
158
|
// user logging out
|
|
143
159
|
setSelectedTenantID(undefined);
|
|
144
|
-
|
|
160
|
+
deleteTenantCookie();
|
|
145
161
|
if (tenantOptions.length > 0) {
|
|
146
162
|
setTenantOptions([]);
|
|
147
163
|
}
|
|
@@ -152,7 +168,8 @@ export const TenantSelectionProviderClient = ({ children, initialTenantOptions,
|
|
|
152
168
|
userID,
|
|
153
169
|
userChanged,
|
|
154
170
|
syncTenants,
|
|
155
|
-
tenantOptions
|
|
171
|
+
tenantOptions,
|
|
172
|
+
initialValue
|
|
156
173
|
]);
|
|
157
174
|
/**
|
|
158
175
|
* If there is no initial value, clear the tenant and refresh the router.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"sourcesContent":["'use client'\n\nimport type { OptionObject } from 'payload'\n\nimport { toast, useAuth, useConfig } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport React, { createContext } from 'react'\n\nimport { generateCookie } from '../../utilities/generateCookie.js'\n\ntype ContextType = {\n /**\n * What is the context of the selector? It is either 'document' | 'global' | undefined.\n *\n * - 'document' means you are viewing a document in the context of a tenant\n * - 'global' means you are viewing a \"global\" (globals are collection documents but prevent you from viewing the list view) document in the context of a tenant\n * - undefined means you are not viewing a document at all\n */\n entityType?: 'document' | 'global'\n /**\n * Hoists the forms modified state\n */\n modified?: boolean\n /**\n * Array of options to select from\n */\n options: OptionObject[]\n /**\n * The currently selected tenant ID\n */\n selectedTenantID: number | string | undefined\n /**\n * Sets the entityType when a document is loaded and sets it to undefined when the document unmounts.\n */\n setEntityType: React.Dispatch<React.SetStateAction<'document' | 'global' | undefined>>\n /**\n * Sets the modified state\n */\n setModified: React.Dispatch<React.SetStateAction<boolean>>\n /**\n * Sets the selected tenant ID\n *\n * @param args.id - The ID of the tenant to select\n * @param args.refresh - Whether to refresh the page after changing the tenant\n */\n setTenant: (args: { id: number | string | undefined; refresh?: boolean }) => void\n /**\n * Used to sync tenants displayed in the tenant selector when updates are made to the tenants collection.\n */\n syncTenants: () => Promise<void>\n /**\n *\n */\n updateTenants: (args: { id: number | string; label: string }) => void\n}\n\nconst Context = createContext<ContextType>({\n entityType: undefined,\n options: [],\n selectedTenantID: undefined,\n setEntityType: () => undefined,\n setModified: () => undefined,\n setTenant: () => null,\n syncTenants: () => Promise.resolve(),\n updateTenants: () => null,\n})\n\nconst setCookie = (value?: string) => {\n document.cookie = generateCookie<string>({\n name: 'payload-tenant',\n maxAge: 60 * 60 * 24 * 365, // 1 year in seconds\n path: '/',\n returnCookieAsObject: false,\n value: value || '',\n })\n}\n\nconst deleteCookie = () => {\n document.cookie = generateCookie<string>({\n name: 'payload-tenant',\n maxAge: -1,\n path: '/',\n returnCookieAsObject: false,\n value: '',\n })\n}\n\nexport const TenantSelectionProviderClient = ({\n children,\n initialTenantOptions,\n initialValue,\n tenantsCollectionSlug,\n}: {\n children: React.ReactNode\n initialTenantOptions: OptionObject[]\n initialValue?: number | string\n tenantsCollectionSlug: string\n}) => {\n const [selectedTenantID, setSelectedTenantID] = React.useState<number | string | undefined>(\n initialValue,\n )\n const [modified, setModified] = React.useState<boolean>(false)\n const [entityType, setEntityType] = React.useState<'document' | 'global' | undefined>(undefined)\n const { user } = useAuth()\n const { config } = useConfig()\n const router = useRouter()\n const userID = React.useMemo(() => user?.id, [user?.id])\n const prevUserID = React.useRef(userID)\n const userChanged = userID !== prevUserID.current\n const [tenantOptions, setTenantOptions] = React.useState<OptionObject[]>(\n () => initialTenantOptions,\n )\n const selectedTenantLabel = React.useMemo(\n () => tenantOptions.find((option) => option.value === selectedTenantID)?.label,\n [selectedTenantID, tenantOptions],\n )\n\n const setTenantAndCookie = React.useCallback(\n ({ id, refresh }: { id: number | string | undefined; refresh?: boolean }) => {\n setSelectedTenantID(id)\n if (id !== undefined) {\n setCookie(String(id))\n } else {\n deleteCookie()\n }\n if (refresh) {\n router.refresh()\n }\n },\n [router],\n )\n\n const setTenant = React.useCallback<ContextType['setTenant']>(\n ({ id, refresh }) => {\n if (id === undefined) {\n if (tenantOptions.length > 1 || tenantOptions.length === 0) {\n // users with multiple tenants can clear the tenant selection\n setTenantAndCookie({ id: undefined, refresh })\n } else if (tenantOptions[0]) {\n // if there is only one tenant, auto-select that tenant\n setTenantAndCookie({ id: tenantOptions[0].value, refresh: true })\n }\n } else if (!tenantOptions.find((option) => option.value === id)) {\n // if the tenant is invalid, set the first tenant as selected\n setTenantAndCookie({\n id: tenantOptions[0]?.value,\n refresh,\n })\n } else {\n // if the tenant is in the options, set it as selected\n setTenantAndCookie({ id, refresh })\n }\n },\n [tenantOptions, setTenantAndCookie],\n )\n\n const syncTenants = React.useCallback(async () => {\n try {\n const req = await fetch(\n `${config.serverURL}${config.routes.api}/${tenantsCollectionSlug}/populate-tenant-options`,\n {\n credentials: 'include',\n method: 'GET',\n },\n )\n\n const result = await req.json()\n\n if (result.tenantOptions && userID) {\n setTenantOptions(result.tenantOptions)\n\n if (result.tenantOptions.length === 1) {\n setSelectedTenantID(result.tenantOptions[0].value)\n setCookie(String(result.tenantOptions[0].value))\n }\n }\n } catch (e) {\n toast.error(`Error fetching tenants`)\n }\n }, [config.serverURL, config.routes.api, tenantsCollectionSlug, userID])\n\n const updateTenants = React.useCallback<ContextType['updateTenants']>(\n ({ id, label }) => {\n setTenantOptions((prev) => {\n return prev.map((currentTenant) => {\n if (id === currentTenant.value) {\n return {\n label,\n value: id,\n }\n }\n return currentTenant\n })\n })\n\n void syncTenants()\n },\n [syncTenants],\n )\n\n React.useEffect(() => {\n if (userChanged) {\n if (userID) {\n // user logging in\n void syncTenants()\n } else {\n // user logging out\n setSelectedTenantID(undefined)\n deleteCookie()\n if (tenantOptions.length > 0) {\n setTenantOptions([])\n }\n }\n prevUserID.current = userID\n }\n }, [userID, userChanged, syncTenants, tenantOptions])\n\n /**\n * If there is no initial value, clear the tenant and refresh the router.\n * Needed for stale tenantIDs set as a cookie.\n */\n React.useEffect(() => {\n if (!initialValue) {\n setTenant({ id: undefined, refresh: true })\n }\n }, [initialValue, setTenant])\n\n /**\n * If there is no selected tenant ID and the entity type is 'global', set the first tenant as selected.\n * This ensures that the global tenant is always set when the component mounts.\n */\n React.useEffect(() => {\n if (!selectedTenantID && tenantOptions.length > 0 && entityType === 'global') {\n setTenant({\n id: tenantOptions[0]?.value,\n refresh: true,\n })\n }\n }, [selectedTenantID, tenantOptions, entityType, setTenant])\n\n return (\n <span\n data-selected-tenant-id={selectedTenantID}\n data-selected-tenant-title={selectedTenantLabel}\n >\n <Context\n value={{\n entityType,\n modified,\n options: tenantOptions,\n selectedTenantID,\n setEntityType,\n setModified,\n setTenant,\n syncTenants,\n updateTenants,\n }}\n >\n {children}\n </Context>\n </span>\n )\n}\n\nexport const useTenantSelection = () => React.use(Context)\n"],"names":["toast","useAuth","useConfig","useRouter","React","createContext","generateCookie","Context","entityType","undefined","options","selectedTenantID","setEntityType","setModified","setTenant","syncTenants","Promise","resolve","updateTenants","setCookie","value","document","cookie","name","maxAge","path","returnCookieAsObject","deleteCookie","TenantSelectionProviderClient","children","initialTenantOptions","initialValue","tenantsCollectionSlug","setSelectedTenantID","useState","modified","user","config","router","userID","useMemo","id","prevUserID","useRef","userChanged","current","tenantOptions","setTenantOptions","selectedTenantLabel","find","option","label","setTenantAndCookie","useCallback","refresh","String","length","req","fetch","serverURL","routes","api","credentials","method","result","json","e","error","prev","map","currentTenant","useEffect","span","data-selected-tenant-id","data-selected-tenant-title","useTenantSelection","use"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"sourcesContent":["'use client'\n\nimport type { OptionObject } from 'payload'\n\nimport { toast, useAuth, useConfig } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport React, { createContext } from 'react'\n\nimport { generateCookie } from '../../utilities/generateCookie.js'\n\ntype ContextType = {\n /**\n * What is the context of the selector? It is either 'document' | 'global' | undefined.\n *\n * - 'document' means you are viewing a document in the context of a tenant\n * - 'global' means you are viewing a \"global\" (globals are collection documents but prevent you from viewing the list view) document in the context of a tenant\n * - undefined means you are not viewing a document at all\n */\n entityType?: 'document' | 'global'\n /**\n * Hoists the forms modified state\n */\n modified?: boolean\n /**\n * Array of options to select from\n */\n options: OptionObject[]\n /**\n * The currently selected tenant ID\n */\n selectedTenantID: number | string | undefined\n /**\n * Sets the entityType when a document is loaded and sets it to undefined when the document unmounts.\n */\n setEntityType: React.Dispatch<React.SetStateAction<'document' | 'global' | undefined>>\n /**\n * Sets the modified state\n */\n setModified: React.Dispatch<React.SetStateAction<boolean>>\n /**\n * Sets the selected tenant ID\n *\n * @param args.id - The ID of the tenant to select\n * @param args.refresh - Whether to refresh the page after changing the tenant\n */\n setTenant: (args: { id: number | string | undefined; refresh?: boolean }) => void\n /**\n * Used to sync tenants displayed in the tenant selector when updates are made to the tenants collection.\n */\n syncTenants: () => Promise<void>\n /**\n *\n */\n updateTenants: (args: { id: number | string; label: string }) => void\n}\n\nconst Context = createContext<ContextType>({\n entityType: undefined,\n options: [],\n selectedTenantID: undefined,\n setEntityType: () => undefined,\n setModified: () => undefined,\n setTenant: () => null,\n syncTenants: () => Promise.resolve(),\n updateTenants: () => null,\n})\n\nconst DEFAULT_COOKIE_NAME = 'payload-tenant'\n\nconst setTenantCookie = (args: { cookieName?: string; value: string }) => {\n const { cookieName = DEFAULT_COOKIE_NAME, value } = args\n document.cookie = generateCookie<string>({\n name: cookieName,\n maxAge: 60 * 60 * 24 * 365, // 1 year in seconds\n path: '/',\n returnCookieAsObject: false,\n value: value || '',\n })\n}\n\nconst deleteTenantCookie = (args: { cookieName?: string } = {}) => {\n const { cookieName = DEFAULT_COOKIE_NAME } = args\n document.cookie = generateCookie<string>({\n name: cookieName,\n maxAge: -1,\n path: '/',\n returnCookieAsObject: false,\n value: '',\n })\n}\n\nconst getTenantCookie = (args: { cookieName?: string } = {}): string | undefined => {\n const { cookieName = DEFAULT_COOKIE_NAME } = args\n const value = `; ${document.cookie}`\n const parts = value.split(`; ${cookieName}=`)\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift()\n }\n return undefined\n}\n\nexport const TenantSelectionProviderClient = ({\n children,\n initialTenantOptions,\n initialValue,\n tenantsCollectionSlug,\n}: {\n children: React.ReactNode\n initialTenantOptions: OptionObject[]\n initialValue?: number | string\n tenantsCollectionSlug: string\n}) => {\n const [selectedTenantID, setSelectedTenantID] = React.useState<number | string | undefined>(\n initialValue,\n )\n const [modified, setModified] = React.useState<boolean>(false)\n const [entityType, setEntityType] = React.useState<'document' | 'global' | undefined>(undefined)\n const { user } = useAuth()\n const { config } = useConfig()\n const router = useRouter()\n const userID = React.useMemo(() => user?.id, [user?.id])\n const prevUserID = React.useRef(userID)\n const userChanged = userID !== prevUserID.current\n const [tenantOptions, setTenantOptions] = React.useState<OptionObject[]>(\n () => initialTenantOptions,\n )\n const selectedTenantLabel = React.useMemo(\n () => tenantOptions.find((option) => option.value === selectedTenantID)?.label,\n [selectedTenantID, tenantOptions],\n )\n\n const setTenantAndCookie = React.useCallback(\n ({ id, refresh }: { id: number | string | undefined; refresh?: boolean }) => {\n setSelectedTenantID(id)\n if (id !== undefined) {\n setTenantCookie({ value: String(id) })\n } else {\n deleteTenantCookie()\n }\n if (refresh) {\n router.refresh()\n }\n },\n [router],\n )\n\n const setTenant = React.useCallback<ContextType['setTenant']>(\n ({ id, refresh }) => {\n if (id === undefined) {\n if (tenantOptions.length > 1 || tenantOptions.length === 0) {\n // users with multiple tenants can clear the tenant selection\n setTenantAndCookie({ id: undefined, refresh })\n } else if (tenantOptions[0]) {\n // if there is only one tenant, auto-select that tenant\n setTenantAndCookie({ id: tenantOptions[0].value, refresh: true })\n }\n } else if (!tenantOptions.find((option) => option.value === id)) {\n // if the tenant is invalid, set the first tenant as selected\n setTenantAndCookie({\n id: tenantOptions[0]?.value,\n refresh,\n })\n } else {\n // if the tenant is in the options, set it as selected\n setTenantAndCookie({ id, refresh })\n }\n },\n [tenantOptions, setTenantAndCookie],\n )\n\n const syncTenants = React.useCallback(async () => {\n try {\n const req = await fetch(\n `${config.serverURL}${config.routes.api}/${tenantsCollectionSlug}/populate-tenant-options`,\n {\n credentials: 'include',\n method: 'GET',\n },\n )\n\n const result = await req.json()\n\n if (result.tenantOptions && userID) {\n setTenantOptions(result.tenantOptions)\n\n if (result.tenantOptions.length === 1) {\n setSelectedTenantID(result.tenantOptions[0].value)\n setTenantCookie({ value: String(result.tenantOptions[0].value) })\n }\n }\n } catch (e) {\n toast.error(`Error fetching tenants`)\n }\n }, [config.serverURL, config.routes.api, tenantsCollectionSlug, userID])\n\n const updateTenants = React.useCallback<ContextType['updateTenants']>(\n ({ id, label }) => {\n setTenantOptions((prev) => {\n return prev.map((currentTenant) => {\n if (id === currentTenant.value) {\n return {\n label,\n value: id,\n }\n }\n return currentTenant\n })\n })\n\n void syncTenants()\n },\n [syncTenants],\n )\n\n React.useEffect(() => {\n if (userChanged || (initialValue && String(initialValue) !== getTenantCookie())) {\n if (userID) {\n // user logging in\n void syncTenants()\n } else {\n // user logging out\n setSelectedTenantID(undefined)\n deleteTenantCookie()\n if (tenantOptions.length > 0) {\n setTenantOptions([])\n }\n }\n prevUserID.current = userID\n }\n }, [userID, userChanged, syncTenants, tenantOptions, initialValue])\n\n /**\n * If there is no initial value, clear the tenant and refresh the router.\n * Needed for stale tenantIDs set as a cookie.\n */\n React.useEffect(() => {\n if (!initialValue) {\n setTenant({ id: undefined, refresh: true })\n }\n }, [initialValue, setTenant])\n\n /**\n * If there is no selected tenant ID and the entity type is 'global', set the first tenant as selected.\n * This ensures that the global tenant is always set when the component mounts.\n */\n React.useEffect(() => {\n if (!selectedTenantID && tenantOptions.length > 0 && entityType === 'global') {\n setTenant({\n id: tenantOptions[0]?.value,\n refresh: true,\n })\n }\n }, [selectedTenantID, tenantOptions, entityType, setTenant])\n\n return (\n <span\n data-selected-tenant-id={selectedTenantID}\n data-selected-tenant-title={selectedTenantLabel}\n >\n <Context\n value={{\n entityType,\n modified,\n options: tenantOptions,\n selectedTenantID,\n setEntityType,\n setModified,\n setTenant,\n syncTenants,\n updateTenants,\n }}\n >\n {children}\n </Context>\n </span>\n )\n}\n\nexport const useTenantSelection = () => React.use(Context)\n"],"names":["toast","useAuth","useConfig","useRouter","React","createContext","generateCookie","Context","entityType","undefined","options","selectedTenantID","setEntityType","setModified","setTenant","syncTenants","Promise","resolve","updateTenants","DEFAULT_COOKIE_NAME","setTenantCookie","args","cookieName","value","document","cookie","name","maxAge","path","returnCookieAsObject","deleteTenantCookie","getTenantCookie","parts","split","length","pop","shift","TenantSelectionProviderClient","children","initialTenantOptions","initialValue","tenantsCollectionSlug","setSelectedTenantID","useState","modified","user","config","router","userID","useMemo","id","prevUserID","useRef","userChanged","current","tenantOptions","setTenantOptions","selectedTenantLabel","find","option","label","setTenantAndCookie","useCallback","refresh","String","req","fetch","serverURL","routes","api","credentials","method","result","json","e","error","prev","map","currentTenant","useEffect","span","data-selected-tenant-id","data-selected-tenant-title","useTenantSelection","use"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-multi-tenant",
|
|
3
|
-
"version": "3.59.
|
|
3
|
+
"version": "3.59.1",
|
|
4
4
|
"description": "Multi Tenant plugin for Payload",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"payload",
|
|
@@ -81,14 +81,14 @@
|
|
|
81
81
|
],
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@payloadcms/eslint-config": "3.28.0",
|
|
84
|
-
"@payloadcms/
|
|
85
|
-
"@payloadcms/
|
|
86
|
-
"payload": "3.59.
|
|
84
|
+
"@payloadcms/translations": "3.59.1",
|
|
85
|
+
"@payloadcms/ui": "3.59.1",
|
|
86
|
+
"payload": "3.59.1"
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"next": "^15.2.3",
|
|
90
|
-
"@payloadcms/ui": "3.59.
|
|
91
|
-
"payload": "3.59.
|
|
90
|
+
"@payloadcms/ui": "3.59.1",
|
|
91
|
+
"payload": "3.59.1"
|
|
92
92
|
},
|
|
93
93
|
"homepage:": "https://payloadcms.com",
|
|
94
94
|
"scripts": {
|