mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 08:42:12 +10:00
chore: merged main
This commit is contained in:
60
packages/lib/client-only/hooks/use-throttle-fn.ts
Normal file
60
packages/lib/client-only/hooks/use-throttle-fn.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
type ThrottleOptions = {
|
||||
leading?: boolean;
|
||||
trailing?: boolean;
|
||||
};
|
||||
|
||||
export function useThrottleFn<T extends (...args: unknown[]) => unknown>(
|
||||
fn: T,
|
||||
ms = 500,
|
||||
options: ThrottleOptions = {},
|
||||
): [(...args: Parameters<T>) => void, boolean, () => void] {
|
||||
const [isThrottling, setIsThrottling] = useState(false);
|
||||
const $isThrottling = useRef(false);
|
||||
|
||||
const $timeout = useRef<NodeJS.Timeout | null>(null);
|
||||
const $lastArgs = useRef<Parameters<T> | null>(null);
|
||||
|
||||
const { leading = true, trailing = true } = options;
|
||||
|
||||
const $setIsThrottling = useCallback((value: boolean) => {
|
||||
$isThrottling.current = value;
|
||||
setIsThrottling(value);
|
||||
}, []);
|
||||
|
||||
const throttledFn = useCallback(
|
||||
(...args: Parameters<T>) => {
|
||||
if (!$isThrottling.current) {
|
||||
$setIsThrottling(true);
|
||||
if (leading) {
|
||||
fn(...args);
|
||||
} else {
|
||||
$lastArgs.current = args;
|
||||
}
|
||||
|
||||
$timeout.current = setTimeout(() => {
|
||||
if (trailing && $lastArgs.current) {
|
||||
fn(...$lastArgs.current);
|
||||
$lastArgs.current = null;
|
||||
}
|
||||
$setIsThrottling(false);
|
||||
}, ms);
|
||||
} else {
|
||||
$lastArgs.current = args;
|
||||
}
|
||||
},
|
||||
[fn, ms, leading, trailing, $setIsThrottling],
|
||||
);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
if ($timeout.current) {
|
||||
clearTimeout($timeout.current);
|
||||
$timeout.current = null;
|
||||
$setIsThrottling(false);
|
||||
$lastArgs.current = null;
|
||||
}
|
||||
}, [$setIsThrottling]);
|
||||
|
||||
return [throttledFn, isThrottling, cancel];
|
||||
}
|
||||
@ -5,19 +5,24 @@ import { useState } from 'react';
|
||||
import { type Messages, setupI18n } from '@lingui/core';
|
||||
import { I18nProvider } from '@lingui/react';
|
||||
|
||||
import type { I18nLocaleData } from '../../constants/i18n';
|
||||
|
||||
export function I18nClientProvider({
|
||||
children,
|
||||
initialLocale,
|
||||
initialLocaleData,
|
||||
initialMessages,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
initialLocale: string;
|
||||
initialLocaleData: I18nLocaleData;
|
||||
initialMessages: Messages;
|
||||
}) {
|
||||
const { lang, locales } = initialLocaleData;
|
||||
|
||||
const [i18n] = useState(() => {
|
||||
return setupI18n({
|
||||
locale: initialLocale,
|
||||
messages: { [initialLocale]: initialMessages },
|
||||
locale: lang,
|
||||
locales: locales,
|
||||
messages: { [lang]: initialMessages },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'server-only';
|
||||
|
||||
import { cookies } from 'next/headers';
|
||||
import { cookies, headers } from 'next/headers';
|
||||
|
||||
import type { I18n, Messages } from '@lingui/core';
|
||||
import { setupI18n } from '@lingui/core';
|
||||
@ -8,19 +8,19 @@ import { setI18n } from '@lingui/react/server';
|
||||
|
||||
import { IS_APP_WEB } from '../../constants/app';
|
||||
import { SUPPORTED_LANGUAGE_CODES } from '../../constants/i18n';
|
||||
import { extractSupportedLanguage } from '../../utils/i18n';
|
||||
import { extractLocaleData } from '../../utils/i18n';
|
||||
|
||||
type SupportedLocales = (typeof SUPPORTED_LANGUAGE_CODES)[number];
|
||||
type SupportedLanguages = (typeof SUPPORTED_LANGUAGE_CODES)[number];
|
||||
|
||||
async function loadCatalog(locale: SupportedLocales): Promise<{
|
||||
async function loadCatalog(lang: SupportedLanguages): Promise<{
|
||||
[k: string]: Messages;
|
||||
}> {
|
||||
const { messages } = await import(
|
||||
`../../translations/${locale}/${IS_APP_WEB ? 'web' : 'marketing'}.js`
|
||||
`../../translations/${lang}/${IS_APP_WEB ? 'web' : 'marketing'}.js`
|
||||
);
|
||||
|
||||
return {
|
||||
[locale]: messages,
|
||||
[lang]: messages,
|
||||
};
|
||||
}
|
||||
|
||||
@ -31,18 +31,18 @@ export const allMessages = catalogs.reduce((acc, oneCatalog) => {
|
||||
return { ...acc, ...oneCatalog };
|
||||
}, {});
|
||||
|
||||
type AllI18nInstances = { [K in SupportedLocales]: I18n };
|
||||
type AllI18nInstances = { [K in SupportedLanguages]: I18n };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
export const allI18nInstances = SUPPORTED_LANGUAGE_CODES.reduce((acc, locale) => {
|
||||
const messages = allMessages[locale] ?? {};
|
||||
export const allI18nInstances = SUPPORTED_LANGUAGE_CODES.reduce((acc, lang) => {
|
||||
const messages = allMessages[lang] ?? {};
|
||||
|
||||
const i18n = setupI18n({
|
||||
locale,
|
||||
messages: { [locale]: messages },
|
||||
locale: lang,
|
||||
messages: { [lang]: messages },
|
||||
});
|
||||
|
||||
return { ...acc, [locale]: i18n };
|
||||
return { ...acc, [lang]: i18n };
|
||||
}, {}) as AllI18nInstances;
|
||||
|
||||
/**
|
||||
@ -50,19 +50,23 @@ export const allI18nInstances = SUPPORTED_LANGUAGE_CODES.reduce((acc, locale) =>
|
||||
*
|
||||
* https://lingui.dev/tutorials/react-rsc#pages-layouts-and-lingui
|
||||
*/
|
||||
export const setupI18nSSR = (overrideLang?: SupportedLocales) => {
|
||||
const lang =
|
||||
overrideLang ||
|
||||
extractSupportedLanguage({
|
||||
cookies: cookies(),
|
||||
});
|
||||
export const setupI18nSSR = () => {
|
||||
const { lang, locales } = extractLocaleData({
|
||||
cookies: cookies(),
|
||||
headers: headers(),
|
||||
});
|
||||
|
||||
// Get and set a ready-made i18n instance for the given language.
|
||||
const i18n = allI18nInstances[lang];
|
||||
|
||||
// Reactivate the i18n instance with the locale for date and number formatting.
|
||||
i18n.activate(lang, locales);
|
||||
|
||||
setI18n(i18n);
|
||||
|
||||
return {
|
||||
lang,
|
||||
locales,
|
||||
i18n,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
export type LocaleContextValue = {
|
||||
locale: string;
|
||||
};
|
||||
|
||||
export const LocaleContext = createContext<LocaleContextValue | null>(null);
|
||||
|
||||
export const useLocale = () => {
|
||||
const context = useContext(LocaleContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('useLocale must be used within a LocaleProvider');
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
export function LocaleProvider({
|
||||
children,
|
||||
locale,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
locale: string;
|
||||
}) {
|
||||
return (
|
||||
<LocaleContext.Provider
|
||||
value={{
|
||||
locale: locale,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</LocaleContext.Provider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user