chore: merged main

This commit is contained in:
Catalin Pit
2024-09-11 08:40:23 +03:00
389 changed files with 19630 additions and 4241 deletions

View 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];
}

View File

@ -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 },
});
});

View File

@ -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,
};
};

View File

@ -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>
);
}