From ae70226f9321c2b2906d4fef74c5b1381d9d87d2 Mon Sep 17 00:00:00 2001 From: Siddharth Tiwari Date: Thu, 22 Feb 2024 12:09:50 +0530 Subject: [PATCH] feat(pay): ui improvement rebase --- apps/pay/app/[username]/layout.tsx | 42 ++- apps/pay/app/[username]/page.tsx | 157 +++------ apps/pay/app/currency-metadata.ts | 10 + apps/pay/app/reducer.tsx | 20 +- apps/pay/app/sats-currency.ts | 10 + apps/pay/app/ssr-client.ts | 27 ++ apps/pay/components/apollo-wrapper.tsx | 2 +- .../components/currency/currency-dropdown.tsx | 20 +- apps/pay/components/input/index.tsx | 34 ++ .../components/layouts/app-layout.module.css | 10 +- .../components/layouts/username-layout.tsx | 145 +------- apps/pay/components/memo/index.tsx | 32 +- .../components/parse-pos-payment/index.tsx | 322 +++--------------- .../parse-payment.module.css | 34 +- .../parse-pos-payment/receive-invoice.tsx | 62 ++-- apps/pay/components/sheet/index.tsx | 127 +++++++ apps/pay/components/sidebar/index.tsx | 133 ++++++++ apps/pay/components/utils.ts | 6 + apps/pay/context/invoice-context.tsx | 56 +++ apps/pay/package.json | 9 + apps/pay/postcss.config.js | 6 + apps/pay/tailwind.config.ts | 20 ++ pnpm-lock.yaml | 270 ++++++++++++--- 23 files changed, 887 insertions(+), 667 deletions(-) create mode 100644 apps/pay/app/currency-metadata.ts create mode 100644 apps/pay/app/sats-currency.ts create mode 100644 apps/pay/app/ssr-client.ts create mode 100644 apps/pay/components/input/index.tsx create mode 100644 apps/pay/components/sheet/index.tsx create mode 100644 apps/pay/components/sidebar/index.tsx create mode 100644 apps/pay/components/utils.ts create mode 100644 apps/pay/context/invoice-context.tsx create mode 100644 apps/pay/postcss.config.js create mode 100644 apps/pay/tailwind.config.ts diff --git a/apps/pay/app/[username]/layout.tsx b/apps/pay/app/[username]/layout.tsx index c76269ee532..2f656f460a7 100644 --- a/apps/pay/app/[username]/layout.tsx +++ b/apps/pay/app/[username]/layout.tsx @@ -1,19 +1,45 @@ import React from "react" +import { getClient } from "../ssr-client" + +import { defaultCurrencyMetadata } from "../currency-metadata" + import UsernameLayoutContainer from "@/components/layouts/username-layout" +import { InvoiceProvider } from "@/context/invoice-context" +import { + AccountDefaultWalletsDocument, + AccountDefaultWalletsQuery, +} from "@/lib/graphql/generated" -export default function UsernameLayout({ - children, - params, -}: { +type Props = { children: React.ReactNode params: { username: string } -}) { +} + +export default async function UsernameLayout({ children, params }: Props) { + const response = await getClient().query({ + query: AccountDefaultWalletsDocument, + variables: { username: params.username }, + }) + + const initialState = { + currentAmount: "0", + createdInvoice: false, + walletCurrency: response.data.accountDefaultWallet.walletCurrency, + walletId: response.data.accountDefaultWallet.id, + username: params.username, + pinnedToHomeScreenModalVisible: false, + memo: "", + displayCurrencyMetaData: defaultCurrencyMetadata, + } + return ( - - {children} - + + + {children} + + ) } diff --git a/apps/pay/app/[username]/page.tsx b/apps/pay/app/[username]/page.tsx index 101836d13e5..b943555ecc9 100644 --- a/apps/pay/app/[username]/page.tsx +++ b/apps/pay/app/[username]/page.tsx @@ -1,6 +1,5 @@ "use client" -import Link from "next/link" -import React from "react" +import React, { useEffect } from "react" import Container from "react-bootstrap/Container" import Image from "react-bootstrap/Image" @@ -8,21 +7,14 @@ import Head from "next/head" import { gql } from "@apollo/client" -import { useSearchParams } from "next/navigation" - import ParsePayment from "../../components/parse-pos-payment" -import PinToHomescreen from "../../components/pin-to-homescreen" - -import CurrencyDropdown from "../../components/currency/currency-dropdown" - -import { useAccountDefaultWalletsQuery } from "../../lib/graphql/generated" -import reducer, { ACTIONS } from "../reducer" +import { ACTIONS } from "../reducer" import styles from "./username.module.css" import LoadingComponent from "@/components/loading" -import { extractSearchParams } from "@/utils/utils" +import { useInvoiceContext } from "@/context/invoice-context" gql` query accountDefaultWallets($username: Username!) { @@ -35,71 +27,30 @@ gql` ` type Props = { - params: { - username: string + searchParams: { + memo: string + amount: string } } -function updateCurrencyAndReload(newDisplayCurrency: string): void { - localStorage.setItem("display", newDisplayCurrency) - - const currentURL = new URL(window.location.toString()) - const searchParams = new URLSearchParams(window.location.search) - searchParams.set("display", newDisplayCurrency) - currentURL.search = searchParams.toString() - - window.history.pushState({}, "", currentURL.toString()) - setTimeout(() => { - window.location.reload() - }, 100) -} - -function ReceivePayment({ params }: Props) { - const searchParams = useSearchParams() - const { memo } = extractSearchParams(searchParams) +function ReceivePayment({ searchParams }: Props) { + const { memo, amount } = searchParams + const { state, dispatch } = useInvoiceContext() + const { username } = state - const { username } = params + const manifestParams = new URLSearchParams() - let accountUsername: string - if (!username) { - accountUsername = "" - } else { - accountUsername = username.toString() - } + useEffect(() => { + dispatch({ + type: ACTIONS.SET_AMOUNT_FROM_PARAMS, + payload: amount ?? "0", + }) + }, []) - const manifestParams = new URLSearchParams() if (memo) { manifestParams.set("memo", memo.toString()) } - const { - data, - error: usernameError, - loading: usernameLoading, - } = useAccountDefaultWalletsQuery({ - variables: { username: accountUsername }, - skip: !accountUsername, - }) - - const [state, dispatch] = React.useReducer(reducer, { - currentAmount: "", - createdInvoice: false, - walletCurrency: data?.accountDefaultWallet.walletCurrency, - username: accountUsername, - pinnedToHomeScreenModalVisible: false, - }) - - React.useEffect(() => { - if (state.walletCurrency === data?.accountDefaultWallet.walletCurrency) { - return - } - dispatch({ - type: ACTIONS.UPDATE_WALLET_CURRENCY, - payload: data?.accountDefaultWallet.walletCurrency, - }) - dispatch({ type: ACTIONS.UPDATE_USERNAME, payload: username }) - }, [state, username, data]) - return username ? ( @@ -109,7 +60,7 @@ function ReceivePayment({ params }: Props) { id="manifest" /> - {usernameError ? ( + {/* {false ? (

{`${usernameError.message}.`}

Please check the username in your browser URL and try again.

@@ -117,54 +68,34 @@ function ReceivePayment({ params }: Props) { Back
- ) : ( - <> - -
- {state.createdInvoice && ( - - )} -

{`Pay ${username}`}

-
- +
+ {state.createdInvoice && ( +
-
- {data && !usernameLoading && accountUsername && state ? ( - - ) : ( - + )} - - )} +

{`Pay ${username}`}

+
+ {username && state ? ( + + ) : ( + + )} + + {/* )} */}
) : null } diff --git a/apps/pay/app/currency-metadata.ts b/apps/pay/app/currency-metadata.ts new file mode 100644 index 00000000000..5770a5e234b --- /dev/null +++ b/apps/pay/app/currency-metadata.ts @@ -0,0 +1,10 @@ +import { Currency } from "@/lib/graphql/generated" + +export const defaultCurrencyMetadata: Currency = { + id: "USD", + flag: "🇺🇸", + name: "US Dollar", + symbol: "$", + fractionDigits: 2, + __typename: "Currency", +} diff --git a/apps/pay/app/reducer.tsx b/apps/pay/app/reducer.tsx index 93c2832be42..e9dc42782c8 100644 --- a/apps/pay/app/reducer.tsx +++ b/apps/pay/app/reducer.tsx @@ -2,6 +2,8 @@ import React from "react" import { MAX_INPUT_VALUE_LENGTH } from "../config/config" +import { Currency } from "@/lib/graphql/generated" + export const ACTIONS = { ADD_DIGIT: "add-digit", DELETE_DIGIT: "delete-digit", @@ -14,11 +16,12 @@ export const ACTIONS = { PINNED_TO_HOMESCREEN_MODAL_VISIBLE: "pin-to-home-screen-modal-visible", BACK: "back-by-one-history", ADD_MEMO: "add-memo", + UPDATE_DISPLAY_CURRENCY_METADATA: "update-display-currency-metadata", } export type ACTION_TYPE = { type: string - payload?: string | string[] | (() => void) | boolean | undefined + payload?: string | string[] | (() => void) | boolean | undefined | Currency } function reducer(state: React.ComponentState, { type, payload }: ACTION_TYPE) { @@ -39,11 +42,16 @@ function reducer(state: React.ComponentState, { type, payload }: ACTION_TYPE) { } return { ...state, - currentAmount: `${state.currentAmount || ""}${payload}`, + currentAmount: `${state.currentAmount || "0"}${payload}`, } case ACTIONS.DELETE_DIGIT: - if (state.currentAmount == null) return state + if ( + state.currentAmount == null || + state.currentAmount === "" || + state.currentAmount === "0" + ) + return state return { ...state, currentAmount: state.currentAmount?.slice(0, -1), @@ -127,6 +135,12 @@ function reducer(state: React.ComponentState, { type, payload }: ACTION_TYPE) { memo: payload, } + case ACTIONS.UPDATE_DISPLAY_CURRENCY_METADATA: + return { + ...state, + displayCurrency: payload, + } + default: return state } diff --git a/apps/pay/app/sats-currency.ts b/apps/pay/app/sats-currency.ts new file mode 100644 index 00000000000..50fb49e168f --- /dev/null +++ b/apps/pay/app/sats-currency.ts @@ -0,0 +1,10 @@ +import { Currency } from "@/lib/graphql/generated" + +export const satsCurrencyMetadata: Currency = { + id: "SAT", + flag: "Sats ₿", + name: "Satoshi", + symbol: "sats", + fractionDigits: 0, + __typename: "Currency", +} diff --git a/apps/pay/app/ssr-client.ts b/apps/pay/app/ssr-client.ts new file mode 100644 index 00000000000..7ff1a97a618 --- /dev/null +++ b/apps/pay/app/ssr-client.ts @@ -0,0 +1,27 @@ +import { HttpLink } from "@apollo/client" +import { registerApolloClient } from "@apollo/experimental-nextjs-app-support/rsc" +import { + NextSSRApolloClient, + NextSSRInMemoryCache, +} from "@apollo/experimental-nextjs-app-support/ssr" + +import { getClientSideGqlConfig } from "@/config/config" + +export const { getClient } = registerApolloClient(() => { + return new NextSSRApolloClient({ + cache: new NextSSRInMemoryCache(), + link: new HttpLink({ + uri: getClientSideGqlConfig().coreGqlUrl, + fetchOptions: { cache: "no-store" }, + + // fetch: (uri, options) => { + // const headersWithTrace = options?.headers || {} + // propagation.inject(context.active(), headersWithTrace) + // return fetch(String(uri), { + // ...options, + // headers: headersWithTrace, + // }) + // }, + }), + }) +}) diff --git a/apps/pay/components/apollo-wrapper.tsx b/apps/pay/components/apollo-wrapper.tsx index d64d5bc68fc..c1504cfa201 100644 --- a/apps/pay/components/apollo-wrapper.tsx +++ b/apps/pay/components/apollo-wrapper.tsx @@ -23,7 +23,7 @@ function makeClient() { const wsLink = new GraphQLWsLink( createClient({ - url: getClientSideGqlConfig().coreGqlWebSocketUrl, + url: "wss://ws.blink.sv/graphql", retryAttempts: 12, connectionParams: {}, shouldRetry: (errOrCloseEvent) => { diff --git a/apps/pay/components/currency/currency-dropdown.tsx b/apps/pay/components/currency/currency-dropdown.tsx index 8e321033dce..8ff5c7820e0 100644 --- a/apps/pay/components/currency/currency-dropdown.tsx +++ b/apps/pay/components/currency/currency-dropdown.tsx @@ -3,7 +3,9 @@ import React, { useEffect } from "react" import { useSearchParams } from "next/navigation" -import { useCurrencyListQuery } from "../../lib/graphql/generated" +import { Currency, useCurrencyListQuery } from "../../lib/graphql/generated" + +import { satsCurrencyMetadata } from "@/app/sats-currency" export default function CurrencyDropdown({ onSelectedDisplayCurrencyChange, @@ -17,17 +19,23 @@ export default function CurrencyDropdown({ showOnlyFlag?: boolean }) { const searchParams = useSearchParams() - const display = searchParams?.get("display") + const display = searchParams?.get("displayCurrency") const { data: currencyData } = useCurrencyListQuery() + const [selectedDisplayCurrency, setSelectedDisplayCurrency] = React.useState("USD") const [isDropDownOpen, setIsDropDownOpen] = React.useState(false) + let updatedCurrencyList: Currency[] = [] + + if (currencyData?.currencyList) { + updatedCurrencyList = [...currencyData?.currencyList, satsCurrencyMetadata] + } useEffect(() => { const newDisplay = display && typeof display === "string" ? display - : localStorage.getItem("display") ?? "USD" + : localStorage.getItem("displayCurrency") ?? "USD" setSelectedDisplayCurrency(newDisplay) // eslint-disable-next-line react-hooks/exhaustive-deps @@ -36,12 +44,12 @@ export default function CurrencyDropdown({ return ( + + ) +} + +export default InputComponent diff --git a/apps/pay/components/layouts/app-layout.module.css b/apps/pay/components/layouts/app-layout.module.css index 3b0b7477b08..639ca433063 100644 --- a/apps/pay/components/layouts/app-layout.module.css +++ b/apps/pay/components/layouts/app-layout.module.css @@ -14,11 +14,15 @@ display: flex; justify-content: space-between; align-items: center; - position: relative; max-width: 700px; margin: 0 auto; padding: 0.5rem 1rem; transition: all 0.2s ease-in-out; + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 10; } .nav_menu { @@ -172,6 +176,7 @@ } .divider { + display: none; height: 2px; background: linear-gradient(0deg, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)), linear-gradient(45deg, #ffbe0b 0%, #fb5607 100%); @@ -209,11 +214,14 @@ @media (min-width: 768px) { .divider { + display: block; margin-top: 1rem; } .nav_bar { + margin-top: 0.5em; padding: 4px 0; + position: relative; } .nav_menu { diff --git a/apps/pay/components/layouts/username-layout.tsx b/apps/pay/components/layouts/username-layout.tsx index eba6d214dd5..6fc31c164a0 100644 --- a/apps/pay/components/layouts/username-layout.tsx +++ b/apps/pay/components/layouts/username-layout.tsx @@ -8,6 +8,8 @@ import { Image, OverlayTrigger, Tooltip } from "react-bootstrap" import { getClientSidePayDomain } from "../../config/config" +import { Header } from "../sidebar" + import styles from "./app-layout.module.css" type Props = { @@ -17,33 +19,6 @@ type Props = { const UsernameLayoutContainer = ({ children, username }: Props) => { const router = useRouter() - const searchParams = useSearchParams() - const memo = searchParams.get("memo") - const [openSideBar, setOpenSideBar] = React.useState(false) - const [copied, setCopied] = React.useState(false) - const [isClient, setIsClient] = useState(false) - - useEffect(() => { - setIsClient(true) - }, []) - - const lightningAddr = username - ? `${username?.toString().toLowerCase()}@${getClientSidePayDomain()}` - : "" - - const cashRegisterLink = username ? `/${username}` : "#" - const payCodeLink = username ? `/${username}/print?memo=${memo}` : "#" - const copyToClipboard = () => { - copy(lightningAddr) - setCopied(true) - setTimeout(() => { - setCopied(false) - }, 2000) - } - - const closeSideBar = () => { - setOpenSideBar(false) - } const navigateHome = () => { let pathname = "/" @@ -55,124 +30,16 @@ const UsernameLayoutContainer = ({ children, username }: Props) => { } return ( -
+ <>
-
- {children} -
-
+ {children} + ) } diff --git a/apps/pay/components/memo/index.tsx b/apps/pay/components/memo/index.tsx index 78279368e22..bc6bfdd14d4 100644 --- a/apps/pay/components/memo/index.tsx +++ b/apps/pay/components/memo/index.tsx @@ -15,37 +15,23 @@ interface Props { const Memo = ({ state, dispatch }: Props) => { const searchParams = useSearchParams() const amount = searchParams.get("amount") || "0" - const sats = searchParams.get("sats") || "0" - const display = searchParams.get("display") || "USD" + const displayCurrency = searchParams.get("displayCurrency") || "USD" const memo = searchParams.get("memo") || "" - const unit = searchParams.get("unit") const [openModal, setOpenModal] = React.useState(false) const [currentMemo, setCurrentMemo] = React.useState(memo?.toString() || "") const handleSetMemo = () => { - if (unit === "SAT" || unit === "CENT") { - const params = new URLSearchParams({ - amount, - sats, - unit, - memo: currentMemo, - display, - }) + const params = new URLSearchParams({ + amount, + memo: currentMemo, + displayCurrency, + }) - const currentUrl = new URL(window.location.toString()) - currentUrl.search = params.toString() - window.history.pushState({}, "", currentUrl.toString()) - } else { - const params = new URLSearchParams({ - memo: currentMemo, - display, - }) + const currentUrl = new URL(window.location.toString()) + currentUrl.search = params.toString() + window.history.pushState({}, "", currentUrl.toString()) - const currentUrl = new URL(window.location.toString()) - currentUrl.search = params.toString() - window.history.pushState({}, "", currentUrl.toString()) - } handleClose() } diff --git a/apps/pay/components/parse-pos-payment/index.tsx b/apps/pay/components/parse-pos-payment/index.tsx index ede009ca3e1..309558a6e8c 100644 --- a/apps/pay/components/parse-pos-payment/index.tsx +++ b/apps/pay/components/parse-pos-payment/index.tsx @@ -6,31 +6,19 @@ import Image from "react-bootstrap/Image" import CurrencyInput, { formatValue } from "react-currency-input-field" -import useRealtimePrice from "../../lib/use-realtime-price" import { ACTION_TYPE, ACTIONS } from "../../app/reducer" -import { - formatOperand, - safeAmount, - getLocaleConfig, - extractSearchParams, -} from "../../utils/utils" -import Memo from "../memo" +import { safeAmount, getLocaleConfig, extractSearchParams } from "../../utils/utils" import { useDisplayCurrency } from "../../lib/use-display-currency" -import { Currency } from "../../lib/graphql/generated" +import Memo from "../memo" import DigitButton from "./digit-button" import styles from "./parse-payment.module.css" import ReceiveInvoice from "./receive-invoice" import NFCComponent from "./nfc" -function isRunningStandalone() { - if (typeof window === "undefined") { - return false - } - return window.matchMedia("(display-mode: standalone)").matches -} +import { satsCurrencyMetadata } from "@/app/sats-currency" interface Props { defaultWalletCurrency: string @@ -40,26 +28,6 @@ interface Props { username: string } -interface UpdateAmount { - shouldUpdate: boolean - value: string | null -} - -export enum AmountUnit { - Sat = "SAT", - Cent = "CENT", // TODO: eventually depreciate this for Fiat, but don't want to break existing POS links - Fiat = "FIAT", -} - -const defaultCurrencyMetadata: Currency = { - id: "USD", - flag: "🇺🇸", - name: "US Dollar", - symbol: "$", - fractionDigits: 2, - __typename: "Currency", -} - function ParsePayment({ defaultWalletCurrency, walletId, @@ -69,149 +37,63 @@ function ParsePayment({ }: Props) { const router = useRouter() const searchParams = useSearchParams() - const { amount, sats, unit, memo } = extractSearchParams(searchParams) - - const display = searchParams?.get("display") ?? localStorage.getItem("display") ?? "USD" - const { currencyToSats, satsToCurrency, hasLoaded } = useRealtimePrice(display) const { currencyList } = useDisplayCurrency() - const [valueInFiat, setValueInFiat] = React.useState(0) - const [valueInSats, setValueInSats] = React.useState(0) - const [exchangeRateFormatted, setExchangeRateFormatted] = React.useState("$0") - const [currentAmount, setCurrentAmount] = React.useState(state.currentAmount) - const [currencyMetadata, setCurrencyMetadata] = React.useState( - defaultCurrencyMetadata, - ) - const [numOfChanges, setNumOfChanges] = React.useState(0) + const memo = searchParams?.get("memo") + const displayCurrency = + searchParams?.get("displayCurrency") ?? localStorage.getItem("display") ?? "USD" + + const currencyMetadata = state.displayCurrencyMetaData const language = typeof navigator !== "undefined" ? navigator?.language : "en" - const prevUnit = React.useRef(AmountUnit.Cent) - // onload // set all query params on first load, even if they are not passed useEffect(() => { - const initialUnit = unit ?? "CENT" // TODO: eventually depreciate CENT for Fiat, but don't want to break existing POS links - const initialAmount = safeAmount(amount).toString() - const initialSats = safeAmount(sats).toString() - const initialDisplay = display ?? localStorage.getItem("display") ?? "USD" - const initialUsername = username + const initialAmount = safeAmount(state.currentAmount).toString() + const initialDisplay = displayCurrency const initialQuery = extractSearchParams(searchParams) - delete initialQuery?.currency const newQuery = { amount: initialAmount, - sats: initialSats, - unit: initialUnit, memo: memo ?? "", - display: initialDisplay, - username: initialUsername, + displayCurrency: initialDisplay, } if (initialQuery !== newQuery) { const params = new URLSearchParams({ amount: initialAmount, - sats: initialSats, - unit: initialUnit, memo: memo ?? "", - display: initialDisplay, - currency: defaultWalletCurrency, + displayCurrency: initialDisplay, }) const newUrl = new URL(window.location.toString()) newUrl.pathname = `/${username}` newUrl.search = params.toString() - router.replace(newUrl.toString(), { scroll: true, }) } - // this only runs once // eslint-disable-next-line react-hooks/exhaustive-deps }, []) - const updateCurrentAmountWithParams = React.useCallback((): UpdateAmount => { - if (unit === AmountUnit.Sat) { - if (sats === currentAmount) { - return { - shouldUpdate: false, - value: null, - } - } else if (sats) { - return { - shouldUpdate: true, - value: sats?.toString(), - } - } - } else { - if (Number(amount) === Number(currentAmount)) { - return { shouldUpdate: false, value: null } - } else if (amount) { - return { shouldUpdate: true, value: amount.toString() } - } - } - return { shouldUpdate: false, value: null } - }, [amount, sats, unit, currentAmount]) - - const toggleCurrency = () => { - const newUnit = unit === AmountUnit.Sat ? AmountUnit.Cent : AmountUnit.Sat - prevUnit.current = (unit as AmountUnit) || AmountUnit.Cent - const params = new URLSearchParams({ - currency: defaultWalletCurrency, - unit: newUnit, - memo, - display, - amount, - sats, - }) - - const newUrl = new URL(window.location.toString()) - newUrl.pathname = `/${username}` - newUrl.search = params.toString() - router.replace(newUrl.toString()) - } - // Update Params From Current Amount const handleAmountChange = (skipRouterPush?: boolean) => { - calculateExchangeRate() - if (!unit || (currentAmount === "" && numOfChanges === 0)) return - setNumOfChanges(numOfChanges + 1) - - // 1) format the fiat amount - const { convertedCurrencyAmount } = satsToCurrency( - currentAmount, - display, - currencyMetadata.fractionDigits, - ) - let amt = unit === AmountUnit.Sat ? convertedCurrencyAmount : currentAmount - if (unit === AmountUnit.Sat || currencyMetadata.fractionDigits === 0) { - const safeAmt = safeAmount(amt) - amt = + let amount = state.currentAmount + if (currencyMetadata.fractionDigits === 0) { + const safeAmt = safeAmount(amount) + amount = currencyMetadata.fractionDigits === 0 ? safeAmt.toFixed() : safeAmt.toFixed(currencyMetadata.fractionDigits) } - if (isNaN(Number(amt))) return + if (isNaN(Number(amount))) return const formattedValue = formatValue({ - value: amt, - intlConfig: { locale: language, currency: display }, + value: amount, + intlConfig: { locale: language, currency: displayCurrency }, }) localStorage.setItem("formattedFiatValue", formattedValue) - setValueInFiat(amt) - - // 2) format the sats amount - let satsAmt = - unit === AmountUnit.Sat - ? currentAmount - : currencyToSats(Number(currentAmount), display, currencyMetadata.fractionDigits) - .convertedCurrencyAmount - satsAmt = safeAmount(satsAmt).toFixed() - localStorage.setItem("formattedSatsValue", `${formatOperand(satsAmt)} sats`) - setValueInSats(satsAmt) // 3) update the query params const newQuery = { - amount: amt, - sats: satsAmt, - currency: defaultWalletCurrency, - unit, - memo, - display, + amount: state.currentAmount, + memo: "", + displayCurrency, } const initialQuery = extractSearchParams(searchParams) @@ -222,143 +104,46 @@ function ParsePayment({ router.replace(newUrl.toString()) } } - // eslint-disable-next-line react-hooks/exhaustive-deps - React.useEffect(handleAmountChange, [currentAmount, hasLoaded.current]) - - React.useEffect(() => { - setCurrentAmount(state.currentAmount) - }, [state.currentAmount]) - // Toggle Current Amount - React.useEffect(() => { - if (!unit || unit === prevUnit.current) return - if (unit === AmountUnit.Cent) { - const { convertedCurrencyAmount } = currencyToSats( - Number(amount), - display, - currencyMetadata.fractionDigits, - ) - dispatch({ - type: ACTIONS.SET_AMOUNT_FROM_PARAMS, - payload: convertedCurrencyAmount.toString(), - }) - } - if (unit === AmountUnit.Sat) { - const { convertedCurrencyAmount } = satsToCurrency( - Number(sats), - display, - currencyMetadata.fractionDigits, - ) - dispatch({ - type: ACTIONS.SET_AMOUNT_FROM_PARAMS, - payload: convertedCurrencyAmount?.toString(), - }) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [unit]) + React.useEffect(handleAmountChange, [state.currentAmount]) // Update CurrencyMetadata React.useEffect(() => { - const latestCurrencyMetadata = currencyList?.find((c) => c.id === display) - if (latestCurrencyMetadata) { - setCurrencyMetadata(latestCurrencyMetadata) - } - }, [display, currencyList]) - - // Update Current Amount From Params - React.useEffect(() => { - if (!unit || !sats || !amount) return - const { shouldUpdate, value } = updateCurrentAmountWithParams() - if (shouldUpdate && value) { + if (displayCurrency === "SAT") { dispatch({ - type: ACTIONS.SET_AMOUNT_FROM_PARAMS, - payload: value?.toString(), + type: ACTIONS.UPDATE_DISPLAY_CURRENCY_METADATA, + payload: satsCurrencyMetadata, }) + } else { + const latestCurrencyMetadata = currencyList?.find((c) => c.id === displayCurrency) + if (latestCurrencyMetadata) { + dispatch({ + type: ACTIONS.UPDATE_DISPLAY_CURRENCY_METADATA, + payload: latestCurrencyMetadata, + }) + } } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [amount, sats, unit, dispatch]) - - const calculateExchangeRate = React.useCallback(() => { - const { formattedCurrency } = satsToCurrency( - 100_000_000, // 1 BTC - display, - currencyMetadata.fractionDigits, - ) - setExchangeRateFormatted(formattedCurrency) - }, [currencyMetadata.fractionDigits, display, satsToCurrency]) + }, [displayCurrency, currencyList]) return (
- {!state.createdInvoice && !isRunningStandalone() && ( - - )} -
- -
-
- {unit === "CENT" ? "≈" : ""} {formatOperand(valueInSats.toString())} sats - {!hasLoaded.current && ( - - )} -
- {state.createdInvoice ? null : ( - - )} -
- -
- - {exchangeRateFormatted} / BTC - +
- - {state.createdInvoice ? ( @@ -419,7 +204,10 @@ function ParsePayment({ if (state.createdInvoice) { dispatch({ type: ACTIONS.CREATE_NEW_INVOICE }) } else { - dispatch({ type: ACTIONS.CREATE_INVOICE, payload: amount?.toString() }) + dispatch({ + type: ACTIONS.CREATE_INVOICE, + payload: state.currentAmount, + }) } }} > diff --git a/apps/pay/components/parse-pos-payment/parse-payment.module.css b/apps/pay/components/parse-pos-payment/parse-payment.module.css index 0b857423fab..6c3c6d6da3d 100644 --- a/apps/pay/components/parse-pos-payment/parse-payment.module.css +++ b/apps/pay/components/parse-pos-payment/parse-payment.module.css @@ -1,5 +1,5 @@ .digits_container { - margin-top: 2rem; + margin-top: 1rem; } .output { @@ -100,7 +100,6 @@ align-items: center; justify-content: center; column-gap: 0.5rem; - margin-top: 2rem; } .pay_btn, @@ -117,13 +116,13 @@ border: none; outline: none; padding: 10px 32px; - border-radius: 6px; + border-radius: 10em; order: 2; } .pay_new_btn { background-color: transparent; - border-radius: 10px; + border-radius: 10em; width: 327px; height: 50px; margin-bottom: 1rem; @@ -131,14 +130,14 @@ .clear_btn { position: relative; - background-color: #fff; + background-color: #eaeaea; color: #232222; display: flex; justify-content: center; align-items: center; column-gap: 10px; border: none; - border-radius: 8px; + border-radius: 10em; outline: none; font-weight: 600; padding: 10px 12px; @@ -146,28 +145,6 @@ transition: all 0.5s ease; } -.clear_btn::before { - content: ""; - position: absolute; - top: -1.5px; - left: -2px; - right: -2px; - bottom: -2px; - background: linear-gradient(0deg, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)), - linear-gradient(45deg, #ffbe0b 0%, #fb5607 100%); - background-size: 100% 100%; - background-repeat: no-repeat; - z-index: -1; - transition: background-size 0.25s ease; - border-radius: 10px; -} - -.clear_btn:hover, -.clear_btn:focus, -.clear_btn:focus-visible { - border: 1px solid rgb(233, 233, 236); -} - @media (min-width: 760px) { .pay_btn { width: 327px; @@ -262,6 +239,7 @@ grid-template-rows: 1fr 1fr; align-items: center; justify-content: space-between; + padding: 0.3em 1em; } .qr_clipboard > button { diff --git a/apps/pay/components/parse-pos-payment/receive-invoice.tsx b/apps/pay/components/parse-pos-payment/receive-invoice.tsx index 8275cefaaf5..30494c4cbc0 100644 --- a/apps/pay/components/parse-pos-payment/receive-invoice.tsx +++ b/apps/pay/components/parse-pos-payment/receive-invoice.tsx @@ -24,6 +24,8 @@ import LoadingComponent from "../loading" import styles from "./parse-payment.module.css" import NFCComponent from "./nfc" +import useRealtimePrice from "@/lib/use-realtime-price" + interface Props { recipientWalletCurrency?: string walletId: string | undefined @@ -39,8 +41,9 @@ function ReceiveInvoice({ recipientWalletCurrency, walletId, state, dispatch }: const searchParams = useSearchParams() const { username } = useParams() const query = extractSearchParams(searchParams) - const { amount, unit, sats, memo } = query + const { amount, memo, displayCurrency } = query + const { currencyToSats } = useRealtimePrice("USD") const { usdToSats, satsToUsd } = useSatPrice() const [progress, setProgress] = React.useState(PROGRESS_BAR_MAX_WIDTH) @@ -56,12 +59,12 @@ function ReceiveInvoice({ recipientWalletCurrency, walletId, state, dispatch }: const getImage = () => takeScreenShot(qrImageRef.current) const shareUrl = - !amount && !unit && !memo + !amount && !memo ? `https://${getClientSidePayDomain()}/${username}?amount=${ state.currentAmount }&sats=${usdToSats( state.currentAmount, - ).toFixed()}¤cy=${recipientWalletCurrency}&unit=SAT&memo=""` + ).toFixed()}¤cy=${recipientWalletCurrency}&memo=""` : window.location.href const shareData = { @@ -114,11 +117,16 @@ function ReceiveInvoice({ recipientWalletCurrency, walletId, state, dispatch }: ) const paymentAmount = React.useMemo(() => { - if (!query.sats || typeof query.sats !== "string") { - alert("No sats amount provided") - return + let amountInSats = state.currentAmount + if (displayCurrency !== "SAT") { + ;({ convertedCurrencyAmount: amountInSats } = currencyToSats( + Number(state.currentAmount), + "USD", + 2, + )) } - let amt = safeAmount(query.sats) + + let amt = safeAmount(amountInSats) if (recipientWalletCurrency === "USD") { const usdAmount = satsToUsd(Number(amt)) if (isNaN(usdAmount)) return @@ -127,35 +135,31 @@ function ReceiveInvoice({ recipientWalletCurrency, walletId, state, dispatch }: } if (amt === null) return return safeAmount(amt).toString() - }, [ - amount, - unit, - sats, - usdToSats, - satsToUsd, - state.currentAmount, - recipientWalletCurrency, - ]) + }, [amount, usdToSats, satsToUsd, state.currentAmount, recipientWalletCurrency]) React.useEffect(() => { + let amountInSats = state.currentAmount + if (displayCurrency !== "SAT") { + ;({ convertedCurrencyAmount: amountInSats } = currencyToSats( + Number(state.currentAmount), + "USD", + 2, + )) + } + if (!walletId || !Number(paymentAmount)) return let amt = paymentAmount if (recipientWalletCurrency === "USD") { - if (!query.sats || typeof query.sats !== "string") { - alert("No sats amount provided") + const usdAmount = satsToUsd(Number(amountInSats)) + if (isNaN(usdAmount)) return + const cents = parseFloat(usdAmount.toFixed(2)) * 100 + amt = cents.toFixed() + if (cents < 0.01) { + setExpiredInvoiceError( + `Amount is too small. Must be larger than ${usdToSats(0.01).toFixed()} sats`, + ) return - } else { - const usdAmount = satsToUsd(Number(query.sats)) - if (isNaN(usdAmount)) return - const cents = parseFloat(usdAmount.toFixed(2)) * 100 - amt = cents.toFixed() - if (cents < 0.01) { - setExpiredInvoiceError( - `Amount is too small. Must be larger than ${usdToSats(0.01).toFixed()} sats`, - ) - return - } } } if (amt === null) return diff --git a/apps/pay/components/sheet/index.tsx b/apps/pay/components/sheet/index.tsx new file mode 100644 index 00000000000..8d0a3cf6266 --- /dev/null +++ b/apps/pay/components/sheet/index.tsx @@ -0,0 +1,127 @@ +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "../utils" + +const Sheet = SheetPrimitive.Root + +const SheetTrigger = SheetPrimitive.Trigger + +const SheetClose = SheetPrimitive.Close + +const SheetPortal = SheetPrimitive.Portal + +const SheetOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetOverlay.displayName = SheetPrimitive.Overlay.displayName + +const sheetVariants = cva( + "fixed z-50 gap-4 bg-white p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500", + { + variants: { + side: { + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, + }, +) + +interface SheetContentProps + extends React.ComponentPropsWithoutRef, + VariantProps {} + +const SheetContent = React.forwardRef< + React.ElementRef, + SheetContentProps +>(({ side = "right", className, children, ...props }, ref) => ( + + + + {children} + + XClose + + + +)) +SheetContent.displayName = SheetPrimitive.Content.displayName + +const SheetHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +SheetHeader.displayName = "SheetHeader" + +const SheetFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +SheetFooter.displayName = "SheetFooter" + +const SheetTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetTitle.displayName = SheetPrimitive.Title.displayName + +const SheetDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetDescription.displayName = SheetPrimitive.Description.displayName + +export { + Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/apps/pay/components/sidebar/index.tsx b/apps/pay/components/sidebar/index.tsx new file mode 100644 index 00000000000..d0aeea59324 --- /dev/null +++ b/apps/pay/components/sidebar/index.tsx @@ -0,0 +1,133 @@ +"use client" + +import { usePathname } from "next/navigation" + +import Image from "next/image" + +import Link from "next/link" + +import CurrencyDropdown from "../currency/currency-dropdown" +import { Sheet, SheetClose, SheetContent, SheetTrigger } from "../sheet" +import PinToHomescreen from "../pin-to-homescreen" + +import { useInvoiceContext } from "@/context/invoice-context" +import { ACTIONS } from "@/app/reducer" + +function updateCurrencyAndReload(newDisplayCurrency: string): void { + localStorage.setItem("displayCurrency", newDisplayCurrency) + + const currentURL = new URL(window.location.toString()) + const searchParams = new URLSearchParams(window.location.search) + searchParams.set("displayCurrency", newDisplayCurrency) + currentURL.search = searchParams.toString() + + window.history.pushState({}, "", currentURL.toString()) + setTimeout(() => { + window.location.reload() + }, 100) +} + +export function Header({ username }: { username: string }) { + const pathName = usePathname() + const { state, dispatch } = useInvoiceContext() + const Links = [ + { + name: "Point of Sale", + href: `/${username}`, + }, + { + name: "print", + href: `/${username}/print`, + }, + ] + + async function shareCurrentUrl() { + try { + await navigator.share({ url: window.location.href }) + } catch (error) { + console.error("Error sharing the URL", error) + } + } + + return ( + <> + + + + + + +
+ {Links.map((link) => + pathName === link.href ? ( + + {link.name} + + ) : ( + + + {link.name} + + + ), + )} + +
+ +
+ +
+ + + + +
+
+
+
+ + ) +} diff --git a/apps/pay/components/utils.ts b/apps/pay/components/utils.ts new file mode 100644 index 00000000000..bd0c391ddd1 --- /dev/null +++ b/apps/pay/components/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/apps/pay/context/invoice-context.tsx b/apps/pay/context/invoice-context.tsx new file mode 100644 index 00000000000..bd9d077b758 --- /dev/null +++ b/apps/pay/context/invoice-context.tsx @@ -0,0 +1,56 @@ +"use client" +import React, { createContext, useContext, useReducer, ReactNode } from "react" + +import reducer from "@/app/reducer" +import { defaultCurrencyMetadata } from "@/app/currency-metadata" +import { Currency } from "@/lib/graphql/generated" + +type InvoiceState = { + currentAmount: string + username: string + walletCurrency: string + walletId: string + createdInvoice: boolean + pinnedToHomeScreenModalVisible: boolean + memo: string + //TOD0 can create a separate context for display currency + displayCurrencyMetaData: Currency +} + +const InvoiceContext = createContext<{ + state: InvoiceState + dispatch: React.Dispatch +}>({ + state: { + currentAmount: "0", + username: "", + walletCurrency: "", + walletId: "", + createdInvoice: false, + pinnedToHomeScreenModalVisible: false, + memo: "", + displayCurrencyMetaData: defaultCurrencyMetadata, + }, + dispatch: () => null, +}) + +export const InvoiceProvider: React.FC<{ + children: ReactNode + initialState: InvoiceState +}> = ({ children, initialState }) => { + const [state, dispatch] = useReducer(reducer, initialState) + + return ( + + {children} + + ) +} + +export const useInvoiceContext = () => { + const context = useContext(InvoiceContext) + if (context === undefined) { + throw new Error("useInvoiceContext must be used within an InvoiceProvider") + } + return context +} diff --git a/apps/pay/package.json b/apps/pay/package.json index 28a327aa2cd..e11c53da7c2 100644 --- a/apps/pay/package.json +++ b/apps/pay/package.json @@ -15,11 +15,15 @@ "@apollo/client": "^3.7.12", "@apollo/experimental-nextjs-app-support": "^0.8.0", "@galoymoney/client": "^0.2.2", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-slot": "^1.0.2", "@t3-oss/env-nextjs": "^0.6.1", "bech32": "^2.0.0", "bitcoinjs-lib": "5.0.5", "bolt11": "1.4.1", "bootstrap": "^4.5.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", "copy-to-clipboard": "^3.3.2", "graphql": "^16.6.0", "graphql-ws": "^5.14.0", @@ -37,6 +41,8 @@ "react-qrcode-logo": "^2.9.0", "react-to-print": "^2.14.12", "ssr": "link:@apollo/experimental-nextjs-app-support/ssr", + "tailwind-merge": "^2.1.0", + "tailwindcss-animate": "^1.0.7", "use-debounce": "^8.0.4", "use-react-screenshot": "^3.0.0", "zod": "^3.22.4" @@ -60,6 +66,7 @@ "@types/react-lottie": "^1.2.6", "@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/parser": "^5.51.0", + "autoprefixer": "^10.4.17", "cypress": "^13.6.1", "eslint": "^8.52.0", "eslint-config-next": "14.1.0", @@ -72,8 +79,10 @@ "eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-testing-library": "^6.2.0", "eslint-webpack-plugin": "^3.0.1", + "postcss": "^8.4.35", "prettier": "^2.4.1", "react-dev-utils": "^12.0.1", + "tailwindcss": "^3.4.1", "ts-pnp": "1.2.0", "typescript": "5.2.2" }, diff --git a/apps/pay/postcss.config.js b/apps/pay/postcss.config.js new file mode 100644 index 00000000000..33ad091d26d --- /dev/null +++ b/apps/pay/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/apps/pay/tailwind.config.ts b/apps/pay/tailwind.config.ts new file mode 100644 index 00000000000..9823b1c69a2 --- /dev/null +++ b/apps/pay/tailwind.config.ts @@ -0,0 +1,20 @@ +import type { Config } from "tailwindcss" + +const config: Config = { + content: [ + "./pages/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + "./app/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + backgroundImage: { + "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", + "gradient-conic": + "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +} +export default config diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6dd89da91e..0e9ee97c199 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -577,6 +577,12 @@ importers: '@galoymoney/client': specifier: ^0.2.2 version: 0.2.6(@bitcoinerlab/secp256k1@1.1.1)(bitcoinjs-lib@5.0.5)(bolt11@1.4.1)(lnurl-pay@1.0.1)(url@0.11.3) + '@radix-ui/react-dialog': + specifier: ^1.0.5 + version: 1.0.5(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.2.45)(react@18.2.0) '@t3-oss/env-nextjs': specifier: ^0.6.1 version: 0.6.1(typescript@5.2.2)(zod@3.22.4) @@ -592,6 +598,12 @@ importers: bootstrap: specifier: ^4.5.2 version: 4.6.2(jquery@3.7.1)(popper.js@1.16.1) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.0.0 + version: 2.0.0 copy-to-clipboard: specifier: ^3.3.2 version: 3.3.3 @@ -643,6 +655,12 @@ importers: ssr: specifier: link:@apollo/experimental-nextjs-app-support/ssr version: link:@apollo/experimental-nextjs-app-support/ssr + tailwind-merge: + specifier: ^2.1.0 + version: 2.1.0 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.1) use-debounce: specifier: ^8.0.4 version: 8.0.4(react@18.2.0) @@ -707,6 +725,9 @@ importers: '@typescript-eslint/parser': specifier: ^5.51.0 version: 5.62.0(eslint@8.54.0)(typescript@5.2.2) + autoprefixer: + specifier: ^10.4.17 + version: 10.4.17(postcss@8.4.35) cypress: specifier: ^13.6.1 version: 13.6.1 @@ -743,12 +764,18 @@ importers: eslint-webpack-plugin: specifier: ^3.0.1 version: 3.2.0(eslint@8.54.0)(webpack@5.90.1) + postcss: + specifier: ^8.4.35 + version: 8.4.35 prettier: specifier: ^2.4.1 version: 2.8.8 react-dev-utils: specifier: ^12.0.1 version: 12.0.1(eslint@8.54.0)(typescript@5.2.2)(webpack@5.90.1) + tailwindcss: + specifier: ^3.4.1 + version: 3.4.1 ts-pnp: specifier: 1.2.0 version: 1.2.0(typescript@5.2.2) @@ -7290,7 +7317,7 @@ packages: '@graphql-tools/utils': 8.9.0(graphql@16.8.1) dataloader: 2.1.0 graphql: 16.8.1 - tslib: 2.4.1 + tslib: 2.6.2 value-or-promise: 1.0.11 dev: false @@ -7984,7 +8011,7 @@ packages: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: graphql: 16.8.1 - tslib: 2.5.3 + tslib: 2.6.2 dev: true /@graphql-tools/optimize@2.0.0(graphql@16.8.1): @@ -8136,7 +8163,7 @@ packages: '@ardatan/relay-compiler': 12.0.0(graphql@16.8.1) '@graphql-tools/utils': 9.2.1(graphql@16.8.1) graphql: 16.8.1 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - encoding - supports-color @@ -8151,7 +8178,7 @@ packages: '@ardatan/relay-compiler': 12.0.0(graphql@16.8.1) '@graphql-tools/utils': 10.0.11(graphql@16.8.1) graphql: 16.8.1 - tslib: 2.5.3 + tslib: 2.6.2 transitivePeerDependencies: - encoding - supports-color @@ -8356,7 +8383,7 @@ packages: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: graphql: 16.8.1 - tslib: 2.4.1 + tslib: 2.6.2 /@graphql-tools/utils@9.2.1(graphql@16.8.1): resolution: {integrity: sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==} @@ -10952,7 +10979,6 @@ packages: '@babel/runtime': 7.23.7 '@types/react': 18.2.45 react: 18.2.0 - dev: true /@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.14)(@types/react@18.2.31)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} @@ -10988,6 +11014,40 @@ packages: react-remove-scroll: 2.5.5(@types/react@18.2.31)(react@18.2.0) dev: false + /@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@types/react': 18.2.45 + '@types/react-dom': 18.2.14 + aria-hidden: 1.2.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.45)(react@18.2.0) + dev: false + /@radix-ui/react-direction@1.0.1(@types/react@18.2.45)(react@18.2.0): resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: @@ -11052,6 +11112,31 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.45)(react@18.2.0) + '@types/react': 18.2.45 + '@types/react-dom': 18.2.14 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.31)(react@18.2.0): resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: @@ -11078,7 +11163,6 @@ packages: '@babel/runtime': 7.23.7 '@types/react': 18.2.45 react: 18.2.0 - dev: true /@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} @@ -11126,6 +11210,29 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.7 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@types/react': 18.2.45 + '@types/react-dom': 18.2.14 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-id@1.0.1(@types/react@18.2.31)(react@18.2.0): resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: @@ -11154,7 +11261,6 @@ packages: '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.45)(react@18.2.0) '@types/react': 18.2.45 react: 18.2.0 - dev: true /@radix-ui/react-popper@1.1.2(@types/react-dom@18.2.17)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} @@ -11228,6 +11334,27 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.7 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.45 + '@types/react-dom': 18.2.14 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.14)(@types/react@18.2.31)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: @@ -11250,6 +11377,28 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.7 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.45)(react@18.2.0) + '@types/react': 18.2.45 + '@types/react-dom': 18.2.14 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.14)(@types/react@18.2.31)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -11271,6 +11420,27 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.14)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.7 + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.45)(react@18.2.0) + '@types/react': 18.2.45 + '@types/react-dom': 18.2.14 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -11515,7 +11685,6 @@ packages: '@babel/runtime': 7.23.7 '@types/react': 18.2.45 react: 18.2.0 - dev: true /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.31)(react@18.2.0): resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} @@ -11545,7 +11714,6 @@ packages: '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.45)(react@18.2.0) '@types/react': 18.2.45 react: 18.2.0 - dev: true /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.31)(react@18.2.0): resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} @@ -11575,7 +11743,6 @@ packages: '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.45)(react@18.2.0) '@types/react': 18.2.45 react: 18.2.0 - dev: true /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.31)(react@18.2.0): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} @@ -11603,7 +11770,6 @@ packages: '@babel/runtime': 7.23.7 '@types/react': 18.2.45 react: 18.2.0 - dev: true /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.45)(react@18.2.0): resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} @@ -16130,8 +16296,8 @@ packages: peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.22.3 - caniuse-lite: 1.0.30001585 + browserslist: 4.22.2 + caniuse-lite: 1.0.30001572 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -16155,6 +16321,22 @@ packages: postcss-value-parser: 4.2.0 dev: true + /autoprefixer@10.4.17(postcss@8.4.35): + resolution: {integrity: sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.22.3 + caniuse-lite: 1.0.30001587 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.35 + postcss-value-parser: 4.2.0 + dev: true + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} @@ -16855,7 +17037,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001585 + caniuse-lite: 1.0.30001587 electron-to-chromium: 1.4.659 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.3) @@ -17009,7 +17191,7 @@ packages: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} dependencies: pascal-case: 3.1.2 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /camelcase-css@2.0.1: @@ -17036,19 +17218,14 @@ packages: /caniuse-lite@1.0.30001572: resolution: {integrity: sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==} - /caniuse-lite@1.0.30001585: - resolution: {integrity: sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==} - dev: true - /caniuse-lite@1.0.30001587: resolution: {integrity: sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==} - dev: false /capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case-first: 2.0.2 dev: true @@ -17153,7 +17330,7 @@ packages: path-case: 3.0.4 sentence-case: 3.0.4 snake-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /char-regex@1.0.2: @@ -17213,6 +17390,7 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 + dev: true /chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} @@ -17227,7 +17405,6 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -17558,7 +17735,7 @@ packages: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case: 2.0.2 dev: true @@ -18475,7 +18652,7 @@ packages: dependencies: debug: 4.3.4(supports-color@5.5.0) is-url: 1.2.4 - postcss: 8.4.35 + postcss: 8.4.32 postcss-values-parser: 2.0.1 transitivePeerDependencies: - supports-color @@ -18667,7 +18844,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 /dotenv-expand@10.0.0: resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} @@ -22255,7 +22432,7 @@ packages: resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} dependencies: capital-case: 1.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /help-me@5.0.0: @@ -22951,7 +23128,7 @@ packages: /is-lower-case@2.0.2: resolution: {integrity: sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /is-map@2.0.2: @@ -23128,7 +23305,7 @@ packages: /is-upper-case@2.0.2: resolution: {integrity: sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /is-url-superb@4.0.0: @@ -24774,13 +24951,13 @@ packages: /lower-case-first@2.0.2: resolution: {integrity: sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 /lowercase-keys@1.0.0: resolution: {integrity: sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A==} @@ -25720,7 +25897,7 @@ packages: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 - tslib: 2.4.1 + tslib: 2.6.2 /node-abi@3.54.0: resolution: {integrity: sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==} @@ -26325,7 +26502,7 @@ packages: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /parent-module@1.0.1: @@ -26392,7 +26569,7 @@ packages: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /path-browserify@1.0.1: @@ -26403,7 +26580,7 @@ packages: resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} dependencies: dot-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 dev: true /path-exists@3.0.0: @@ -27753,7 +27930,6 @@ packages: react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.45)(react@18.2.0) tslib: 2.6.2 - dev: true /react-remove-scroll@2.5.5(@types/react@18.2.31)(react@18.2.0): resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} @@ -27791,7 +27967,6 @@ packages: tslib: 2.6.2 use-callback-ref: 1.3.0(@types/react@18.2.45)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.45)(react@18.2.0) - dev: true /react-style-singleton@2.2.1(@types/react@18.2.31)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} @@ -27825,7 +28000,6 @@ packages: invariant: 2.2.4 react: 18.2.0 tslib: 2.6.2 - dev: true /react-to-print@2.14.15(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-SKnwOzU2cJ8eaAkoJO7+gNhvfEDmm+Y34IdcHsjtHioUevUPhprqbVtvNJlZ2JkGJ8ExK2QNWM9pXECTDR5D8w==} @@ -28209,7 +28383,7 @@ packages: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.4.31 + postcss: 8.4.32 source-map: 0.6.1 dev: true @@ -28526,7 +28700,7 @@ packages: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} dependencies: no-case: 3.0.4 - tslib: 2.4.1 + tslib: 2.6.2 upper-case-first: 2.0.2 dev: true @@ -28904,7 +29078,7 @@ packages: /sponge-case@1.0.1: resolution: {integrity: sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /sprintf-js@1.0.3: @@ -29417,7 +29591,7 @@ packages: /swap-case@2.0.2: resolution: {integrity: sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /swc-loader@0.2.3(@swc/core@1.3.105)(webpack@5.89.0): @@ -29490,7 +29664,7 @@ packages: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 - chokidar: 3.5.3 + chokidar: 3.6.0 didyoumean: 1.2.2 dlv: 1.1.3 fast-glob: 3.3.2 @@ -29856,7 +30030,7 @@ packages: /title-case@3.0.3: resolution: {integrity: sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /tmp@0.0.33: @@ -30526,13 +30700,13 @@ packages: /upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /upper-case@2.0.2: resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 dev: true /uri-js@4.4.1: @@ -30605,7 +30779,6 @@ packages: '@types/react': 18.2.45 react: 18.2.0 tslib: 2.6.2 - dev: true /use-debounce@8.0.4(react@18.2.0): resolution: {integrity: sha512-fGqsYQzl8kLHF2QpQSgIwgOgJmnh6j5L6SIzQiHdLfwp3q1egUL3btq5Bg2SJysH6A0ILLgT2IqXZKoNJr0nFw==} @@ -30668,7 +30841,6 @@ packages: detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.6.2 - dev: true /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}