Skip to content

Commit

Permalink
more ui stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
solareon committed Jun 25, 2024
1 parent 6db8e13 commit ae507a6
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 124 deletions.
2 changes: 2 additions & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"private": true,
"homepage": "./",
"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
Expand Down
74 changes: 23 additions & 51 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import GroupDashboard from "./components/GroupDashboard";
import JoinGroup from "./components/JoinGroup";
import PlayerList from "./components/PlayerList";
import GroupJob from "./components/GroupJob";
import { useGroupStore } from "./storage/GroupStore";
import { useGroupJobStepStore } from "./storage/GroupJobStepStore";
import { GroupJobStep } from "./types/GroupJobStep";
import { Group } from "./types/Group";
import { useNuiEvent } from "./hooks/useNuiEvent";
Expand All @@ -12,8 +14,6 @@ const devMode = !window?.["invokeNative"];

const App = () => {
const [theme, setTheme] = useState("light");
const [notificationText, setNotificationText] =
useState("Notification text");
const appDiv = useRef(null);

const {
Expand All @@ -30,25 +30,8 @@ const App = () => {
useCamera,
} = window as any;

const initialSteps: GroupJobStep[] = [
{ id: 1, name: "Step 1", isDone: false },
{ id: 2, name: "Step 2", isDone: false },
{ id: 3, name: "Step 3", isDone: false },
];

const [groups, setGroups] = useState<Group>([
{
id: 1,
status: "open",
GName: "Group 1",
GPass: "password",
Users: 1,
leader: 1,
members: [{ name: "Larry", CID: "ABCD1234", Player: 1 }],
stage: initialSteps,
ScriptCreated: false,
},
]);
const { groups, setGroups } = useGroupStore();
const { groupJobSteps } = useGroupJobStepStore();

const createGroup = () => {
const newGroup = {
Expand All @@ -59,7 +42,7 @@ const App = () => {
Users: 1,
leader: 1,
members: [{ name: "Larry", CID: "ABCD1234", Player: 1 }],
stage: initialSteps,
stage: groupJobSteps,
ScriptCreated: false,
};
setGroups([...groups, newGroup]);
Expand Down Expand Up @@ -135,41 +118,30 @@ const App = () => {
});
}, [theme]);

useEffect(() => {
if (notificationText === "") setNotificationText("Notification text");
}, [notificationText]);

const toggleTheme = () => {
setTheme(theme === "dark" ? "light" : "dark");
console.log(theme);
};

return (
<AppProvider>
<div
className={`h-screen w-full flex items-center justify-center flex-wrap bg-background-primary-light dark:bg-background-primary-dark font-poppins ${devMode ? "" : "hidden"}`}
ref={appDiv}
data-mode={theme}
>
<div className="w-full h-full flex flex-col items-center justify-center gap-12">
<div className="flex flex-col text-center gap-4">
<button
onClick={toggleTheme}
className="w-56 h-13 bg-background-highlight-light dark:bg-background-highlight-dark text-text-primary-light dark:text-text-primary-dark rounded-m"
>
Toggle Theme
</button>
<GroupDashboard
groups={groups}
createGroup={createGroup}
/>
<JoinGroup />
<PlayerList />
<GroupJob initialSteps={initialSteps} />
</div>
</div>
</div>
</AppProvider>
<AppProvider>
<div
className="grid grid-cols-1 size-full items-center justify-center bg-background-primary-light dark:bg-background-primary-dark font-poppins text-center gap-4"
ref={appDiv}
data-mode={theme}
>
<button
onClick={toggleTheme}
className="w-56 h-13 bg-background-highlight-light dark:bg-background-highlight-dark text-text-primary-light dark:text-text-primary-dark rounded-m"
>
Toggle Theme
</button>
<GroupDashboard groups={groups} createGroup={createGroup} />
<JoinGroup />
<PlayerList />
<GroupJob />
</div>
</AppProvider>
);
};

Expand Down
43 changes: 31 additions & 12 deletions web/src/components/CreateGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import Tooltip from './Tooltip';

const CreateGroup: React.FC<any> = ({ onSelect, onClose }) => {
const [groupName, setGroupName] = useState('');

const [disabledReason, setDisabledReason] = useState('');
const [password, setPassword] = useState('');
const [verifyPassword, setVerifyPassword] = useState('');
const [isSubmitDisabled, setIsSubmitDisabled] = useState(true);

useEffect(() => {
let reason = '';
if (groupName === '') {
reason = 'Group name is required';
} else if (password === '') {
reason = 'Password is required';
} else if (password !== verifyPassword) {
reason = 'Passwords do not match';
}
setDisabledReason(reason);
setIsSubmitDisabled(reason !== '');
}, [password, verifyPassword, groupName]);

// Rest of the code...

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Perform validation logic here
if (password !== verifyPassword) {

alert('Passwords do not match');
return;
}
// Perform other submission logic here
// ...
const groupData = {
Expand All @@ -24,15 +36,15 @@ const CreateGroup: React.FC<any> = ({ onSelect, onClose }) => {
};

return (
<div className="fixed inset-0 bg-black bg-opacity-75 flex justify-center items-center">
<div className="fixed inset-0 bg-black bg-opacity-75 flex justify-center items-center select-none">
<div className="bg-neutral-800 p-4 rounded-lg h-[30vh] max-h-full overflow-none">
<div className="flex justify-between items-center mb-2">
<h2 className="text-white text-xl">Create Group</h2>
<button onClick={onClose} className="text-white">x</button>
</div>
<form onSubmit={handleSubmit}>
<div className="mb-4">
<label htmlFor="groupName" className="text-white">Group Name</label>
<label className="text-white">Group Name</label>
<input
type="text"
id="groupName"
Expand All @@ -42,7 +54,7 @@ const CreateGroup: React.FC<any> = ({ onSelect, onClose }) => {
/>
</div>
<div className="mb-4">
<label htmlFor="password" className="text-white">Password</label>
<label className="text-white">Password</label>
<input
type="password"
id="password"
Expand All @@ -52,7 +64,7 @@ const CreateGroup: React.FC<any> = ({ onSelect, onClose }) => {
/>
</div>
<div className="mb-4">
<label htmlFor="verifyPassword" className="text-white">Verify Password</label>
<label className="text-white">Verify Password</label>
<input
type="password"
id="verifyPassword"
Expand All @@ -63,8 +75,15 @@ const CreateGroup: React.FC<any> = ({ onSelect, onClose }) => {
</div>
<div className="flex justify-end">
<button type="button" onClick={onClose} className="mr-2 px-4 py-2 rounded bg-neutral-700 text-white">Cancel</button>
<button type="submit" className="px-4 py-2 rounded bg-primary text-white">Submit</button>
<button
type="submit"
className={`px-4 py-2 rounded text-white ${isSubmitDisabled ? 'bg-neutral-800 cursor-not-allowed' : 'bg-neutral-700 hover:bg-neutral-600'}`}
disabled={isSubmitDisabled}
>
Submit
</button>
</div>
<div className="mb-4 p-2 text-red-500">{disabledReason}</div>
</form>
</div>
</div>
Expand Down
15 changes: 9 additions & 6 deletions web/src/components/DataHandler.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React from 'react';
import { useNuiEvent } from '../hooks/useNuiEvent';
import { usePlayerDataStore } from '../storage/PlayerDataStore';
import React from "react";
import { useNuiEvent } from "../hooks/useNuiEvent";
import { usePlayerDataStore } from "../storage/PlayerDataStore";
import { useGroupStore } from "../storage/GroupStore";

const DataHandler: React.FC = () => {
const { setPlayerData } = usePlayerDataStore();
const { setPlayerData } = usePlayerDataStore();
const { setGroups } = useGroupStore();

useNuiEvent('LoadPhoneData', setPlayerData);
useNuiEvent("loadPlayerData", setPlayerData);
useNuiEvent("setGroups", setGroups);

return null; // This component doesn't render anything
return null; // This component doesn't render anything
};

export default DataHandler;
115 changes: 62 additions & 53 deletions web/src/components/GroupDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,79 @@ import React, { useState } from 'react';
import CreateGroup from "./CreateGroup";
import { Group } from '../types/Group';
import { usePlayerDataStore } from '../storage/PlayerDataStore';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faUsers, faList, faTrash, faUserGroup } from '@fortawesome/free-solid-svg-icons';


const GroupDashboard = ({ groups, createGroup }) => {
const { playerData } = usePlayerDataStore();
const [ showCreateGroup, setShowCreateGroup ] = useState(false);
const inGroup = groups.some(group => group.members.some(member => member.Player === playerData.source));

return (
<div className="p-6 bg-neutral-400">
<div className="text-md font-bold text-text-primary-light dark:text-text-primary-dark">
Join a group or browse groups currently busy</div>
<button
onClick={() => setShowCreateGroup(true)}
className="px-4 py-2 m-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Create Group
</button>
<div className="max-w-4xl mx-auto bg-white p-4 rounded shadow-md">
{Object.keys(groups).map((key) => {
const element = groups[key];
let isLeader = element.leader === playerData.source;
let isMember = element.members.some(member => member.Player === playerData.source);
<div className="p-2 bg-neutral-400">
{!inGroup && (
<div>
<div className="text-md font-bold text-text-primary-light dark:text-text-primary-dark">
Join a group or browse groups currently busy
</div>
<button
onClick={() => setShowCreateGroup(true)}
className="px-4 py-2 m-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Create Group
</button>
</div>
)}
<div className="mx-auto bg-white p-2 rounded shadow-md">
{Object.keys(groups).map((key) => {
const element = groups[key];
let isLeader = element.leader === playerData.source;
let isMember = element.members.some((member) => member.Player === playerData.source);

return (
<div key={element.id} className="jobcenter-div-job-group">
<div className="jobcenter-div-job-group-image">
<i className="fas fa-users"></i>
</div>
<div className="jobcenter-div-job-group-body-main">
{element.GName}
{isLeader ? (
<>
<i id="jobcenter-block-grouped" data-id={element.id} data-pass={element.GPass} className="fas fa-sign-in-alt"></i>
<div className="jobcenter-option-class-body">
<i id="jobcenter-list-group" data-id={element.id} style={{ paddingRight: '5%' }} className="fas fa-list-ul"></i>
<i id="jobcenter-delete-group" data-delete={element.id} className="fas fa-trash-alt"></i>
<i style={{ paddingLeft: '5%', paddingRight: '5%' }} className="fas fa-user-friends"> {element.Users}</i>
return (
<div key={element.id} className="flex flex-row grid grid-rows-2 bg-neutral-700 rounded-md m-2 p-2">
<div className="flex justify-start row-span-1">
<FontAwesomeIcon icon={faUsers} size="xl" /> &nbsp;{element.GName}
</div>
<div className="flex justify-end row-span-1">
{isLeader ? (
<>
<div className="items-center text-lg">
<FontAwesomeIcon icon={faList} size="xl" className="px-1" />
<FontAwesomeIcon icon={faTrash} size="xl" className="px-1" />
<FontAwesomeIcon icon={faUserGroup} size="xl" className="px-1" />
{element.Users}
</div>
</>
) : (
<div className="items-center text-lg">
{isMember ? (
<>
<FontAwesomeIcon icon={faTrash} size="xl" className="px-1" />
<FontAwesomeIcon icon={faUserGroup} size="xl" /> {element.Users}
</>
) : (
<>
<FontAwesomeIcon icon={faUserGroup} size="xl" /> {element.Users}
</>
)}
</div>
</>
) : (
<div className="jobcenter-option-class-body">
{isMember ? (
<>
<i id="jobcenter-leave-grouped" data-id={element.id} data-pass={element.GPass} className="fas fa-sign-out-alt" style={{ transform: 'rotate(180deg)' }}></i>
<i id="jobcenter-list-group" data-id={element.id} style={{ paddingRight: '5%' }} className="fas fa-list-ul"></i>
</>
) : (
<i id="jobcenter-join-grouped" data-id={element.id} data-pass={element.GPass} className="fas fa-sign-in-alt"></i>
)}
<i style={{ paddingLeft: '5%', paddingRight: '5%' }} className="fas fa-user-friends">{element.Users}</i>
</div>
)}
)}
</div>
</div>
</div>
);
})}
);
})}
</div>
{showCreateGroup && (
<CreateGroup
onSelect={(groupData) => {
handleCreateGroup(groupData);
setShowCreateGroup(false);
}}
onClose={() => setShowCreateGroup(false)}
/>
)}
<CreateGroup
onSelect={(groupData) => {
createGroup(groupData);
setShowCreateGroup(false);
}}
onClose={() => setShowCreateGroup(false)}
/>
)}
</div>
);
};
Expand Down
6 changes: 4 additions & 2 deletions web/src/components/GroupJob.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import React, { useState } from 'react';
import clsx from 'clsx';
import { useNuiEvent } from '../hooks/useNuiEvent';
import { GroupJobStep } from '../types/GroupJobStep';
import { useGroupJobStepStore } from '../storage/GroupJobStepStore';

interface GroupJobProps {
initialSteps: GroupJobStep[];
}

const GroupJob: React.FC<GroupJobProps> = ({ initialSteps }) => {
const [steps, setSteps] = useState<GroupJobStep[]>(initialSteps);
const GroupJob: React.FC<GroupJobProps> = () => {
const { groupJobSteps } = useGroupJobStepStore();
const [steps, setSteps] = useState<GroupJobStep[]>(groupJobSteps);

useNuiEvent('updateGroupJobStep', (data: { id: string; isDone: boolean }) => {
if (!data || !data.id) {
Expand Down
Loading

0 comments on commit ae507a6

Please sign in to comment.