diff --git a/ee/insiders b/ee/insiders index bbc136d82..c481a017f 160000 --- a/ee/insiders +++ b/ee/insiders @@ -1 +1 @@ -Subproject commit bbc136d82da6aedc8bc0bd9d7884ca4112f3470d +Subproject commit c481a017f4d2fc8e4f46facf107b92be8cc3c833 diff --git a/packages/core/modules/Settings/account.tsx b/packages/core/modules/Settings/account.tsx index f41283d8b..bac16398b 100644 --- a/packages/core/modules/Settings/account.tsx +++ b/packages/core/modules/Settings/account.tsx @@ -3,14 +3,14 @@ import { WorkspaceConfigForm } from "@karrio/ui/forms/workspace-config-form"; import { CloseAccountAction } from "@karrio/ui/forms/close-account-action"; import { dynamicMetadata } from "@karrio/core/components/metadata"; import { ConfirmModal } from "@karrio/ui/modals/confirm-modal"; +import { useAPIMetadata } from "@karrio/hooks/api-metadata"; import { AppLink } from "@karrio/ui/components/app-link"; export const generateMetadata = dynamicMetadata("Account Settings"); export default function AccountPage(pageProps: any) { - const { APP_NAME, MULTI_ORGANIZATIONS } = (pageProps as any).metadata || {}; - - const Component= (): JSX.Element => { + const Component = (): JSX.Element => { + const { metadata } = useAPIMetadata(); return ( <>
@@ -38,10 +38,11 @@ export default function AccountPage(pageProps: any) { Profile - {MULTI_ORGANIZATIONS && ( + {metadata?.MULTI_ORGANIZATIONS && (
  • @@ -91,10 +92,11 @@ export default function AccountPage(pageProps: any) {

    Close Account

    Warning: You will lose access to your{" "} - {APP_NAME} services + {metadata?.APP_NAME} services

    +
    Close this account... diff --git a/packages/core/modules/Settings/addresses.tsx b/packages/core/modules/Settings/addresses.tsx index 7a73deacf..fb440c148 100644 --- a/packages/core/modules/Settings/addresses.tsx +++ b/packages/core/modules/Settings/addresses.tsx @@ -16,6 +16,7 @@ import { import { GoogleGeocodingScript } from "@karrio/ui/components/google-geocoding-script"; import { ConfirmModal, useConfirmModal } from "@karrio/ui/modals/confirm-modal"; import { dynamicMetadata } from "@karrio/core/components/metadata"; +import { useAPIMetadata } from "@karrio/hooks/api-metadata"; import { AppLink } from "@karrio/ui/components/app-link"; import { useLoader } from "@karrio/ui/components/loader"; import { useSearchParams } from "next/navigation"; @@ -25,9 +26,8 @@ import React, { useEffect } from "react"; export const generateMetadata = dynamicMetadata("Addresses"); export default function AddressPage(pageProps: any) { - const { MULTI_ORGANIZATIONS } = (pageProps as any).metadata || {}; - const Component = (): JSX.Element => { + const { metadata } = useAPIMetadata(); const searchParams = useSearchParams(); const modal = searchParams.get("modal") as string; const { setLoading } = useLoader(); @@ -109,7 +109,7 @@ export default function AddressPage(pageProps: any) { Profile
  • - {MULTI_ORGANIZATIONS && ( + {metadata?.MULTI_ORGANIZATIONS && (
  • { + const Component = (): JSX.Element => { + const { metadata } = useAPIMetadata(); return ( <>
    @@ -38,10 +38,11 @@ export default function AccountPage(pageProps: any) { Profile
  • - {MULTI_ORGANIZATIONS && ( + {metadata?.MULTI_ORGANIZATIONS && (
  • + - {MULTI_ORGANIZATIONS && ( + {metadata?.MULTI_ORGANIZATIONS && (
    diff --git a/packages/core/modules/Settings/parcels.tsx b/packages/core/modules/Settings/parcels.tsx index c38e0580d..1b1a77d77 100644 --- a/packages/core/modules/Settings/parcels.tsx +++ b/packages/core/modules/Settings/parcels.tsx @@ -11,17 +11,16 @@ import { ConfirmModal, useConfirmModal } from "@karrio/ui/modals/confirm-modal"; import { ParcelDescription } from "@karrio/ui/components/parcel-description"; import { dynamicMetadata } from "@karrio/core/components/metadata"; import { getURLSearchParams, isNoneOrEmpty } from "@karrio/lib"; -import { AppLink } from "@karrio/ui/components/app-link"; +import { useAPIMetadata } from "@karrio/hooks/api-metadata"; import { useLoader } from "@karrio/ui/components/loader"; +import { AppLink } from "@karrio/ui/components/app-link"; import React, { useEffect, useState } from "react"; import { useSearchParams } from "next/navigation"; - export const generateMetadata = dynamicMetadata("Parcels"); export default function ParcelsPage(pageProps: any) { - const { MULTI_ORGANIZATIONS } = (pageProps as any).metadata || {}; - const Component = (): JSX.Element => { + const { metadata } = useAPIMetadata(); const searchParams = useSearchParams(); const modal = searchParams.get("modal") as string; const { setLoading } = useLoader(); @@ -103,10 +102,11 @@ export default function ParcelsPage(pageProps: any) { Profile
  • - {MULTI_ORGANIZATIONS && ( + {metadata?.MULTI_ORGANIZATIONS && (
  • diff --git a/packages/core/modules/Settings/profile.tsx b/packages/core/modules/Settings/profile.tsx index 7974729a3..ad62d6a72 100644 --- a/packages/core/modules/Settings/profile.tsx +++ b/packages/core/modules/Settings/profile.tsx @@ -5,13 +5,13 @@ import { EmailManagement } from "@karrio/ui/forms/email-management"; import { dynamicMetadata } from "@karrio/core/components/metadata"; import { ConfirmModal } from "@karrio/ui/modals/confirm-modal"; import { AppLink } from "@karrio/ui/components/app-link"; +import { useAPIMetadata } from "@karrio/hooks/api-metadata"; export const generateMetadata = dynamicMetadata("Profile Settings"); export default function AccountPage(pageProps: any) { - const { APP_NAME, MULTI_ORGANIZATIONS } = (pageProps as any).metadata || {}; - - const Component= (): JSX.Element => { + const Component = (): JSX.Element => { + const { metadata } = useAPIMetadata(); return ( <>
    @@ -39,10 +39,11 @@ export default function AccountPage(pageProps: any) { Profile
  • - {MULTI_ORGANIZATIONS && ( + {metadata?.MULTI_ORGANIZATIONS && (
  • @@ -85,7 +86,7 @@ export default function AccountPage(pageProps: any) {

    Profile

    - Your email address is your identity on {APP_NAME} and is used to + Your email address is your identity on {metadata?.APP_NAME} and is used to log in.

    diff --git a/packages/core/modules/Settings/templates.tsx b/packages/core/modules/Settings/templates.tsx index 7d5917680..2900c7f4a 100644 --- a/packages/core/modules/Settings/templates.tsx +++ b/packages/core/modules/Settings/templates.tsx @@ -12,16 +12,16 @@ import { DocumentTemplateType, NotificationType } from "@karrio/types"; import { dynamicMetadata } from "@karrio/core/components/metadata"; import { useConfirmModal } from "@karrio/ui/modals/confirm-modal"; import { useNotifier } from "@karrio/ui/components/notifier"; +import { useAPIMetadata } from "@karrio/hooks/api-metadata"; import { AppLink } from "@karrio/ui/components/app-link"; import React from "react"; export const generateMetadata = dynamicMetadata("Document Templates"); export default function TemplatesPage(pageProps: any) { - const { MULTI_ORGANIZATIONS } = (pageProps as any).metadata || {}; - const Component = (): JSX.Element => { const { notify } = useNotifier(); + const { metadata } = useAPIMetadata(); const mutation = useDocumentTemplateMutation(); const { confirm: confirmDeletion } = useConfirmModal(); const { @@ -35,20 +35,20 @@ export default function TemplatesPage(pageProps: any) { }; const toggle = ({ active, id }: DocumentTemplateType) => - async () => { - try { - await mutation.updateDocumentTemplate.mutateAsync({ - id, - active: !active, - }); - notify({ - type: NotificationType.success, - message: `template ${!active ? "enabled" : "disabled"}!`, - }); - } catch (message: any) { - notify({ type: NotificationType.error, message }); - } - }; + async () => { + try { + await mutation.updateDocumentTemplate.mutateAsync({ + id, + active: !active, + }); + notify({ + type: NotificationType.success, + message: `template ${!active ? "enabled" : "disabled"}!`, + }); + } catch (message: any) { + notify({ type: NotificationType.error, message }); + } + }; return ( <> @@ -84,7 +84,7 @@ export default function TemplatesPage(pageProps: any) { Profile
  • - {MULTI_ORGANIZATIONS && ( + {metadata?.MULTI_ORGANIZATIONS && (
  • { +export const OrganizationDropdown = (): JSX.Element => { const trigger = useRef(null); const searchParams = useSearchParams(); const { query } = useAPIToken(); diff --git a/packages/ui/modals/create-organization-modal.tsx b/packages/ui/modals/create-organization-modal.tsx index e9f5066f3..1ca3566d3 100644 --- a/packages/ui/modals/create-organization-modal.tsx +++ b/packages/ui/modals/create-organization-modal.tsx @@ -1,133 +1,133 @@ -import { CreateOrganizationMutationInput } from '@karrio/types/graphql/ee'; -import { useOrganizationMutation } from '@karrio/hooks/organization'; -import React, { useContext, useReducer, useState } from 'react'; -import { Notifier, useNotifier } from '../components/notifier'; -import { InputField } from '../components/input-field'; -import { NotificationType } from '@karrio/types'; -import { useLoader } from '../components/loader'; -import { isEqual, isNone } from '@karrio/lib'; - -type OperationType = { - onChange: (orgId: string) => Promise; -}; -type CreateOrganizationContextType = { - createOrganization: (operation: OperationType) => void, -}; -type stateValue = string | boolean | Partial | undefined | null; - -const DEFAULT_ORGANIZATION = { name: "" } as Partial; - -function reducer(state: Partial | undefined, { name, value }: { name: string, value: stateValue }) { - switch (name) { - case 'partial': - return isNone(value) ? undefined : { ...(state || {}), ...(value as CreateOrganizationMutationInput) }; - default: - return { ...(state || {}), [name]: value } - } -} - -export const CreateOrganizationContext = React.createContext({} as CreateOrganizationContextType); - -export const CreateOrganizationModalProvider= ({ children }): JSX.Element => { - const { notify } = useNotifier(); - const { loading, setLoading } = useLoader(); - const mutation = useOrganizationMutation(); - const [key, setKey] = useState(`organization-${Date.now()}`); - const [isActive, setIsActive] = useState(false); - const [organization, dispatch] = useReducer(reducer, undefined, () => DEFAULT_ORGANIZATION); - const [operation, setOperation] = useState(); - - const createOrganization = (operation: OperationType) => { - setIsActive(true); - setOperation(operation); - dispatch({ name: 'partial', value: DEFAULT_ORGANIZATION }); - setKey(`organization-${Date.now()}`); - }; - const close = (_?: React.MouseEvent | any) => { - setIsActive(false); - setOperation(undefined); - dispatch({ name: 'partial', value: undefined }); - setKey(`organization-${Date.now()}`); - }; - - const handleChange = (event: React.ChangeEvent) => { - event.preventDefault(); - const target = event.target; - let name: string = target.name; - let value: stateValue = target.type === 'checkbox' ? target.checked : target.value; - - dispatch({ name, value }); - }; - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setLoading(true); - try { - const response = await mutation.createOrganization.mutateAsync(organization as any); - notify({ type: NotificationType.success, message: 'Organization created successfully!' }); - operation?.onChange && operation?.onChange(response?.create_organization?.organization?.id as string); - setTimeout(() => { setLoading(false); close(); }, 600); - } catch (message: any) { - notify({ type: NotificationType.error, message }); - setLoading(false); - } - }; - - return ( - - - {children} - - -
    -
    -
    - -
    -
    - Create a new organization -
    -
    - - {organization && <> -
    - - - -
    - -
    -
    - - -
    - } -
    - -
    - - -
    -
    - ) -}; - -export function useCreateOrganizationModal() { - return useContext(CreateOrganizationContext); -} +import { CreateOrganizationMutationInput } from '@karrio/types/graphql/ee'; +import { useOrganizationMutation } from '@karrio/hooks/organization'; +import React, { useContext, useReducer, useState } from 'react'; +import { Notifier, useNotifier } from '../components/notifier'; +import { InputField } from '../components/input-field'; +import { NotificationType } from '@karrio/types'; +import { useLoader } from '../components/loader'; +import { isEqual, isNone } from '@karrio/lib'; + +type OperationType = { + onChange: (orgId: string) => Promise; +}; +type CreateOrganizationContextType = { + createOrganization: (operation: OperationType) => void, +}; +type stateValue = string | boolean | Partial | undefined | null; + +const DEFAULT_ORGANIZATION = { name: "" } as Partial; + +function reducer(state: Partial | undefined, { name, value }: { name: string, value: stateValue }) { + switch (name) { + case 'partial': + return isNone(value) ? undefined : { ...(state || {}), ...(value as CreateOrganizationMutationInput) }; + default: + return { ...(state || {}), [name]: value } + } +} + +export const CreateOrganizationContext = React.createContext({} as CreateOrganizationContextType); + +export const CreateOrganizationModalProvider = ({ children }: { children: React.ReactNode }): JSX.Element => { + const { notify } = useNotifier(); + const { loading, setLoading } = useLoader(); + const mutation = useOrganizationMutation(); + const [key, setKey] = useState(`organization-${Date.now()}`); + const [isActive, setIsActive] = useState(false); + const [organization, dispatch] = useReducer(reducer, undefined, () => DEFAULT_ORGANIZATION); + const [operation, setOperation] = useState(); + + const createOrganization = (operation: OperationType) => { + setIsActive(true); + setOperation(operation); + dispatch({ name: 'partial', value: DEFAULT_ORGANIZATION }); + setKey(`organization-${Date.now()}`); + }; + const close = (_?: React.MouseEvent | any) => { + setIsActive(false); + setOperation(undefined); + dispatch({ name: 'partial', value: undefined }); + setKey(`organization-${Date.now()}`); + }; + + const handleChange = (event: React.ChangeEvent) => { + event.preventDefault(); + const target = event.target; + let name: string = target.name; + let value: stateValue = target.type === 'checkbox' ? target.checked : target.value; + + dispatch({ name, value }); + }; + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + try { + const response = await mutation.createOrganization.mutateAsync(organization as any); + notify({ type: NotificationType.success, message: 'Organization created successfully!' }); + operation?.onChange && operation?.onChange(response?.create_organization?.organization?.id as string); + setTimeout(() => { setLoading(false); close(); }, 600); + } catch (message: any) { + notify({ type: NotificationType.error, message }); + setLoading(false); + } + }; + + return ( + + + {children} + + +
    +
    +
    + +
    +
    + Create a new organization +
    +
    + + {organization && <> +
    + + + +
    + +
    +
    + + +
    + } +
    + +
    + + +
    +
    + ) +}; + +export function useCreateOrganizationModal() { + return useContext(CreateOrganizationContext); +} diff --git a/schemas/graphql-ee.json b/schemas/graphql-ee.json index 9716366e3..a4ec6dd2a 100644 --- a/schemas/graphql-ee.json +++ b/schemas/graphql-ee.json @@ -10077,6 +10077,12 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "cancelled", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "delivered", "description": null, @@ -10112,6 +10118,12 @@ "description": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "return_to_sender", + "description": null, + "isDeprecated": false, + "deprecationReason": null } ], "possibleTypes": null @@ -26972,6 +26984,16 @@ } }, "defaultValue": null + }, + { + "name": "metadata", + "description": null, + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "defaultValue": null } ], "interfaces": null, @@ -27480,6 +27502,16 @@ "ofType": null }, "defaultValue": null + }, + { + "name": "metadata", + "description": null, + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "defaultValue": null } ], "interfaces": null, @@ -32199,19 +32231,15 @@ "name": "roles", "description": null, "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "UserRole", - "ofType": null - } + "kind": "ENUM", + "name": "UserRole", + "ofType": null } } }, diff --git a/schemas/graphql.json b/schemas/graphql.json index 9716366e3..a4ec6dd2a 100644 --- a/schemas/graphql.json +++ b/schemas/graphql.json @@ -10077,6 +10077,12 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "cancelled", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "delivered", "description": null, @@ -10112,6 +10118,12 @@ "description": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "return_to_sender", + "description": null, + "isDeprecated": false, + "deprecationReason": null } ], "possibleTypes": null @@ -26972,6 +26984,16 @@ } }, "defaultValue": null + }, + { + "name": "metadata", + "description": null, + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "defaultValue": null } ], "interfaces": null, @@ -27480,6 +27502,16 @@ "ofType": null }, "defaultValue": null + }, + { + "name": "metadata", + "description": null, + "type": { + "kind": "SCALAR", + "name": "JSON", + "ofType": null + }, + "defaultValue": null } ], "interfaces": null, @@ -32199,19 +32231,15 @@ "name": "roles", "description": null, "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "UserRole", - "ofType": null - } + "kind": "ENUM", + "name": "UserRole", + "ofType": null } } }, diff --git a/schemas/openapi.yml b/schemas/openapi.yml index 1600d2eef..29809fe98 100644 --- a/schemas/openapi.yml +++ b/schemas/openapi.yml @@ -14,7 +14,7 @@ info: ## Versioning When backwards-incompatible changes are made to the API, a new, dated version is released. - The current version is `2024.12.2`. + The current version is `2024.12.3`. Read our API changelog to learn more about backwards compatibility. @@ -84,7 +84,7 @@ info: All API requests must be made over [HTTPS](http://en.wikipedia.org/wiki/HTTP_Secure). API requests without authentication will also fail. title: Karrio API - version: 2024.12.2 + version: 2024.12.3 paths: /: get: