From 4db4c79d8ad775b11f13105d7d48d158c76d3926 Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 30 Apr 2022 14:49:49 +0200 Subject: [PATCH] feat(web): Settings modal, locale state provider --- locales/en.json | 10 ++- locales/fr.json | 10 ++- resource/locale/client.lua | 35 ++++++-- web/src/App.tsx | 5 ++ .../features/settings/components/locale.tsx | 38 ++++++++ web/src/features/settings/index.tsx | 74 ++++++++++++++++ web/src/index.tsx | 13 +-- web/src/providers/LocaleProvider.tsx | 87 +++++++++++++++++++ 8 files changed, 256 insertions(+), 16 deletions(-) create mode 100644 web/src/features/settings/components/locale.tsx create mode 100644 web/src/features/settings/index.tsx create mode 100644 web/src/providers/LocaleProvider.tsx diff --git a/locales/en.json b/locales/en.json index c332031..54d9c83 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1,5 +1,11 @@ { "language": "English", - "ui.close": "Close", - "ui.confirm": "Confirm" + "ui": { + "settings": { + "title": "Settings", + "language": "Language" + }, + "close": "Close", + "confirm": "Confirm" + } } diff --git a/locales/fr.json b/locales/fr.json index 70abe13..3f6821a 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -1,5 +1,11 @@ { "language": "Français", - "ui.close": "Fermer", - "ui.confirm": "Confirmer" + "ui": { + "settings": { + "title": "Réglages", + "language": "Langue" + }, + "close": "Fermer", + "confirm": "Confirmer" + } } diff --git a/resource/locale/client.lua b/resource/locale/client.lua index 07469c9..f6731e3 100644 --- a/resource/locale/client.lua +++ b/resource/locale/client.lua @@ -1,21 +1,42 @@ +local default = { 'en', 'fr', 'de', 'it', 'es', 'pt-BR', 'pl', 'ru', 'ko', 'zh-TW', 'ja', 'es-MX', 'zh-CN' } local userLocale = GetResourceKvpString('locale') local function loadLocale(locale, cb) + if cb then cb(1) end local JSON = LoadResourceFile('ox_lib', ('locales/%s.json'):format(locale)) or LoadResourceFile('ox_lib', ('locales/en.json'):format(locale)) - if cb then cb(JSON) end - + SendNUIMessage({ + action = 'setLocale', + data = json.decode(JSON) + }) SetResourceKvp('locale', locale) TriggerEvent('ox_lib:setLocale', locale) end RegisterNUICallback('getLocale', loadLocale) -if not userLocale then - local default = { 'en', 'fr', 'de', 'it', 'es', 'pt-BR', 'pl', 'ru', 'ko', 'zh-TW', 'ja', 'es-MX', 'zh-CN' } - userLocale = default[GetCurrentLanguage() + 1] -end +RegisterNUICallback('closeSettings', function(_, cb) + cb(1) + SetNuiFocus(false, false) +end) -loadLocale(userLocale) +if not userLocale then userLocale = default[GetCurrentLanguage() + 1] end + +RegisterNUICallback('init', function(_, cb) + cb(1) + loadLocale(userLocale) + SendNUIMessage({ -- Loads the `default` array into select options + action = 'loadLocales', + data = default + }) +end) + +RegisterCommand('ox_lib', function() + SendNUIMessage({ + action = 'openSettings', + data = GetResourceKvpString('locale') -- Sets the value for language select + }) + SetNuiFocus(true, true) +end) RegisterCommand('setlocale', function(_, args, _) if args?[1] then diff --git a/web/src/App.tsx b/web/src/App.tsx index c963b48..c551d72 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -4,16 +4,21 @@ import Progressbar from "./features/progress/Progressbar"; import TextUI from "./features/textui/TextUI"; import InputDialog from "./features/dialog/InputDialog"; import ContextMenu from "./features/menu/ContextMenu"; +import Settings from "./features/settings"; import { useNuiEvent } from "./hooks/useNuiEvent"; import { setClipboard } from "./utils/setClipboard"; +import { fetchNui } from "./utils/fetchNui"; const App: React.FC = () => { useNuiEvent("setClipboard", (data: string) => { setClipboard(data); }); + fetchNui("init"); + return ( <> + diff --git a/web/src/features/settings/components/locale.tsx b/web/src/features/settings/components/locale.tsx new file mode 100644 index 0000000..3f4eca6 --- /dev/null +++ b/web/src/features/settings/components/locale.tsx @@ -0,0 +1,38 @@ +import { HStack, Text, Select, Spacer } from "@chakra-ui/react"; +import { useEffect, useState } from "react"; +import { useNuiEvent } from "../../../hooks/useNuiEvent"; +import { useLocales } from "../../../providers/LocaleProvider"; +import { fetchNui } from "../../../utils/fetchNui"; + +const LocaleSetting: React.FC<{ + languages: string[]; + selectValue: string; + setSelectValue: React.Dispatch>; +}> = (props) => { + const { locale } = useLocales(); + + const handleChange = (e: React.ChangeEvent) => { + props.setSelectValue(e.target.value); + fetchNui("getLocale", e.target.value); + }; + + return ( + + {locale.ui.settings.language} + + + + ); +}; + +export default LocaleSetting; diff --git a/web/src/features/settings/index.tsx b/web/src/features/settings/index.tsx new file mode 100644 index 0000000..ab04d8d --- /dev/null +++ b/web/src/features/settings/index.tsx @@ -0,0 +1,74 @@ +import { + Button, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + useDisclosure, +} from "@chakra-ui/react"; +import LocaleSetting from "./components/locale"; +import { useEffect, useState } from "react"; +import { useNuiEvent } from "../../hooks/useNuiEvent"; +import { debugData } from "../../utils/debugData"; +import { fetchNui } from "../../utils/fetchNui"; +import { useLocales } from "../../providers/LocaleProvider"; + +debugData([ + { + action: "openSettings", + data: true, + }, +]); + +const Settings: React.FC = () => { + const { isOpen, onOpen, onClose } = useDisclosure(); + const { locale } = useLocales(); + const [languages, setLanguages] = useState([""]); + const [selectValue, setSelectValue] = useState(""); + + const closeSettings = () => { + onClose(); + fetchNui("closeSettings"); + }; + + useNuiEvent("loadLocales", (data) => setLanguages(data)); + useNuiEvent("openSettings", (data: string) => { + onOpen(); + setSelectValue(data); + }); + + return ( + <> + + + + {locale.ui.settings.title} + + + + + + + + + + ); +}; + +export default Settings; diff --git a/web/src/index.tsx b/web/src/index.tsx index 4d902bb..6b1276e 100644 --- a/web/src/index.tsx +++ b/web/src/index.tsx @@ -11,6 +11,7 @@ import { far } from "@fortawesome/free-regular-svg-icons"; import { fab } from "@fortawesome/free-brands-svg-icons"; import { library } from "@fortawesome/fontawesome-svg-core"; import { isEnvBrowser } from "./utils/misc"; +import LocaleProvider from "./providers/LocaleProvider"; library.add(fas, far, fab); @@ -33,11 +34,13 @@ debugData([ ReactDOM.render( - - - - - + + + + + + + , document.getElementById("root") ); diff --git a/web/src/providers/LocaleProvider.tsx b/web/src/providers/LocaleProvider.tsx new file mode 100644 index 0000000..4637666 --- /dev/null +++ b/web/src/providers/LocaleProvider.tsx @@ -0,0 +1,87 @@ +import { Context, createContext, useContext, useEffect, useState } from "react"; +import { useNuiEvent } from "../hooks/useNuiEvent"; +import { debugData } from "../utils/debugData"; + +debugData([ + { + action: "loadLocales", + data: [ + "en", + "fr", + "de", + "it", + "es", + "pt-BR", + "pl", + "ru", + "ko", + "zh-TW", + "ja", + "es-MX", + "zh-CN", + ], + }, +]); + +debugData([ + { + action: "setLocale", + data: { + language: "English", + ui: { + settings: { + title: "Settings", + language: "Language", + }, + close: "Close", + confirm: "Confirm", + }, + }, + }, +]); + +interface Locale { + language: string; + ui: { + settings: { + title: string; + language: string; + }; + close: string; + confirm: string; + }; +} + +interface LocaleContextValue { + locale: Locale; + setLocale: (locales: Locale) => void; +} + +const LocaleCtx = createContext(null); + +const LocaleProvider: React.FC = ({ children }) => { + const [locale, setLocale] = useState({ + language: "", + ui: { + settings: { + title: "", + language: "", + }, + close: "", + confirm: "", + }, + }); + + useNuiEvent("setLocale", async (data: Locale) => setLocale(data)); + + return ( + + {children} + + ); +}; + +export default LocaleProvider; + +export const useLocales = () => + useContext(LocaleCtx as Context);