mirror of
https://github.com/kac5a/k5_documents.git
synced 2026-08-02 18:58:42 -04:00
add template grades, custom name, fix previously introduced bugs
This commit is contained in:
@@ -97,33 +97,29 @@ function detachPaper()
|
||||
DeleteEntity(prop)
|
||||
end
|
||||
|
||||
local function toggleNuiFrame(shouldShow, shouldHoldDocument, givenDocument)
|
||||
local function toggleNuiFrame(shouldShow, shouldHoldDocument)
|
||||
holdDocument(shouldHoldDocument)
|
||||
SetNuiFocus(shouldShow, shouldShow)
|
||||
print(givenDocument)
|
||||
SendReactMessage('setVisible', {
|
||||
app = shouldShow,
|
||||
givenDocument = givenDocument
|
||||
})
|
||||
SendReactMessage('setVisible', shouldShow)
|
||||
end
|
||||
|
||||
-- local function toggleDocumentFrame(shouldShow, document)
|
||||
-- holdDocument(shouldShow)
|
||||
-- SetNuiFocus(shouldShow, shouldShow)
|
||||
-- SendReactMessage('setDocument', document)
|
||||
-- end
|
||||
local function toggleDocumentFrame(shouldShow, document)
|
||||
holdDocument(shouldShow)
|
||||
SetNuiFocus(shouldShow, shouldShow)
|
||||
SendReactMessage('setDocument', document)
|
||||
end
|
||||
|
||||
-- RegisterNUICallback('hideDocument', function(_, cb)
|
||||
-- toggleDocumentFrame(false, nil)
|
||||
-- cb({})
|
||||
-- end)
|
||||
RegisterNUICallback('hideDocument', function(_, cb)
|
||||
toggleDocumentFrame(false, nil)
|
||||
cb({})
|
||||
end)
|
||||
|
||||
RegisterCommand(Config.Command, function()
|
||||
toggleNuiFrame(true, true, nil)
|
||||
toggleNuiFrame(true, true)
|
||||
end)
|
||||
|
||||
RegisterNUICallback('hideFrame', function(_, cb)
|
||||
toggleNuiFrame(false, false, nil)
|
||||
toggleNuiFrame(false, false)
|
||||
cb({})
|
||||
end)
|
||||
|
||||
@@ -232,8 +228,6 @@ RegisterNUICallback('showDocument', function(data, cb)
|
||||
Citizen.CreateThread(function()
|
||||
local targetId = playerSelector(Config.Locale.showDocument)
|
||||
if targetId == -1 then
|
||||
print("asd")
|
||||
TriggerServerEvent("k5_documents:receiveDocument", data, -1)
|
||||
holdDocument(false)
|
||||
else
|
||||
holdDocument(false)
|
||||
@@ -258,8 +252,7 @@ end)
|
||||
|
||||
RegisterNetEvent('k5_documents:viewDocument')
|
||||
AddEventHandler('k5_documents:viewDocument', function(data)
|
||||
print(data)
|
||||
toggleNuiFrame(true, true, data.data)
|
||||
toggleDocumentFrame(true, data.data)
|
||||
end)
|
||||
|
||||
function playerSelector(confirmText)
|
||||
|
||||
@@ -2,8 +2,8 @@ fx_version "cerulean"
|
||||
|
||||
description "A better document management script"
|
||||
author "K5 Scripts"
|
||||
version '1.1.4'
|
||||
update "Fixed visual bug when giving document to someone"
|
||||
version '1.1.5'
|
||||
update "Custom document names, template creation set for job grades, bug fixes"
|
||||
repository 'https://github.com/kac5a/k5_documents'
|
||||
|
||||
lua54 'yes'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"files": {
|
||||
"main.js": "/web/build/static/js/main.10eced3f.js",
|
||||
"main.js": "/web/build/static/js/main.8a2981e6.js",
|
||||
"static/media/city_logo.png": "/web/build/static/media/city_logo.008b591a2d4e6445d96c.png",
|
||||
"index.html": "/web/build/index.html",
|
||||
"main.10eced3f.js.map": "/web/build/static/js/main.10eced3f.js.map"
|
||||
"main.8a2981e6.js.map": "/web/build/static/js/main.8a2981e6.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/main.10eced3f.js"
|
||||
"static/js/main.8a2981e6.js"
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,18 @@
|
||||
// These are the jobs that can create documents. The boss rank of this job can create document templates.
|
||||
const AVAILABLE_JOBS = ['police', 'ambulance', 'mechanic']
|
||||
const AVAILABLE_JOBS = [
|
||||
{
|
||||
job: 'police',
|
||||
templateGrades: [3, 4],
|
||||
},
|
||||
{
|
||||
job: 'ambulance',
|
||||
templateGrades: [3],
|
||||
},
|
||||
{
|
||||
job: 'mechanic',
|
||||
templateGrades: [4],
|
||||
},
|
||||
]
|
||||
|
||||
const COLORS = {
|
||||
// These are hexadecimal color codes for the main theme. You can change them as you wish.
|
||||
@@ -20,7 +33,10 @@ const TEXTS = {
|
||||
myDocumentsTitle: 'My Documents',
|
||||
issuedDocumentsTitle: 'Issued Documents',
|
||||
templatesTitle: 'Templates',
|
||||
customDocumentName: 'Custom Document Name',
|
||||
documentType: 'Type',
|
||||
documentName: 'Name',
|
||||
unnamed: 'Unnamed',
|
||||
actions: 'Actions',
|
||||
edit: 'Edit',
|
||||
cancel: 'Cancel',
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/><link href="https://fonts.googleapis.com/css2?family=Oooh+Baby&display=swap" rel="stylesheet"/><title>K5 Documents</title><script type="text/javascript" src="/web/build/config.js"></script><script defer="defer" src="/web/build/static/js/main.10eced3f.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/><link href="https://fonts.googleapis.com/css2?family=Oooh+Baby&display=swap" rel="stylesheet"/><title>K5 Documents</title><script type="text/javascript" src="/web/build/config.js"></script><script defer="defer" src="/web/build/static/js/main.8a2981e6.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
web/build/static/js/main.8a2981e6.js
Normal file
3
web/build/static/js/main.8a2981e6.js
Normal file
File diff suppressed because one or more lines are too long
1
web/build/static/js/main.8a2981e6.js.map
Normal file
1
web/build/static/js/main.8a2981e6.js.map
Normal file
File diff suppressed because one or more lines are too long
@@ -1,5 +1,18 @@
|
||||
// These are the jobs that can create documents. The boss rank of this job can create document templates.
|
||||
const AVAILABLE_JOBS = ['police', 'ambulance', 'mechanic']
|
||||
const AVAILABLE_JOBS = [
|
||||
{
|
||||
job: 'police',
|
||||
templateGrades: [3, 4],
|
||||
},
|
||||
{
|
||||
job: 'ambulance',
|
||||
templateGrades: [3],
|
||||
},
|
||||
{
|
||||
job: 'mechanic',
|
||||
templateGrades: [4],
|
||||
},
|
||||
]
|
||||
|
||||
const COLORS = {
|
||||
// These are hexadecimal color codes for the main theme. You can change them as you wish.
|
||||
@@ -20,7 +33,10 @@ const TEXTS = {
|
||||
myDocumentsTitle: 'My Documents',
|
||||
issuedDocumentsTitle: 'Issued Documents',
|
||||
templatesTitle: 'Templates',
|
||||
customDocumentName: 'Custom Document Name',
|
||||
documentType: 'Type',
|
||||
documentName: 'Name',
|
||||
unnamed: 'Unnamed',
|
||||
actions: 'Actions',
|
||||
edit: 'Edit',
|
||||
cancel: 'Cancel',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
declare var TEXTS: { [key: string]: string }
|
||||
declare var COLORS: { [key: string]: string }
|
||||
declare var AVAILABLE_JOBS: string[]
|
||||
declare var AVAILABLE_JOBS: {job:string, templateGrades: number[]}[]
|
||||
|
||||
export const texts = typeof TEXTS === "undefined" ? {} : TEXTS
|
||||
export const colors = typeof COLORS === "undefined" ? {} : COLORS
|
||||
|
||||
@@ -2,18 +2,15 @@ import Box from '@mui/material/Box';
|
||||
import { Grid } from '@mui/material';
|
||||
import Header from './Header';
|
||||
import Menu from './Menu/Menu';
|
||||
import { useContext, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { NavLinks } from './Menu/NavLinks';
|
||||
import { useJob } from '../hooks/useJob';
|
||||
import { debugData } from '../utils/debugData';
|
||||
import { ContextProvider } from '../context/Context';
|
||||
import { VisibilityCtx } from '../providers/VisibilityProvider';
|
||||
import DocumentViewFromPlayer from './Components/DocumentViewFromPlayer';
|
||||
|
||||
export default function App() {
|
||||
const [selectedPage, setSelectedPage] = useState<Page>(NavLinks[0])
|
||||
const { isBoss, job } = useJob()
|
||||
const {visible, givenDocument} = useContext(VisibilityCtx)
|
||||
const { job } = useJob()
|
||||
|
||||
debugData([
|
||||
{
|
||||
@@ -24,10 +21,10 @@ export default function App() {
|
||||
|
||||
return (
|
||||
<ContextProvider>
|
||||
{visible && !givenDocument && <Box sx={{ p:0, height: "70vh", width: "70vw", display: "flex", alignItems: "center" }}>
|
||||
<Box sx={{ p:0, height: "70vh", width: "70vw", display: "flex", alignItems: "center" }}>
|
||||
<Grid container sx={{height: '100%'}}>
|
||||
<Grid item xs={3} style={{marginTop: "auto", marginBottom: "auto"}}>
|
||||
<Menu selected={selectedPage} isBoss={isBoss} job={job?.name!} setSelected={setSelectedPage}/>
|
||||
<Menu selected={selectedPage} jobGrade={job?.grade!} job={job?.name!} setSelected={setSelectedPage}/>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<Box
|
||||
@@ -40,8 +37,7 @@ export default function App() {
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>}
|
||||
{visible && givenDocument && <DocumentViewFromPlayer />}
|
||||
</Box>
|
||||
</ContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ import SignedArea from "./SignedArea"
|
||||
import { DATE_FORMAT_SHORT } from "../../utils/consts"
|
||||
import { useContext } from "react"
|
||||
import { texts } from "../../AppConfig"
|
||||
import { VisibilityCtx } from "../../providers/VisibilityProvider"
|
||||
import { DocumentCtx } from "../../providers/DocumentProvider"
|
||||
|
||||
|
||||
const DocumentViewFromPlayer = () => {
|
||||
|
||||
const { givenDocument: document } = useContext(VisibilityCtx)
|
||||
|
||||
const { document } = useContext(DocumentCtx)
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
<StyledDocument>
|
||||
|
||||
@@ -48,10 +48,11 @@ const CreateDocument = ({ template, handleCreate, handleClose }: Props) => {
|
||||
rules: { required: texts.requiredError }
|
||||
})
|
||||
|
||||
const handleCreateTemplate: SubmitHandler<K5Document> = (data: K5Document) => {
|
||||
const handleCreateDocument: SubmitHandler<K5Document> = (data: K5Document) => {
|
||||
let result = {
|
||||
name: data.name,
|
||||
createdAt: (new Date()).toString(),
|
||||
customName: data.customName,
|
||||
description: data.description,
|
||||
fields: data.fields,
|
||||
isCopy: false,
|
||||
@@ -69,7 +70,7 @@ const CreateDocument = ({ template, handleCreate, handleClose }: Props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(handleCreateTemplate)}>
|
||||
<form onSubmit={handleSubmit(handleCreateDocument)}>
|
||||
<StyledDocument>
|
||||
<Box style={{width: 0}} sx={{ flexGrow: 1 }}>
|
||||
<Grid
|
||||
@@ -170,6 +171,14 @@ const CreateDocument = ({ template, handleCreate, handleClose }: Props) => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item container justifyContent="center" flex={1} style={{ marginTop: "1.5vh" }}>
|
||||
<DocTextField
|
||||
size="small"
|
||||
label={texts.customDocumentName}
|
||||
error={!!errors.customName}
|
||||
style={{width: "auto", marginRight: "auto", justifySelf: "flex-start"}}
|
||||
helperText={errors.customName?.message as string}
|
||||
{...register("customName")}
|
||||
/>
|
||||
<Button disabled={!isSigned} type="submit" variant="contained" color="success" >{texts.createDocumentBtn}</Button>
|
||||
<Button variant="contained" color="secondary" style={{marginLeft: "1.8vh"}} onClick={handleClose} >{texts.cancel}</Button>
|
||||
</Grid>
|
||||
|
||||
@@ -8,10 +8,10 @@ type Props = {
|
||||
selected: Page
|
||||
setSelected: (selectedPage: Page) => void
|
||||
job: string
|
||||
isBoss: boolean
|
||||
jobGrade: number
|
||||
}
|
||||
|
||||
const Menu = ({isBoss, selected, job, setSelected}: Props) => {
|
||||
const Menu = ({jobGrade, selected, job, setSelected}: Props) => {
|
||||
|
||||
const handleListItemClick = (selectedPage: Page) => {
|
||||
setSelected(selectedPage);
|
||||
@@ -21,13 +21,13 @@ const Menu = ({isBoss, selected, job, setSelected}: Props) => {
|
||||
if (!navLink.jobAccess) {
|
||||
return true
|
||||
} else if (!navLink.bossOnly) {
|
||||
if (availableJobs.includes(job)) {
|
||||
if (availableJobs.filter(j => j.job === job).length) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if (availableJobs.includes(job) && isBoss) {
|
||||
if (availableJobs.filter(j => j.job === job && j.templateGrades.includes(jobGrade)).length) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DataGrid, GridActionsCellItem, GridColumns, GridRowParams, GridValueGetterParams } from "@mui/x-data-grid"
|
||||
import { DataGrid, GridActionsCellItem, GridColumns, GridRenderCellParams, GridRowParams, GridValueGetterParams } from "@mui/x-data-grid"
|
||||
import DeleteIcon from "@mui/icons-material/Delete"
|
||||
import { useCallback, useContext, useEffect, useState } from "react"
|
||||
import { fetchNui } from "../../utils/fetchNui"
|
||||
@@ -46,9 +46,15 @@ const IssuedDocuments = () => {
|
||||
} = useDeleteDocument({ handleGetDocuments, setDocumentsLoading })
|
||||
|
||||
const columns: GridColumns<K5Document> = [
|
||||
{
|
||||
field: 'customName',
|
||||
headerName: texts.customName,
|
||||
flex: 1,
|
||||
renderCell: (params: GridRenderCellParams<string | undefined>) => (params.value === undefined ? <div style={{ fontStyle: "italic" }}>{texts.unnamed}</div> : params.value)
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
headerName: texts.documentName,
|
||||
headerName: texts.documentType,
|
||||
flex: 1,
|
||||
},
|
||||
{
|
||||
|
||||
1
web/src/components/types.d.ts
vendored
1
web/src/components/types.d.ts
vendored
@@ -27,6 +27,7 @@ declare type Field = {
|
||||
declare type K5Document = {
|
||||
id?: string
|
||||
name: string
|
||||
customName?: string
|
||||
createdAt: string
|
||||
description: string
|
||||
fields: Field[]
|
||||
|
||||
@@ -7,6 +7,8 @@ import theme from './theme/theme';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { GlobalStyles } from '@mui/material';
|
||||
import { Box } from '@mui/system';
|
||||
import { DocumentProvider } from './providers/DocumentProvider';
|
||||
import DocumentViewFromPlayer from './components/Components/DocumentViewFromPlayer';
|
||||
|
||||
const root = createRoot(document.getElementById('root')!);
|
||||
|
||||
@@ -21,10 +23,22 @@ root.render(
|
||||
body: { backgroundColor: "transparent"},
|
||||
}}
|
||||
/>
|
||||
<Box style={{ height: "100vh", width: "100vw", display: 'flex', justifyContent: "center", alignItems: "center"}}>
|
||||
<Box style={{position: "fixed", top:0, left: 0, height: "100vh", width: "100vw", display: 'flex', justifyContent: "center", alignItems: "center"}}>
|
||||
<App />
|
||||
</Box>
|
||||
</VisibilityProvider>
|
||||
|
||||
<DocumentProvider>
|
||||
<CssBaseline />
|
||||
<GlobalStyles
|
||||
styles={{
|
||||
body: { backgroundColor: "transparent"},
|
||||
}}
|
||||
/>
|
||||
<Box style={{position: "fixed", top:0, left: 0, height: "100vh", width: "100vw", display: 'flex', justifyContent: "center", alignItems: "center"}}>
|
||||
<DocumentViewFromPlayer/>
|
||||
</Box>
|
||||
</DocumentProvider>
|
||||
</ThemeProvider>
|
||||
|
||||
</React.StrictMode>
|
||||
|
||||
53
web/src/providers/DocumentProvider.tsx
Normal file
53
web/src/providers/DocumentProvider.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React, {createContext, useEffect, useState} from "react";
|
||||
import {useNuiEvent} from "../hooks/useNuiEvent";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import { isEnvBrowser } from "../utils/misc";
|
||||
|
||||
export const DocumentCtx = createContext<DocumentProviderValue>({} as DocumentProviderValue)
|
||||
|
||||
type DocumentProviderValue = {
|
||||
document: K5Document | undefined
|
||||
setDocument: (document: K5Document | undefined) => void
|
||||
}
|
||||
|
||||
// This should be mounted at the top level of your application, it is currently set to
|
||||
// apply a CSS visibility value. If this is non-performant, this should be customized.
|
||||
export const DocumentProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [document, setDocument] = useState<K5Document | undefined>()
|
||||
const [visible, setVisible] = useState<boolean>(false)
|
||||
|
||||
useNuiEvent<string>('setDocument', (data) => {
|
||||
setVisible(!!data)
|
||||
setDocument(data ? JSON.parse(data) as K5Document : undefined)
|
||||
})
|
||||
|
||||
// Handle pressing escape/backspace
|
||||
useEffect(() => {
|
||||
// Only attach listener when we are visible
|
||||
if (!visible) return;
|
||||
|
||||
const keyHandler = (e: KeyboardEvent) => {
|
||||
if (!isEnvBrowser()) fetchNui("hideDocument").then((_d) => {}).catch(_e => {});
|
||||
if (["Escape"].includes(e.code)) {
|
||||
setVisible(!visible)
|
||||
setDocument(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("keydown", keyHandler)
|
||||
|
||||
return () => window.removeEventListener("keydown", keyHandler)
|
||||
}, [visible])
|
||||
|
||||
return (
|
||||
<DocumentCtx.Provider
|
||||
value={{
|
||||
document,
|
||||
setDocument,
|
||||
}}
|
||||
>
|
||||
<div style={{ visibility: visible ? 'visible' : 'hidden', height: '100%'}}>
|
||||
{document && children}
|
||||
</div>
|
||||
</DocumentCtx.Provider>)
|
||||
}
|
||||
@@ -8,21 +8,14 @@ export const VisibilityCtx = createContext<VisibilityProviderValue>({} as Visibi
|
||||
type VisibilityProviderValue = {
|
||||
setVisible: (visible: boolean) => void
|
||||
visible: boolean
|
||||
givenDocument: K5Document | undefined
|
||||
setGivenDocument: (doc: K5Document | undefined) => void
|
||||
}
|
||||
|
||||
// This should be mounted at the top level of your application, it is currently set to
|
||||
// apply a CSS visibility value. If this is non-performant, this should be customized.
|
||||
export const VisibilityProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [visible, setVisible] = useState(false)
|
||||
const [givenDocument, setGivenDocument] = useState<K5Document| undefined>()
|
||||
|
||||
useNuiEvent<{ app: boolean, givenDocument: string | undefined }>('setVisible', (data: { app: boolean, givenDocument: string | undefined }) => {
|
||||
console.log(data.givenDocument)
|
||||
setVisible(data.app)
|
||||
data.givenDocument && setGivenDocument(JSON.parse(data.givenDocument) as K5Document)
|
||||
})
|
||||
useNuiEvent<boolean>('setVisible', setVisible)
|
||||
|
||||
// Handle pressing escape/backspace
|
||||
useEffect(() => {
|
||||
@@ -48,12 +41,10 @@ export const VisibilityProvider: React.FC<{ children: React.ReactNode }> = ({ ch
|
||||
value={{
|
||||
visible,
|
||||
setVisible,
|
||||
givenDocument,
|
||||
setGivenDocument
|
||||
}}
|
||||
>
|
||||
<div style={{ visibility: visible ? 'visible' : 'hidden', height: '100%'}}>
|
||||
{children}
|
||||
{visible && children}
|
||||
</div>
|
||||
</VisibilityCtx.Provider>)
|
||||
}
|
||||
Reference in New Issue
Block a user