Skip to content

Commit

Permalink
(ui): allow setting/updating/searching for server owners
Browse files Browse the repository at this point in the history
  • Loading branch information
camwhit-e committed Nov 2, 2024
1 parent 79e4cbe commit d56f5fb
Show file tree
Hide file tree
Showing 7 changed files with 439 additions and 82 deletions.
6 changes: 5 additions & 1 deletion app/Http/Controllers/ServersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,16 @@ public function update(Request $request, int $id): Response
$validated = $request->validate([
'name' => ['required', 'max:50'],
'address' => ['required', 'url'],
'owner_id' => ['nullable', 'exists:users,id'],
'owner_id' => ['nullable'],
'public' => ['required'],
]);

$validated['public'] = $validated['public'] === 'on' ? true : false;

if ($request['owner_id'] != 0 && !User::where('id', $request['owner_id'])->exists()) {
throw new \Exception('This user does not exist.');
};

$server = Server::findOrFail($id)->forceFill($validated)->saveOrFail();

return Inertia::render('Servers/Edit', [
Expand Down
411 changes: 360 additions & 51 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
},
"dependencies": {
"@heroicons/react": "^2.1.5",
"boring-avatars": "^1.11.2"
"boring-avatars": "^1.11.2",
"react-select": "^5.8.2"
}
}
4 changes: 2 additions & 2 deletions resources/js/Pages/Servers/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PageProps, Server, User } from '@/types';
import Avatar from 'boring-avatars';
import ServerForm from './ServerForm';

export default function Edit({ server, owner }: PageProps<{ server: Server, owner?: User }>) {
export default function Edit({ server, users, owner }: PageProps<{ server: Server, users: User[], owner?: User }>) {
return (
<Authenticated title={'Edit server: ' + server.name}>
<Card
Expand All @@ -23,7 +23,7 @@ export default function Edit({ server, owner }: PageProps<{ server: Server, owne
/>
</div>
</div>
<ServerForm server={server} owner={owner} />
<ServerForm server={server} users={users} owner={owner} />
</div>
</Card>
</Authenticated>
Expand Down
10 changes: 9 additions & 1 deletion resources/js/Pages/Servers/Index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { useState } from 'react';
export default function Index({ servers }: PageProps<{ servers: Server[] }>) {
const [filter, setFilter] = useState<string>('');

console.log(servers[0]);

return (
<Authenticated title={'All Servers'}>
<div className={'mb-4 flex justify-between'}>
Expand Down Expand Up @@ -64,7 +66,13 @@ export default function Index({ servers }: PageProps<{ servers: Server[] }>) {
</div>
</th>
<td className="px-6 py-4">
{server.ownerId ?? 'None'}
{server.owner_id ? (
<Link href={`/users/${server.owner_id}`}>
User {server.owner_id}
</Link>
) : (
<>N/A</>
)}
</td>
<td className="px-6 py-4">
{server.public ? (
Expand Down
85 changes: 60 additions & 25 deletions resources/js/Pages/Servers/ServerForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import PrimaryButton from '@/Components/PrimaryButton';
import { Server, User } from '@/types';
import { router } from '@inertiajs/react';
import { useState } from 'react';
import Select, { StylesConfig } from 'react-select';

export default function ServerForm({ server, users, owner }: { server?: Server, users?: User[], owner?: User }) {
const [values, setValues] = useState({
name: server?.name ?? '',
address: server?.address ?? '',
owner_id: server?.ownerId ?? 0,
owner_id: server?.owner_id ?? 0,
public: server?.public ?? false,
});

Expand All @@ -32,6 +33,50 @@ export default function ServerForm({ server, users, owner }: { server?: Server,
}
}

const options = users?.map(user => ({
value: user.id,
label: user.email
}));

const customStyles: StylesConfig = {
control: (provided) => ({
...provided,
backgroundColor: '#27272a', // bg-zinc-800
borderColor: '#4b5563', // Default border color
boxShadow: 'none', // Remove default shadow
'&:hover': {
borderColor: '#065f46', // Change border color on hover to green-700
},
'&:focus': {
borderColor: '#065f46', // Change border color on focus to green-700
outline: 'none', // Remove outline for focus
},
}),
menu: (provided) => ({
...provided,
zIndex: 9999, // Ensure the menu is above other content
backgroundColor: '#27272a', // bg-zinc-800 for the menu
}),
option: (provided, state) => ({
...provided,
backgroundColor: state.isFocused ? '#065f46' : '#27272a', // Green-700 on focus
color: 'white', // Text color
'&:hover': {
backgroundColor: '#065f46', // Green-700 on hover
},
}),
singleValue: (provided) => ({
...provided,
color: 'white', // Text color for selected value
}),
placeholder: (provided) => ({
...provided,
color: '#a1a1aa', // gray-400 for placeholder
}),
};

console.log(values);

return (
<form
className="lg:col-span-2"
Expand Down Expand Up @@ -69,31 +114,21 @@ export default function ServerForm({ server, users, owner }: { server?: Server,
</label>
</div>
<div className="grid md:grid-cols-2 md:gap-6">
<div className="group relative z-0 mb-5 w-full">
<select
name="owner_id"
id="owner_id"
defaultValue={server?.ownerId}
className="peer block w-full appearance-none border-0 border-b-2 border-gray-300 bg-transparent px-0 py-2.5 text-sm text-gray-900 focus:border-green-600 focus:outline-none focus:ring-0 dark:border-gray-600 dark:text-white dark:focus:border-green-500"
onChange={(e) => setValues({ ...values, owner_id: parseInt(e.currentTarget.value) })}
>
{server && owner ? (
<option value={server.ownerId}>
{owner?.name} ({owner?.email})
</option>
) : (
<option value={0}></option>
<div className="group relative mb-5 w-full">
<Select
options={options}
styles={customStyles}
className={'mt-2 relative'}
placeholder={owner?.email}
isSearchable
isClearable
onChange={(e: unknown) => (

// @ts-ignore e.value is an integer
setValues({ ...values, owner_id: e?.value ?? 0 })
)}
{users?.filter(x => x.id !== owner?.id).map((user) => (
<option key={user.id} value={user.id}>{user.name} ({user.email})</option>
))}
</select>
<label
htmlFor="name"
className="absolute top-3 -z-10 origin-[0] -translate-y-6 scale-75 transform text-sm text-gray-500 duration-300 peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-focus:start-0 peer-focus:-translate-y-6 peer-focus:scale-75 peer-focus:font-medium peer-focus:text-green-600 rtl:peer-focus:translate-x-1/4 dark:text-gray-400 peer-focus:dark:text-green-500"
>
Server Owner
</label>
menuPortalTarget={document.body}
/>
</div>
<div className="mb-4 flex items-center">
<input
Expand Down
2 changes: 1 addition & 1 deletion resources/js/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface Server {
id: number;
name: string;
address: string;
ownerId: number;
owner_id: number;
public: boolean;
}

Expand Down

0 comments on commit d56f5fb

Please sign in to comment.