@payloadcms/plugin-multi-tenant 3.47.0 → 3.48.0-canary.0

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;AAE5C,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;AAaD,eAAO,MAAM,6BAA6B,wHAOvC;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;CACnB,sBAsKA,CAAA;AAED,eAAO,MAAM,kBAAkB,mBAA2B,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;AAE5C,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;AAaD,eAAO,MAAM,6BAA6B,wHAOvC;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;CACnB,sBAsJA,CAAA;AAED,eAAO,MAAM,kBAAkB,mBAA2B,CAAA"}
@@ -22,6 +22,8 @@ export const TenantSelectionProviderClient = ({ children, initialValue, tenantCo
22
22
  const userID = React.useMemo(()=>user?.id, [
23
23
  user?.id
24
24
  ]);
25
+ const prevUserID = React.useRef(userID);
26
+ const userChanged = userID !== prevUserID.current;
25
27
  const [tenantOptions, setTenantOptions] = React.useState(()=>tenantOptionsFromProps);
26
28
  const selectedTenantLabel = React.useMemo(()=>tenantOptions.find((option)=>option.value === selectedTenantID)?.label, [
27
29
  selectedTenantID,
@@ -42,16 +44,16 @@ export const TenantSelectionProviderClient = ({ children, initialValue, tenantCo
42
44
  // users with multiple tenants can clear the tenant selection
43
45
  setSelectedTenantID(undefined);
44
46
  deleteCookie();
45
- } else {
47
+ } else if (tenantOptions[0]) {
46
48
  // if there is only one tenant, force the selection of that tenant
47
- setSelectedTenantID(tenantOptions[0]?.value);
48
- setCookie(String(tenantOptions[0]?.value));
49
+ setSelectedTenantID(tenantOptions[0].value);
50
+ setCookie(String(tenantOptions[0].value));
49
51
  }
50
52
  } else if (!tenantOptions.find((option)=>option.value === id)) {
51
53
  // if the tenant is not valid, set the first tenant as selected
52
- if (tenantOptions?.[0]?.value) {
54
+ if (tenantOptions[0]?.value) {
53
55
  setTenant({
54
- id: tenantOptions[0].value,
56
+ id: tenantOptions[0]?.value,
55
57
  refresh: true
56
58
  });
57
59
  } else {
@@ -82,11 +84,15 @@ export const TenantSelectionProviderClient = ({ children, initialValue, tenantCo
82
84
  method: 'GET'
83
85
  });
84
86
  const result = await req.json();
85
- if (result.docs) {
87
+ if (result.docs && userID) {
86
88
  setTenantOptions(result.docs.map((doc)=>({
87
89
  label: doc[useAsTitle],
88
90
  value: doc.id
89
91
  })));
92
+ if (result.totalDocs === 1) {
93
+ setSelectedTenantID(result.docs[0].id);
94
+ setCookie(String(result.docs[0].id));
95
+ }
90
96
  }
91
97
  } catch (e) {
92
98
  toast.error(`Error fetching tenants`);
@@ -95,7 +101,9 @@ export const TenantSelectionProviderClient = ({ children, initialValue, tenantCo
95
101
  config.serverURL,
96
102
  config.routes.api,
97
103
  tenantsCollectionSlug,
98
- useAsTitle
104
+ useAsTitle,
105
+ setCookie,
106
+ userID
99
107
  ]);
100
108
  const updateTenants = React.useCallback(({ id, label })=>{
101
109
  setTenantOptions((prev)=>{
@@ -114,47 +122,26 @@ export const TenantSelectionProviderClient = ({ children, initialValue, tenantCo
114
122
  syncTenants
115
123
  ]);
116
124
  React.useEffect(()=>{
117
- if (userID && !tenantCookie) {
118
- if (tenantOptionsFromProps.length === 1) {
119
- // Users with no cookie set and only 1 tenant should set that tenant automatically
120
- setTenant({
121
- id: tenantOptionsFromProps[0]?.value,
122
- refresh: true
123
- });
124
- setTenantOptions(tenantOptionsFromProps);
125
- } else if ((!tenantOptions || tenantOptions.length === 0) && tenantOptionsFromProps.length > 0) {
126
- // If there are no tenant options, set them from the props
127
- setTenantOptions(tenantOptionsFromProps);
128
- }
129
- } else if (userID && tenantCookie) {
130
- if ((!tenantOptions || tenantOptions.length === 0) && tenantOptionsFromProps.length > 0) {
131
- // If there are no tenant options, set them from the props
132
- setTenantOptions(tenantOptionsFromProps);
125
+ if (userChanged) {
126
+ if (userID) {
127
+ // user logging in
128
+ void syncTenants();
129
+ } else {
130
+ // user logging out
131
+ setSelectedTenantID(undefined);
132
+ deleteCookie();
133
+ if (tenantOptions.length > 0) {
134
+ setTenantOptions([]);
135
+ }
133
136
  }
134
- }
135
- }, [
136
- initialValue,
137
- selectedTenantID,
138
- tenantCookie,
139
- userID,
140
- setTenant,
141
- tenantOptionsFromProps,
142
- tenantOptions
143
- ]);
144
- React.useEffect(()=>{
145
- if (!userID && tenantCookie) {
146
- // User is not logged in, but has a tenant cookie, delete it
147
- deleteCookie();
148
- setSelectedTenantID(undefined);
149
- } else if (userID) {
150
- // User changed, refresh
151
- router.refresh();
137
+ prevUserID.current = userID;
152
138
  }
153
139
  }, [
154
140
  userID,
155
- tenantCookie,
141
+ userChanged,
142
+ syncTenants,
156
143
  deleteCookie,
157
- router
144
+ tenantOptions
158
145
  ]);
159
146
  return /*#__PURE__*/ _jsx("span", {
160
147
  "data-selected-tenant-id": selectedTenantID,
@@ -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\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\nexport const TenantSelectionProviderClient = ({\n children,\n initialValue,\n tenantCookie,\n tenantOptions: tenantOptionsFromProps,\n tenantsCollectionSlug,\n useAsTitle,\n}: {\n children: React.ReactNode\n initialValue?: number | string\n tenantCookie?: string\n tenantOptions: OptionObject[]\n tenantsCollectionSlug: string\n useAsTitle: 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 userID = React.useMemo(() => user?.id, [user?.id])\n const [tenantOptions, setTenantOptions] = React.useState<OptionObject[]>(\n () => tenantOptionsFromProps,\n )\n const selectedTenantLabel = React.useMemo(\n () => tenantOptions.find((option) => option.value === selectedTenantID)?.label,\n [selectedTenantID, tenantOptions],\n )\n\n const router = useRouter()\n\n const setCookie = React.useCallback((value?: string) => {\n const expires = '; expires=Fri, 31 Dec 9999 23:59:59 GMT'\n document.cookie = 'payload-tenant=' + (value || '') + expires + '; path=/'\n }, [])\n\n const deleteCookie = React.useCallback(() => {\n // eslint-disable-next-line react-compiler/react-compiler -- TODO: fix\n document.cookie = 'payload-tenant=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'\n }, [])\n\n const setTenant = React.useCallback<ContextType['setTenant']>(\n ({ id, refresh }) => {\n if (id === undefined) {\n if (tenantOptions.length > 1) {\n // users with multiple tenants can clear the tenant selection\n setSelectedTenantID(undefined)\n deleteCookie()\n } else {\n // if there is only one tenant, force the selection of that tenant\n setSelectedTenantID(tenantOptions[0]?.value)\n setCookie(String(tenantOptions[0]?.value))\n }\n } else if (!tenantOptions.find((option) => option.value === id)) {\n // if the tenant is not valid, set the first tenant as selected\n if (tenantOptions?.[0]?.value) {\n setTenant({ id: tenantOptions[0].value, refresh: true })\n } else {\n setTenant({ id: undefined, refresh: true })\n }\n } else {\n // if the tenant is in the options, set it as selected\n setSelectedTenantID(id)\n setCookie(String(id))\n }\n if (entityType !== 'document' && refresh) {\n router.refresh()\n }\n },\n [deleteCookie, entityType, router, setCookie, tenantOptions],\n )\n\n const syncTenants = React.useCallback(async () => {\n try {\n const req = await fetch(\n `${config.serverURL}${config.routes.api}/${tenantsCollectionSlug}?select[${useAsTitle}]=true&limit=0&depth=0`,\n {\n credentials: 'include',\n method: 'GET',\n },\n )\n\n const result = await req.json()\n\n if (result.docs) {\n setTenantOptions(\n result.docs.map((doc: Record<string, number | string>) => ({\n label: doc[useAsTitle],\n value: doc.id,\n })),\n )\n }\n } catch (e) {\n toast.error(`Error fetching tenants`)\n }\n }, [config.serverURL, config.routes.api, tenantsCollectionSlug, useAsTitle])\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 (userID && !tenantCookie) {\n if (tenantOptionsFromProps.length === 1) {\n // Users with no cookie set and only 1 tenant should set that tenant automatically\n setTenant({ id: tenantOptionsFromProps[0]?.value, refresh: true })\n setTenantOptions(tenantOptionsFromProps)\n } else if (\n (!tenantOptions || tenantOptions.length === 0) &&\n tenantOptionsFromProps.length > 0\n ) {\n // If there are no tenant options, set them from the props\n setTenantOptions(tenantOptionsFromProps)\n }\n } else if (userID && tenantCookie) {\n if ((!tenantOptions || tenantOptions.length === 0) && tenantOptionsFromProps.length > 0) {\n // If there are no tenant options, set them from the props\n setTenantOptions(tenantOptionsFromProps)\n }\n }\n }, [\n initialValue,\n selectedTenantID,\n tenantCookie,\n userID,\n setTenant,\n tenantOptionsFromProps,\n tenantOptions,\n ])\n\n React.useEffect(() => {\n if (!userID && tenantCookie) {\n // User is not logged in, but has a tenant cookie, delete it\n deleteCookie()\n setSelectedTenantID(undefined)\n } else if (userID) {\n // User changed, refresh\n router.refresh()\n }\n }, [userID, tenantCookie, deleteCookie, router])\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","Context","entityType","undefined","options","selectedTenantID","setEntityType","setModified","setTenant","syncTenants","Promise","resolve","updateTenants","TenantSelectionProviderClient","children","initialValue","tenantCookie","tenantOptions","tenantOptionsFromProps","tenantsCollectionSlug","useAsTitle","setSelectedTenantID","useState","modified","user","config","userID","useMemo","id","setTenantOptions","selectedTenantLabel","find","option","value","label","router","setCookie","useCallback","expires","document","cookie","deleteCookie","refresh","length","String","req","fetch","serverURL","routes","api","credentials","method","result","json","docs","map","doc","e","error","prev","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\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\nexport const TenantSelectionProviderClient = ({\n children,\n initialValue,\n tenantCookie,\n tenantOptions: tenantOptionsFromProps,\n tenantsCollectionSlug,\n useAsTitle,\n}: {\n children: React.ReactNode\n initialValue?: number | string\n tenantCookie?: string\n tenantOptions: OptionObject[]\n tenantsCollectionSlug: string\n useAsTitle: 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 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 () => tenantOptionsFromProps,\n )\n const selectedTenantLabel = React.useMemo(\n () => tenantOptions.find((option) => option.value === selectedTenantID)?.label,\n [selectedTenantID, tenantOptions],\n )\n\n const router = useRouter()\n\n const setCookie = React.useCallback((value?: string) => {\n const expires = '; expires=Fri, 31 Dec 9999 23:59:59 GMT'\n document.cookie = 'payload-tenant=' + (value || '') + expires + '; path=/'\n }, [])\n\n const deleteCookie = React.useCallback(() => {\n // eslint-disable-next-line react-compiler/react-compiler -- TODO: fix\n document.cookie = 'payload-tenant=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'\n }, [])\n\n const setTenant = React.useCallback<ContextType['setTenant']>(\n ({ id, refresh }) => {\n if (id === undefined) {\n if (tenantOptions.length > 1) {\n // users with multiple tenants can clear the tenant selection\n setSelectedTenantID(undefined)\n deleteCookie()\n } else if (tenantOptions[0]) {\n // if there is only one tenant, force the selection of that tenant\n setSelectedTenantID(tenantOptions[0].value)\n setCookie(String(tenantOptions[0].value))\n }\n } else if (!tenantOptions.find((option) => option.value === id)) {\n // if the tenant is not valid, set the first tenant as selected\n if (tenantOptions[0]?.value) {\n setTenant({ id: tenantOptions[0]?.value, refresh: true })\n } else {\n setTenant({ id: undefined, refresh: true })\n }\n } else {\n // if the tenant is in the options, set it as selected\n setSelectedTenantID(id)\n setCookie(String(id))\n }\n if (entityType !== 'document' && refresh) {\n router.refresh()\n }\n },\n [deleteCookie, entityType, router, setCookie, tenantOptions],\n )\n\n const syncTenants = React.useCallback(async () => {\n try {\n const req = await fetch(\n `${config.serverURL}${config.routes.api}/${tenantsCollectionSlug}?select[${useAsTitle}]=true&limit=0&depth=0`,\n {\n credentials: 'include',\n method: 'GET',\n },\n )\n\n const result = await req.json()\n\n if (result.docs && userID) {\n setTenantOptions(\n result.docs.map((doc: Record<string, number | string>) => ({\n label: doc[useAsTitle],\n value: doc.id,\n })),\n )\n\n if (result.totalDocs === 1) {\n setSelectedTenantID(result.docs[0].id)\n setCookie(String(result.docs[0].id))\n }\n }\n } catch (e) {\n toast.error(`Error fetching tenants`)\n }\n }, [config.serverURL, config.routes.api, tenantsCollectionSlug, useAsTitle, setCookie, 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, deleteCookie, tenantOptions])\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","Context","entityType","undefined","options","selectedTenantID","setEntityType","setModified","setTenant","syncTenants","Promise","resolve","updateTenants","TenantSelectionProviderClient","children","initialValue","tenantCookie","tenantOptions","tenantOptionsFromProps","tenantsCollectionSlug","useAsTitle","setSelectedTenantID","useState","modified","user","config","userID","useMemo","id","prevUserID","useRef","userChanged","current","setTenantOptions","selectedTenantLabel","find","option","value","label","router","setCookie","useCallback","expires","document","cookie","deleteCookie","refresh","length","String","req","fetch","serverURL","routes","api","credentials","method","result","json","docs","map","doc","totalDocs","e","error","prev","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.47.0",
3
+ "version": "3.48.0-canary.0",
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/translations": "3.47.0",
85
- "@payloadcms/ui": "3.47.0",
86
- "payload": "3.47.0"
84
+ "@payloadcms/ui": "3.48.0-canary.0",
85
+ "@payloadcms/translations": "3.48.0-canary.0",
86
+ "payload": "3.48.0-canary.0"
87
87
  },
88
88
  "peerDependencies": {
89
89
  "next": "^15.2.3",
90
- "@payloadcms/ui": "3.47.0",
91
- "payload": "3.47.0"
90
+ "@payloadcms/ui": "3.48.0-canary.0",
91
+ "payload": "3.48.0-canary.0"
92
92
  },
93
93
  "homepage:": "https://payloadcms.com",
94
94
  "scripts": {