feat(web): Settings modal, locale state provider

This commit is contained in:
Luke
2022-04-30 14:49:49 +02:00
parent 48728f0241
commit 4db4c79d8a
8 changed files with 256 additions and 16 deletions

View File

@@ -1,5 +1,11 @@
{
"language": "English",
"ui.close": "Close",
"ui.confirm": "Confirm"
"ui": {
"settings": {
"title": "Settings",
"language": "Language"
},
"close": "Close",
"confirm": "Confirm"
}
}

View File

@@ -1,5 +1,11 @@
{
"language": "Français",
"ui.close": "Fermer",
"ui.confirm": "Confirmer"
"ui": {
"settings": {
"title": "Réglages",
"language": "Langue"
},
"close": "Fermer",
"confirm": "Confirmer"
}
}

View File

@@ -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

View File

@@ -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 (
<>
<Settings />
<Progressbar />
<CircleProgressbar />
<Notifications />

View File

@@ -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<React.SetStateAction<string>>;
}> = (props) => {
const { locale } = useLocales();
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
props.setSelectValue(e.target.value);
fetchNui("getLocale", e.target.value);
};
return (
<HStack spacing={5}>
<Text>{locale.ui.settings.language}</Text>
<Spacer />
<Select
onChange={(e) => handleChange(e)}
value={props.selectValue}
w={150}
>
{props.languages.map((language) => (
<option key={language} value={language}>
{language}
</option>
))}
</Select>
</HStack>
);
};
export default LocaleSetting;

View File

@@ -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 (
<>
<Modal
isOpen={isOpen}
onClose={onClose}
isCentered
closeOnEsc
closeOnOverlayClick={false}
size="xs"
>
<ModalOverlay />
<ModalContent>
<ModalHeader>{locale.ui.settings.title}</ModalHeader>
<ModalBody>
<LocaleSetting
languages={languages}
selectValue={selectValue}
setSelectValue={setSelectValue}
/>
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" onClick={closeSettings}>
{locale.ui.close}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};
export default Settings;

View File

@@ -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(
<React.StrictMode>
<VisibilityProvider>
<ChakraProvider theme={theme}>
<App />
</ChakraProvider>
</VisibilityProvider>
<LocaleProvider>
<VisibilityProvider>
<ChakraProvider theme={theme}>
<App />
</ChakraProvider>
</VisibilityProvider>
</LocaleProvider>
</React.StrictMode>,
document.getElementById("root")
);

View File

@@ -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<LocaleContextValue | null>(null);
const LocaleProvider: React.FC = ({ children }) => {
const [locale, setLocale] = useState<Locale>({
language: "",
ui: {
settings: {
title: "",
language: "",
},
close: "",
confirm: "",
},
});
useNuiEvent("setLocale", async (data: Locale) => setLocale(data));
return (
<LocaleCtx.Provider value={{ locale, setLocale }}>
{children}
</LocaleCtx.Provider>
);
};
export default LocaleProvider;
export const useLocales = () =>
useContext<LocaleContextValue>(LocaleCtx as Context<LocaleContextValue>);