@pmate/account-sdk 0.5.5 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/package.json +35 -28
  2. package/src/api/AccountService.ts +97 -0
  3. package/src/api/Api.ts +99 -0
  4. package/src/api/AppService.ts +71 -0
  5. package/src/api/EntityService.ts +41 -0
  6. package/src/api/ProfileService.ts +133 -0
  7. package/src/api/cacheInMem.ts +73 -0
  8. package/src/api/index.ts +5 -0
  9. package/src/atoms/accountAtom.ts +18 -0
  10. package/src/atoms/accountProfileAtom.ts +13 -0
  11. package/src/atoms/appConfigAtom.ts +24 -0
  12. package/src/atoms/atomWithLoadable.ts +48 -0
  13. package/src/atoms/createProfileAtom.ts +27 -0
  14. package/src/atoms/index.ts +17 -0
  15. package/src/atoms/learningLangAtom.ts +8 -0
  16. package/src/atoms/localStorageAtom.ts +39 -0
  17. package/src/atoms/loginAtom.ts +8 -0
  18. package/src/atoms/motherTongueAtom.ts +8 -0
  19. package/src/atoms/profileAtom.ts +24 -0
  20. package/src/atoms/profileDraftAtom.ts +7 -0
  21. package/src/atoms/profilesAtom.ts +20 -0
  22. package/src/atoms/sessionCheckAtom.ts +10 -0
  23. package/src/atoms/switchProfileAtom.ts +9 -0
  24. package/src/atoms/updateProfileAtom.ts +35 -0
  25. package/src/atoms/uploadAvatarAtom.ts +49 -0
  26. package/src/atoms/userLogoutAtom.ts +8 -0
  27. package/src/atoms/userSettingsAtom.ts +58 -0
  28. package/src/components/AuthProviderV2.tsx +300 -0
  29. package/src/components/Button.tsx +39 -0
  30. package/src/components/Drawer.tsx +80 -0
  31. package/src/components/index.ts +1 -0
  32. package/src/constants.ts +1 -0
  33. package/src/hooks/index.ts +5 -0
  34. package/src/hooks/useAppBackgroundStyle.ts +25 -0
  35. package/src/hooks/useAppConfig.ts +51 -0
  36. package/src/hooks/useAuthApp.ts +165 -0
  37. package/src/hooks/useAuthSnapshot.ts +84 -0
  38. package/src/hooks/useIsAuthenticated.ts +19 -0
  39. package/src/hooks/useProfileStepFlow.ts +78 -0
  40. package/src/i18n/index.ts +59 -0
  41. package/src/index.ts +9 -0
  42. package/src/locales/ar-SA.json +183 -0
  43. package/src/locales/de-DE.json +183 -0
  44. package/src/locales/el-GR.json +183 -0
  45. package/src/locales/en.json +183 -0
  46. package/src/locales/es-ES.json +183 -0
  47. package/src/locales/fi-FI.json +183 -0
  48. package/src/locales/fil-PH.json +183 -0
  49. package/src/locales/fr-FR.json +183 -0
  50. package/src/locales/hi-IN.json +183 -0
  51. package/src/locales/ja-JP.json +183 -0
  52. package/src/locales/ko-KR.json +183 -0
  53. package/src/locales/pt-BR.json +183 -0
  54. package/src/locales/pt-PT.json +183 -0
  55. package/src/locales/ru-RU.json +183 -0
  56. package/src/locales/ta-IN.json +183 -0
  57. package/src/locales/uk-UA.json +183 -0
  58. package/src/locales/zh-CN.json +183 -0
  59. package/src/locales/zh-TW.json +183 -0
  60. package/src/node/index.ts +271 -0
  61. package/src/types/account.types.ts +28 -0
  62. package/src/types/app.ts +22 -0
  63. package/src/types/profile.ts +6 -0
  64. package/src/utils/AccountManagerV2.ts +352 -0
  65. package/src/utils/Redirect.ts +17 -0
  66. package/src/utils/accountStorage.ts +46 -0
  67. package/src/utils/errors.ts +1 -0
  68. package/src/utils/index.ts +11 -0
  69. package/src/utils/location.ts +34 -0
  70. package/src/utils/profileStep.ts +26 -0
  71. package/src/utils/resolveAppId.ts +13 -0
  72. package/src/utils/selectedProfileStorage.ts +46 -0
  73. package/src/utils/tokenStorage.ts +47 -0
  74. package/dist/index.cjs.js +0 -22
  75. package/dist/index.cjs.js.map +0 -1
  76. package/dist/index.d.ts +0 -305
  77. package/dist/index.es.js +0 -8897
  78. package/dist/index.es.js.map +0 -1
@@ -0,0 +1,39 @@
1
+ import React from "react"
2
+
3
+ type ButtonVariant = "primary" | "plain"
4
+
5
+ export interface ButtonProps
6
+ extends React.ButtonHTMLAttributes<HTMLButtonElement> {
7
+ variant?: ButtonVariant
8
+ }
9
+
10
+ const joinClassNames = (...parts: Array<string | false | null | undefined>) =>
11
+ parts.filter(Boolean).join(" ")
12
+
13
+ const baseClassName =
14
+ "inline-flex items-center rounded-md px-3 py-1.5 text-sm font-medium transition-colors"
15
+
16
+ const variantClassName: Record<ButtonVariant, string> = {
17
+ primary: "bg-slate-900 text-white hover:bg-slate-800",
18
+ plain: "border border-slate-200 bg-white text-slate-700 hover:bg-slate-50",
19
+ }
20
+
21
+ export const Button = ({
22
+ variant = "primary",
23
+ className,
24
+ disabled,
25
+ ...props
26
+ }: ButtonProps) => {
27
+ return (
28
+ <button
29
+ {...props}
30
+ disabled={disabled}
31
+ className={joinClassNames(
32
+ baseClassName,
33
+ variantClassName[variant],
34
+ disabled && "cursor-not-allowed opacity-60",
35
+ className,
36
+ )}
37
+ />
38
+ )
39
+ }
@@ -0,0 +1,80 @@
1
+ import React, { useEffect, useState } from "react"
2
+
3
+ type DrawerAnchor = "left" | "right" | "top" | "bottom"
4
+
5
+ export interface DrawerProps {
6
+ open: boolean
7
+ onClose: () => void
8
+ children: React.ReactNode
9
+ anchor?: DrawerAnchor
10
+ className?: string
11
+ overlayClassName?: string
12
+ id?: string
13
+ style?: React.CSSProperties
14
+ }
15
+
16
+ const joinClassNames = (...parts: Array<string | false | null | undefined>) =>
17
+ parts.filter(Boolean).join(" ")
18
+
19
+ const positionClassMap: Record<DrawerAnchor, string> = {
20
+ left: "left-0 top-0 h-full",
21
+ right: "right-0 top-0 h-full",
22
+ top: "left-0 top-0 w-full",
23
+ bottom: "bottom-0 left-0 w-full",
24
+ }
25
+
26
+ const hiddenTransformMap: Record<DrawerAnchor, string> = {
27
+ left: "-translate-x-full",
28
+ right: "translate-x-full",
29
+ top: "-translate-y-full",
30
+ bottom: "translate-y-full",
31
+ }
32
+
33
+ export const Drawer = ({
34
+ open,
35
+ onClose,
36
+ children,
37
+ anchor = "right",
38
+ className,
39
+ overlayClassName,
40
+ id,
41
+ style,
42
+ }: DrawerProps) => {
43
+ const [mounted, setMounted] = useState(open)
44
+
45
+ useEffect(() => {
46
+ if (open) {
47
+ setMounted(true)
48
+ }
49
+ }, [open])
50
+
51
+ const handleTransitionEnd = () => {
52
+ if (!open) {
53
+ setMounted(false)
54
+ }
55
+ }
56
+
57
+ if (!mounted) return null
58
+
59
+ return (
60
+ <div
61
+ id={id}
62
+ className={joinClassNames("fixed inset-0 z-[1002]", overlayClassName)}
63
+ onClick={onClose}
64
+ >
65
+ <div
66
+ className={joinClassNames(
67
+ "absolute bg-white transition-transform duration-300",
68
+ positionClassMap[anchor],
69
+ open ? "translate-x-0 translate-y-0" : hiddenTransformMap[anchor],
70
+ className,
71
+ )}
72
+ style={style}
73
+ onClick={(event) => event.stopPropagation()}
74
+ onTransitionEnd={handleTransitionEnd}
75
+ >
76
+ {children}
77
+ </div>
78
+ </div>
79
+ )
80
+ }
@@ -0,0 +1 @@
1
+ export * from "./AuthProviderV2"
@@ -0,0 +1 @@
1
+ export const DEFAULT_APP_ID = "@pmate/chat"
@@ -0,0 +1,5 @@
1
+ export * from "./useProfileStepFlow"
2
+ export * from "./useAuthApp"
3
+ export * from "./useAppBackgroundStyle"
4
+ export * from "./useAppConfig"
5
+ export * from "./useIsAuthenticated"
@@ -0,0 +1,25 @@
1
+ import { useEffect, useMemo, useState } from "react"
2
+ import { getWindowSearch, subscribeToLocationChange } from "../utils/location"
3
+ import { useAppConfig } from "./useAppConfig"
4
+
5
+ export const useAppBackgroundStyle = () => {
6
+ const [search, setSearch] = useState(getWindowSearch())
7
+ useEffect(() => {
8
+ const update = () => setSearch(getWindowSearch())
9
+ const unsubscribe = subscribeToLocationChange(update)
10
+ return () => unsubscribe()
11
+ }, [])
12
+ const appParam = useMemo(
13
+ () => new URLSearchParams(search).get("app"),
14
+ [search]
15
+ )
16
+ const { appConfig } = useAppConfig(appParam)
17
+
18
+ return useMemo(
19
+ () => ({
20
+ background:
21
+ appConfig?.background || "linear-gradient(180deg, #9ca3af 0%, #6b7280 100%)",
22
+ }),
23
+ [appConfig]
24
+ )
25
+ }
@@ -0,0 +1,51 @@
1
+ import { useEffect, useState } from "react"
2
+ import { resolveAppConfigId } from "../atoms/appConfigAtom"
3
+ import { AppService } from "../api/AppService"
4
+ import type { AppConfig } from "../types/app"
5
+
6
+ type AppConfigState = {
7
+ appConfig: AppConfig | null
8
+ isLoading: boolean
9
+ error: Error | null
10
+ }
11
+
12
+ export const useAppConfig = (app?: string | null): AppConfigState => {
13
+ const resolvedApp = resolveAppConfigId(app)
14
+ const [state, setState] = useState<AppConfigState>({
15
+ appConfig: null,
16
+ isLoading: true,
17
+ error: null,
18
+ })
19
+
20
+ useEffect(() => {
21
+ let active = true
22
+ setState({ appConfig: null, isLoading: true, error: null })
23
+
24
+ AppService.getAppConfig(resolvedApp)
25
+ .then((appConfig) => {
26
+ if (!active) {
27
+ return
28
+ }
29
+ setState({ appConfig, isLoading: false, error: null })
30
+ })
31
+ .catch((error: unknown) => {
32
+ if (!active) {
33
+ return
34
+ }
35
+ setState({
36
+ appConfig: null,
37
+ isLoading: false,
38
+ error:
39
+ error instanceof Error
40
+ ? error
41
+ : new Error("Failed to load app config"),
42
+ })
43
+ })
44
+
45
+ return () => {
46
+ active = false
47
+ }
48
+ }, [resolvedApp])
49
+
50
+ return state
51
+ }
@@ -0,0 +1,165 @@
1
+ import { useCallback, useMemo } from "react"
2
+ import { DEFAULT_APP_ID } from "../constants"
3
+ import { resolveAppId } from "../utils/resolveAppId"
4
+ import type { ProfileStepType } from "../utils/profileStep"
5
+
6
+ type UseAuthAppOptions = {
7
+ app?: string
8
+ redirect?: string
9
+ }
10
+
11
+ type AuthAppRedirectOptions = {
12
+ app?: string
13
+ redirect?: string
14
+ }
15
+
16
+ type LogoutScope = "app" | "all"
17
+
18
+ type AuthLogoutRedirectOptions = AuthAppRedirectOptions & {
19
+ scope?: LogoutScope
20
+ }
21
+
22
+ type AuthProfileRedirectOptions = AuthAppRedirectOptions & {
23
+ step?: ProfileStepType
24
+ }
25
+
26
+ const AUTH_APP_BASE = "https://auth.pmate.chat"
27
+
28
+ const getDefaultRedirect = () => {
29
+ if (typeof window === "undefined") {
30
+ return ""
31
+ }
32
+ return window.location.href
33
+ }
34
+
35
+ export const useAuthApp = (options: UseAuthAppOptions = {}) => {
36
+ const app = resolveAppId(options.app ?? DEFAULT_APP_ID)
37
+ const redirect = useMemo(
38
+ () => options.redirect ?? getDefaultRedirect(),
39
+ [options.redirect]
40
+ )
41
+
42
+ const buildUrl = useCallback(
43
+ (path = "/", overrides: AuthAppRedirectOptions = {}) => {
44
+ const targetRedirect = overrides.redirect ?? redirect
45
+ const targetApp = overrides.app ?? app
46
+ const url = new URL(path, AUTH_APP_BASE)
47
+ if (targetRedirect) {
48
+ url.searchParams.set("redirect", targetRedirect)
49
+ }
50
+ if (targetApp) {
51
+ url.searchParams.set("app", targetApp)
52
+ }
53
+ return url.toString()
54
+ },
55
+ [app, redirect]
56
+ )
57
+
58
+ const buildProfileUrl = useCallback(
59
+ (path: string, overrides: AuthProfileRedirectOptions = {}) => {
60
+ const url = new URL(buildUrl(path, overrides))
61
+ if (overrides.step) {
62
+ url.searchParams.set("step", overrides.step)
63
+ }
64
+ return url.toString()
65
+ },
66
+ [buildUrl]
67
+ )
68
+
69
+ const buildLogoutUrl = useCallback(
70
+ (overrides?: AuthLogoutRedirectOptions) => {
71
+ const url = new URL(buildUrl("/logout", overrides))
72
+ if (overrides?.scope === "all") {
73
+ url.searchParams.set("scope", "all")
74
+ }
75
+ return url.toString()
76
+ },
77
+ [buildUrl]
78
+ )
79
+
80
+ const buildLoginUrl = useCallback(
81
+ (overrides?: AuthAppRedirectOptions) => buildUrl("/", overrides),
82
+ [buildUrl]
83
+ )
84
+
85
+ const buildCreateProfileUrl = useCallback(
86
+ (overrides?: AuthProfileRedirectOptions) =>
87
+ buildProfileUrl("/create-profile", overrides),
88
+ [buildProfileUrl]
89
+ )
90
+
91
+ const buildSelectProfileUrl = useCallback(
92
+ (overrides?: AuthAppRedirectOptions) =>
93
+ buildUrl("/select-profile", overrides),
94
+ [buildUrl]
95
+ )
96
+
97
+ const buildEditProfileUrl = useCallback(
98
+ (overrides?: AuthProfileRedirectOptions) =>
99
+ buildProfileUrl("/edit-profile", overrides),
100
+ [buildProfileUrl]
101
+ )
102
+
103
+ const login = useCallback(
104
+ (overrides?: AuthAppRedirectOptions) => {
105
+ if (typeof window === "undefined") {
106
+ return
107
+ }
108
+ window.location.assign(buildLoginUrl(overrides))
109
+ },
110
+ [buildLoginUrl]
111
+ )
112
+
113
+ const logout = useCallback(
114
+ (scopeOrOverrides?: LogoutScope | AuthLogoutRedirectOptions) => {
115
+ if (typeof window === "undefined") {
116
+ return
117
+ }
118
+ const overrides =
119
+ typeof scopeOrOverrides === "string"
120
+ ? { scope: scopeOrOverrides }
121
+ : (scopeOrOverrides ?? {})
122
+ window.location.assign(buildLogoutUrl(overrides))
123
+ },
124
+ [buildLogoutUrl]
125
+ )
126
+
127
+ const redirectToCreateProfile = useCallback(
128
+ (overrides?: AuthProfileRedirectOptions) => {
129
+ if (typeof window === "undefined") {
130
+ return
131
+ }
132
+ window.location.assign(buildCreateProfileUrl(overrides))
133
+ },
134
+ [buildCreateProfileUrl]
135
+ )
136
+
137
+ const redirectToSelectProfile = useCallback(
138
+ (overrides?: AuthAppRedirectOptions) => {
139
+ if (typeof window === "undefined") {
140
+ return
141
+ }
142
+ window.location.assign(buildSelectProfileUrl(overrides))
143
+ },
144
+ [buildSelectProfileUrl]
145
+ )
146
+
147
+ const redirectToEditProfile = useCallback(
148
+ (overrides?: AuthProfileRedirectOptions) => {
149
+ if (typeof window === "undefined") {
150
+ return
151
+ }
152
+ window.location.assign(buildEditProfileUrl(overrides))
153
+ },
154
+ [buildEditProfileUrl]
155
+ )
156
+
157
+ return {
158
+ app,
159
+ login,
160
+ logout,
161
+ selectProfile: redirectToSelectProfile,
162
+ createProfile: redirectToCreateProfile,
163
+ updateProfile: redirectToEditProfile,
164
+ }
165
+ }
@@ -0,0 +1,84 @@
1
+ import { useEffect, useState } from "react"
2
+ import type { AccountSnapshot, AuthBehaviors } from "../types/account.types"
3
+ import { AccountLifecycleState } from "../types/account.types"
4
+ import { AccountManagerEvent, AccountManagerV2 } from "../utils/AccountManagerV2"
5
+
6
+ const checkAuth = async ({
7
+ app,
8
+ behaviors,
9
+ }: {
10
+ app: string
11
+ behaviors: AuthBehaviors
12
+ }): Promise<AccountSnapshot> => {
13
+ const manager = AccountManagerV2.get(app)
14
+ if (behaviors.requiresAuth === false) {
15
+ return manager.getSnapshot()
16
+ }
17
+
18
+ try {
19
+ const account = await manager.loginUrlSessionOverride()
20
+ if (account) {
21
+ const profiles = await manager.getProfiles()
22
+ if (profiles.length > 0) {
23
+ manager.setSelectedProfile(profiles[0].id)
24
+ }
25
+ }
26
+ return manager.getSnapshot()
27
+ } catch (error) {
28
+ console.error(error)
29
+ return manager.getSnapshot()
30
+ }
31
+ }
32
+
33
+ export const useAuthSnapshot = ({
34
+ app,
35
+ behaviors,
36
+ }: {
37
+ app: string
38
+ behaviors: AuthBehaviors
39
+ }) => {
40
+ const [loading, setLoading] = useState(true)
41
+ const [snapshot, setSnapshot] = useState<AccountSnapshot>({
42
+ state: AccountLifecycleState.Idle,
43
+ profiles: [],
44
+ profile: null,
45
+ accountId: null,
46
+ account: null,
47
+ error: null,
48
+ })
49
+
50
+ useEffect(() => {
51
+ let isActive = true
52
+ const manager = AccountManagerV2.get(app)
53
+
54
+ const refreshSnapshot = async () => {
55
+ const next = await manager.getSnapshot()
56
+ if (!isActive) {
57
+ return
58
+ }
59
+ setSnapshot(next)
60
+ }
61
+
62
+ const loadSnapshot = async () => {
63
+ setLoading(true)
64
+ const snap = await checkAuth({ app, behaviors })
65
+ if (!isActive) {
66
+ return
67
+ }
68
+ setSnapshot(snap)
69
+ setLoading(false)
70
+ }
71
+
72
+ void loadSnapshot()
73
+ const unsubscribe = manager.on(AccountManagerEvent.StateChange, () => {
74
+ void refreshSnapshot()
75
+ })
76
+
77
+ return () => {
78
+ isActive = false
79
+ unsubscribe()
80
+ }
81
+ }, [app, behaviors.authBehavior, behaviors.requiresAuth])
82
+
83
+ return { loading, snapshot }
84
+ }
@@ -0,0 +1,19 @@
1
+ import { DEFAULT_APP_ID } from "../constants"
2
+ import { useAuthSnapshot } from "./useAuthSnapshot"
3
+ import { resolveAppId } from "../utils/resolveAppId"
4
+
5
+ export const useIsAuthenticated = (app?: string) => {
6
+ const { loading, snapshot } = useAuthSnapshot({
7
+ app: resolveAppId(app ?? DEFAULT_APP_ID),
8
+ behaviors: {
9
+ authBehavior: "prompt",
10
+ requiresAuth: false,
11
+ },
12
+ })
13
+
14
+ if (loading) {
15
+ return false
16
+ }
17
+
18
+ return Boolean(snapshot.account)
19
+ }
@@ -0,0 +1,78 @@
1
+ import { useCallback, useMemo } from "react"
2
+ import { isProfileStepType, ProfileStepType } from "../utils/profileStep"
3
+ import { useAppConfig } from "./useAppConfig"
4
+
5
+ type UseProfileStepFlowParams = {
6
+ params: URLSearchParams
7
+ }
8
+
9
+ export const useProfileStepFlow = ({
10
+ params,
11
+ }: UseProfileStepFlowParams) => {
12
+ const appParam = params.get("app")
13
+ const redirectParam = params.get("redirect")
14
+ const { appConfig, error, isLoading } = useAppConfig(appParam)
15
+ const shouldBlockStep = Boolean(appParam) && isLoading && !appConfig && !error
16
+
17
+ // The app registry decides the canonical order of profile steps.
18
+ // When the config is still loading for an explicit app, we intentionally
19
+ // block the create flow instead of briefly falling back to a synthetic
20
+ // default step that does not exist in the app schema.
21
+ const appProfileSteps = useMemo<ProfileStepType[]>(
22
+ () =>
23
+ (appConfig?.profiles ?? [])
24
+ .map((profile) => profile.type)
25
+ .filter((type): type is ProfileStepType => isProfileStepType(type)),
26
+ [appConfig]
27
+ )
28
+ const stepParam = params.get("step")
29
+ const normalizedStep: ProfileStepType | null =
30
+ appProfileSteps.find((item) => item === stepParam) ?? null
31
+
32
+ // step=... wins when it is valid for the current app.
33
+ // Otherwise we use the first configured step. If the app does not declare
34
+ // any profile schema, create-profile should stay unavailable instead of
35
+ // inventing a fallback step.
36
+ const defaultStep: ProfileStepType | null = shouldBlockStep
37
+ ? null
38
+ : (appProfileSteps[0] ?? null)
39
+ const activeStep: ProfileStepType | null = normalizedStep ?? defaultStep
40
+
41
+ // createSteps stays empty while we intentionally block rendering.
42
+ // Once app config is ready, it mirrors the registry schema order exactly.
43
+ const createSteps = useMemo<ProfileStepType[]>(() => {
44
+ return shouldBlockStep ? [] : appProfileSteps
45
+ }, [appProfileSteps, shouldBlockStep])
46
+ const currentStepIndex =
47
+ activeStep === null ? -1 : createSteps.indexOf(activeStep)
48
+ const nextStep =
49
+ currentStepIndex >= 0 ? createSteps[currentStepIndex + 1] : undefined
50
+ const isCreateFlowStep =
51
+ activeStep === null ? false : createSteps.includes(activeStep)
52
+ const buildStepUrl = useCallback(
53
+ (next: ProfileStepType) => {
54
+ const search = new URLSearchParams()
55
+ search.set("step", next)
56
+ if (appParam) {
57
+ search.set("app", appParam)
58
+ }
59
+ if (redirectParam) {
60
+ search.set("redirect", redirectParam)
61
+ }
62
+ return `/create-profile?${search.toString()}`
63
+ },
64
+ [appParam, redirectParam]
65
+ )
66
+
67
+ return {
68
+ activeStep,
69
+ appProfileSteps,
70
+ buildStepUrl,
71
+ createSteps,
72
+ error,
73
+ isLoading,
74
+ isCreateFlowStep,
75
+ isReady: activeStep !== null,
76
+ nextStep,
77
+ }
78
+ }
@@ -0,0 +1,59 @@
1
+ import i18next from "i18next"
2
+ import {
3
+ I18nextProvider,
4
+ initReactI18next,
5
+ useTranslation as useI18nTranslation,
6
+ } from "react-i18next"
7
+ import arSA from "../locales/ar-SA.json"
8
+ import deDE from "../locales/de-DE.json"
9
+ import elGR from "../locales/el-GR.json"
10
+ import en from "../locales/en.json"
11
+ import esES from "../locales/es-ES.json"
12
+ import fiFI from "../locales/fi-FI.json"
13
+ import filPH from "../locales/fil-PH.json"
14
+ import frFR from "../locales/fr-FR.json"
15
+ import hiIN from "../locales/hi-IN.json"
16
+ import jaJP from "../locales/ja-JP.json"
17
+ import koKR from "../locales/ko-KR.json"
18
+ import ptBR from "../locales/pt-BR.json"
19
+ import ptPT from "../locales/pt-PT.json"
20
+ import ruRU from "../locales/ru-RU.json"
21
+ import taIN from "../locales/ta-IN.json"
22
+ import ukUA from "../locales/uk-UA.json"
23
+ import zhCN from "../locales/zh-CN.json"
24
+ import zhTW from "../locales/zh-TW.json"
25
+
26
+ const resources = {
27
+ en: { translation: en },
28
+ "ar-SA": { translation: arSA },
29
+ "de-DE": { translation: deDE },
30
+ "el-GR": { translation: elGR },
31
+ "es-ES": { translation: esES },
32
+ "fi-FI": { translation: fiFI },
33
+ "fil-PH": { translation: filPH },
34
+ "fr-FR": { translation: frFR },
35
+ "hi-IN": { translation: hiIN },
36
+ "ja-JP": { translation: jaJP },
37
+ "ko-KR": { translation: koKR },
38
+ "pt-BR": { translation: ptBR },
39
+ "pt-PT": { translation: ptPT },
40
+ "ru-RU": { translation: ruRU },
41
+ "ta-IN": { translation: taIN },
42
+ "uk-UA": { translation: ukUA },
43
+ "zh-CN": { translation: zhCN },
44
+ "zh-TW": { translation: zhTW },
45
+ } as const
46
+
47
+ const supportedLngs = Object.keys(resources)
48
+
49
+ const i18n = i18next.createInstance()
50
+ i18n.use(initReactI18next).init({
51
+ resources,
52
+ supportedLngs,
53
+ lng: "zh-CN",
54
+ fallbackLng: "zh-CN",
55
+ interpolation: { escapeValue: false },
56
+ })
57
+
58
+ export { i18n, I18nextProvider }
59
+ export const useTranslation = () => useI18nTranslation().t
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from "./atoms"
2
+ export * from "./components"
3
+ export * from "./i18n"
4
+ export { DEFAULT_APP_ID } from "./constants"
5
+ export type { AppConfig, ProfileStep } from "./types/app"
6
+ export * from "./hooks"
7
+ export * from "./utils"
8
+ export * from "./api"
9
+ export type { ProfileDraft } from "./types/profile"