Browse Source

Build User Registration function

master
EJ-Dannug 3 months ago
parent
commit
fadaf8a23d
  1. 17
      app/Http/Controllers/Auth/RegisteredUserController.php
  2. 20
      app/Models/Role.php
  3. 12
      app/Models/User.php
  4. 30
      database/migrations/2024_06_09_183352_add_emp_id_and_username_to_users_table.php
  5. 28
      database/migrations/2024_06_09_184105_create_roles_table.php
  6. 31
      database/migrations/2024_06_09_184744_add_role_id_to_users_table.php
  7. 47
      package-lock.json
  8. 4
      package.json
  9. BIN
      public/assets/images/icons/ico-dropdown.png
  10. BIN
      public/assets/images/icons/ico-help.png
  11. BIN
      public/assets/images/icons/ico-search.png
  12. BIN
      public/assets/images/img-signup.png
  13. 2
      resources/js/Components/Dropdown.tsx
  14. 4
      resources/js/Components/Footer.tsx
  15. 9
      resources/js/Components/FormGroup.tsx
  16. 2
      resources/js/Components/InputError.tsx
  17. 13
      resources/js/Components/InputLabel.tsx
  18. 16
      resources/js/Components/Modal.tsx
  19. 2
      resources/js/Components/PrimaryButton.tsx
  20. 2
      resources/js/Components/TextInput.tsx
  21. 11
      resources/js/Layouts/AuthenticatedLayout.tsx
  22. 4
      resources/js/Pages/About.tsx
  23. 220
      resources/js/Pages/Auth/Register.tsx
  24. 3
      resources/js/Pages/Welcome.tsx

17
app/Http/Controllers/Auth/RegisteredUserController.php

@ -5,9 +5,8 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;
use Inertia\Inertia;
@ -28,24 +27,30 @@ class RegisteredUserController extends Controller
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request): RedirectResponse
public function store(Request $request): JsonResponse
{
$request->validate([
'emp_id' => 'required|integer',
'name' => 'required|string|max:255',
'email' => 'required|string|lowercase|email|max:255|unique:'.User::class,
'username' => 'required|string|max:255|unique:'.User::class,
'password' => ['required', 'confirmed', Rules\Password::defaults()],
'role_id' => 'required|exists:roles,id',
]);
$user = User::create([
'emp_id' => $request->emp_id,
'name' => $request->name,
'email' => $request->email,
'username' => $request->username,
'password' => Hash::make($request->password),
'role_id' => $request->role_id,
]);
event(new Registered($user));
Auth::login($user);
return redirect(route('dashboard', absolute: false));
return response()->json([
'message' => 'Registration successful! Please log in.'
]);
}
}

20
app/Models/Role.php

@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
];
}

12
app/Models/User.php

@ -17,9 +17,12 @@ class User extends Authenticatable
* @var array<int, string>
*/
protected $fillable = [
'emp_id',
'name',
'email',
'username',
'password',
'role_id',
];
/**
@ -42,6 +45,15 @@ class User extends Authenticatable
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
'role_id' => 'integer',
];
}
/**
* Get the role associated with the user.
*/
public function role()
{
return $this->belongsTo(Role::class);
}
}

30
database/migrations/2024_06_09_183352_add_emp_id_and_username_to_users_table.php

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->integer('emp_id')->default(-1)->after('id');
$table->string('username')->after('email');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('emp_id');
$table->dropColumn('username');
});
}
};

28
database/migrations/2024_06_09_184105_create_roles_table.php

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('roles');
}
};

31
database/migrations/2024_06_09_184744_add_role_id_to_users_table.php

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->unsignedBigInteger('role_id')->nullable()->after('id');
$table->foreign('role_id')->references('id')->on('roles')->onDelete('set null');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropForeign(['role_id']);
$table->dropColumn('role_id');
});
}
};

47
package-lock.json

@ -4,6 +4,10 @@
"requires": true,
"packages": {
"": {
"dependencies": {
"feather-icons-react": "^0.7.0",
"react-feather": "^2.0.10"
},
"devDependencies": {
"@headlessui/react": "^1.4.2",
"@inertiajs/react": "^1.0.0",
@ -1869,6 +1873,15 @@
"reusify": "^1.0.4"
}
},
"node_modules/feather-icons-react": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/feather-icons-react/-/feather-icons-react-0.7.0.tgz",
"integrity": "sha512-IAHpKhrpxag3gKWcZYC7zmewfjMQLI34tmrpH3+52mvC61Q4FRBjJXl1WmPyKefGnk3sbS0wiqWDD3QIHiJBaA==",
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@ -2206,8 +2219,7 @@
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/jsesc": {
"version": "2.5.2",
@ -2295,7 +2307,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
@ -2457,7 +2468,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -2705,6 +2715,16 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@ -2750,7 +2770,6 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@ -2762,7 +2781,6 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@ -2771,6 +2789,22 @@
"react": "^18.3.1"
}
},
"node_modules/react-feather": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/react-feather/-/react-feather-2.0.10.tgz",
"integrity": "sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==",
"dependencies": {
"prop-types": "^15.7.2"
},
"peerDependencies": {
"react": ">=16.8.6"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@ -2890,7 +2924,6 @@
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0"
}

4
package.json

@ -24,5 +24,9 @@
"tailwindcss": "^3.2.1",
"typescript": "^5.0.2",
"vite": "^5.0"
},
"dependencies": {
"feather-icons-react": "^0.7.0",
"react-feather": "^2.0.10"
}
}

BIN
public/assets/images/icons/ico-dropdown.png

Before

Width: 16  |  Height: 16  |  Size: 180 B

BIN
public/assets/images/icons/ico-help.png

Before

Width: 20  |  Height: 20  |  Size: 668 B

BIN
public/assets/images/icons/ico-search.png

Before

Width: 30  |  Height: 30  |  Size: 495 B

BIN
public/assets/images/img-signup.png

After

Width: 512  |  Height: 512  |  Size: 126 KiB

2
resources/js/Components/Dropdown.tsx

@ -21,7 +21,7 @@ const Dropdown = ({ children }: PropsWithChildren) => {
return (
<DropDownContext.Provider value={{ open, setOpen, toggleOpen }}>
<div className="relative btn bg-primary-background shadow-md hover:bg-neutral-10 hover:border hover:border-neutral-10">{children}</div>
<div className="relative btn bg-primary-background shadow-md hover:bg-secondary-hover hover:text-white hover:border hover:border--secondary-hover active:bg-secondary-pressed active:border-secondary-border active:text-white">{children}</div>
</DropDownContext.Provider>
);
};

4
resources/js/Components/Footer.tsx

@ -1,4 +1,5 @@
import { Link } from '@inertiajs/react';
import { HelpCircle } from 'react-feather';
export default function Footer() {
return (
@ -27,7 +28,8 @@ export default function Footer() {
<p className="font-light text-sm leading-4">Copyright © 2024 DOST. All rights reserved.</p>
<Link href="/help">
<div id="btn-help" className="btn transition rounded-badge mx-4 bg-info-background border border-info-border hover:bg-info-focus hover:border-info-border active:bg-info-focus active:border-info-focus px-4 py-2 text-info-main">
<img src="./assets/images/icons/ico-help.png" alt="Help Icon" width="20" height="20" />
{/* <img src="./assets/images/icons/ico-help.png" alt="Help Icon" width="20" height="20" /> */}
<HelpCircle stroke="#0065C1" />
<span className="font-semibold text-sm leading-5">Help</span>
</div>
</Link>

9
resources/js/Components/FormGroup.tsx

@ -0,0 +1,9 @@
import { PropsWithChildren } from 'react';
export default function FormGroup({ children }: PropsWithChildren) {
return(
<div className="form-group flex my-2">
{ children }
</div>
);
}

2
resources/js/Components/InputError.tsx

@ -2,7 +2,7 @@ import { HTMLAttributes } from 'react';
export default function InputError({ message, className = '', ...props }: HTMLAttributes<HTMLParagraphElement> & { message?: string }) {
return message ? (
<p {...props} className={'text-sm text-red-600 ' + className}>
<p {...props} className={'text-sm text-error-main ' + className}>
{message}
</p>
) : null;

13
resources/js/Components/InputLabel.tsx

@ -1,9 +1,14 @@
import { LabelHTMLAttributes } from 'react';
import { HTMLAttributes } from 'react';
export default function InputLabel({ value, className = '', children, ...props }: LabelHTMLAttributes<HTMLLabelElement> & { value?: string }) {
export default function InputLabel({ className = '', children, ...props }: HTMLAttributes<HTMLLabelElement> & { htmlFor?: string }) {
return (
<label {...props} className={`block font-medium text-sm text-gray-700 ` + className}>
{value ? value : children}
<label
{...props}
className={'bg-secondary-main h-[30px] w-[30px] flex items-center justify-center flex-shrink-0 join-item' +
className
}
>
{ children }
</label>
);
}

16
resources/js/Components/Modal.tsx

@ -7,11 +7,15 @@ export default function Modal({
maxWidth = '2xl',
closeable = true,
onClose = () => {},
styling = 'def',
className = '',
}: PropsWithChildren<{
show: boolean;
maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
closeable?: boolean;
onClose: CallableFunction;
styling?: 'def' | 'success' | 'error' | 'info' | 'warning';
className?: string;
}>) {
const close = () => {
if (closeable) {
@ -27,6 +31,14 @@ export default function Modal({
'2xl': 'sm:max-w-2xl',
}[maxWidth];
const stylingClass = {
'def': 'bg-neutral-white',
'success': 'bg-success-background border-success-border',
'error': 'bg-error-background border-error-border',
'info': 'bg-info-background border-info-border',
'warning': 'bg-warning-background border-warning-border',
}[styling];
return (
<Transition show={show} as={Fragment} leave="duration-200">
<Dialog
@ -44,7 +56,7 @@ export default function Modal({
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="absolute inset-0 bg-gray-500/75" />
<div className="absolute inset-0 bg-neutral-0 opacity-50" />
</Transition.Child>
<Transition.Child
@ -57,7 +69,7 @@ export default function Modal({
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel
className={`mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto ${maxWidthClass}`}
className={`mb-6 bg-white border-4 rounded-lg overflow-hidden shadow-xl items-center justify-center text-center transform transition-all sm:w-full sm:mx-auto ${maxWidthClass} ${stylingClass} ${className}`}
>
{children}
</Dialog.Panel>

2
resources/js/Components/PrimaryButton.tsx

@ -5,7 +5,7 @@ export default function PrimaryButton({ className = '', disabled, children, ...p
<button
{...props}
className={
`inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150 ${
`flex items-center btn bg-primary-main text-white hover:bg-primary-hover active:bg-primary-pressed ${
disabled && 'opacity-25'
} ` + className
}

2
resources/js/Components/TextInput.tsx

@ -21,7 +21,7 @@ export default forwardRef(function TextInput(
{...props}
type={type}
className={
'border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm ' +
'px-2 flex-grow w-full h-[30px] box-border bg-primary-background border border-primary-hover focus:outline-none focus:bg-neutral-10 focus:border-2 focus:border-primary-hover ' +
className
}
ref={localRef}

11
resources/js/Layouts/AuthenticatedLayout.tsx

@ -1,13 +1,15 @@
import { useState, PropsWithChildren, ReactNode } from 'react';
import { PropsWithChildren, useState } from 'react';
import ApplicationLogo from '@/Components/ApplicationLogo';
import Footer from '@/Components/Footer';
import Dropdown from '@/Components/Dropdown';
import NavLink from '@/Components/NavLink';
import { Link, usePage } from '@inertiajs/react';
import { User } from '@/types';
import { ChevronDown } from 'react-feather';
export default function Authenticated({ user, children }: PropsWithChildren<{ user: User }>) {
const { url } = usePage();
const [isHiglighted, setIsHiglighted] = useState(false);
return (
<div>
@ -32,11 +34,14 @@ export default function Authenticated({ user, children }: PropsWithChildren<{ us
<li><Dropdown>
<Dropdown.Trigger>
<button className="flex items-center py-1 px-2">
<button className="flex items-center py-1 px-2"
onMouseEnter={() => setIsHiglighted(true)}
onMouseDown={() => setIsHiglighted(true)}
onMouseLeave={() => setIsHiglighted(false)}>
<span className="font-semibold text-base leading-6 mr-4">
{user.name}
</span>
<img src="./assets/images/icons/ico-dropdown.png" alt="Dropdown Icon" className="flex-end" />
<ChevronDown stroke={isHiglighted ? "#FFFFFF" : "#000000"} />
</button>
</Dropdown.Trigger>
<Dropdown.Content>

4
resources/js/Pages/About.tsx

@ -69,7 +69,9 @@ const About = ({ auth }: PageProps) => {
<div className="stat-actions">
<div className="badge badge-lg bg-info-background text-info-main badge-outline mr-1">ReactJS</div>
<div className="badge badge-lg bg-info-background text-info-main badge-outline mr-1">TailwindCSS</div>
<div className="badge badge-lg bg-info-background text-info-main badge-outline">daisyUI</div>
<div className="badge badge-lg bg-info-background text-info-main badge-outline mr-1">daisyUI</div>
<div className="badge badge-lg bg-info-background text-info-main badge-outline mr-1">StorySet</div>
<div className="badge badge-lg bg-info-background text-info-main badge-outline">FeatherIcons</div>
</div>
</div>
</div>

220
resources/js/Pages/Auth/Register.tsx

@ -1,17 +1,25 @@
import { useEffect, FormEventHandler } from 'react';
import { useEffect, FormEventHandler, useState } from 'react';
import { Head, Link, useForm } from '@inertiajs/react';
import GuestLayout from '@/Layouts/GuestLayout';
import ProjectBanner from '@/Components/ProjectBanner';
import FormGroup from '@/Components/FormGroup';
import InputError from '@/Components/InputError';
import InputLabel from '@/Components/InputLabel';
import PrimaryButton from '@/Components/PrimaryButton';
import TextInput from '@/Components/TextInput';
import { Head, Link, useForm } from '@inertiajs/react';
import PrimaryButton from '@/Components/PrimaryButton';
import { Grid, User, Mail, AtSign, Lock, Eye, EyeOff, LogIn, Unlock, CheckCircle, XOctagon } from 'react-feather';
import axios from 'axios';
import Modal from '@/Components/Modal';
export default function Register() {
const { data, setData, post, processing, errors, reset } = useForm({
emp_id: '',
name: '',
email: '',
username: '',
password: '',
password_confirmation: '',
role_id: ''
});
useEffect(() => {
@ -20,98 +28,206 @@ export default function Register() {
};
}, []);
const submit: FormEventHandler = (e) => {
const [showPassword, setShowPassword] = useState(false);
const toggleShowPassword = () => {
setShowPassword((prevShowPassword) => !prevShowPassword);
};
const [status, setStatus] = useState('');
const [feedback, setFeedback] = useState('');
const [isSuccessModalOpen, setIsSuccessModalOpen] = useState(false);
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
const handleCloseSuccessModal = () => {
setIsSuccessModalOpen(false);
window.location.href = '/login';
};
const submit: FormEventHandler = async (e) => {
e.preventDefault();
post(route('register'));
try {
const response = await axios.post(route('register'), data);
setStatus('Success')
setFeedback(response.data.message);
setIsSuccessModalOpen(true);
} catch (error) {
setStatus('Error')
if (axios.isAxiosError(error)) {
setFeedback(error.response?.data.message || 'An error occurred');
} else {
setFeedback('An unexpected error occurred');
}
setIsErrorModalOpen(true);
}
};
return (
<GuestLayout>
<Head title="Register" />
<form onSubmit={submit}>
<div>
<InputLabel htmlFor="name" value="Name" />
<div id="Register" className="hero min-h-screen bg-secondary-main">
<div className="hero-content flex-row-reverse">
<ProjectBanner />
<div className="custom-font card w-104 shrink-0 bg-primary-background">
<div className="card-body justify-center items-center">
<img src="assets/images/img-signup.png" alt="An image that represents a sign up form from StorySet" width="250" height="250" />
<form id="SignUpForm" onSubmit={submit}>
<FormGroup>
<InputLabel htmlFor='emp_id'>
<Grid stroke="#FFFFFF" />
</InputLabel>
<TextInput
id='emp_id'
name='emp_id'
value={data.emp_id}
autoComplete='off'
placeholder='Employee ID'
required
onChange={(e) => setData('emp_id', e.target.value)}
className='border-r-0'
/>
<InputError message={errors.emp_id} className="mt-2" />
<select name="role_id" id="role_id" value={data.role_id} onChange={(e) => setData('role_id', e.target.value)}
className='px-2 py-0 flex-grow w-full h-[30px] box-border bg-primary-background border border-primary-hover focus:outline-none focus:bg-neutral-10 focus:border focus:border-primary-hover'>
<option value="" selected disabled>Select your role</option>
<option value="1">Admin</option>
<option value="2">Team Leader</option>
<option value="3">Team Member</option>
</select>
</FormGroup>
<FormGroup>
<InputLabel htmlFor='name'>
<User stroke="#FFFFFF" />
</InputLabel>
<TextInput
id="name"
name="name"
id='name'
name='name'
value={data.name}
className="mt-1 block w-full"
autoComplete="name"
isFocused={true}
onChange={(e) => setData('name', e.target.value)}
autoComplete='off'
placeholder='Full Name'
required
onChange={(e) => setData('name', e.target.value)}
/>
<InputError message={errors.name} className="mt-2" />
</div>
<div className="mt-4">
<InputLabel htmlFor="email" value="Email" />
</FormGroup>
<FormGroup>
<InputLabel htmlFor='email'>
<Mail stroke="#FFFFFF" />
</InputLabel>
<TextInput
id="email"
type="email"
name="email"
type='email'
id='email'
name='email'
value={data.email}
className="mt-1 block w-full"
autoComplete="username"
onChange={(e) => setData('email', e.target.value)}
autoComplete='off'
placeholder='Email Address'
required
onChange={(e) => setData('email', e.target.value)}
/>
<InputError message={errors.email} className="mt-2" />
</div>
</FormGroup>
<div className="mt-4">
<InputLabel htmlFor="password" value="Password" />
<FormGroup>
<InputLabel htmlFor='username'>
<AtSign stroke="#FFFFFF" />
</InputLabel>
<TextInput
id='username'
name='username'
value={data.username}
autoComplete='off'
placeholder='Username'
required
onChange={(e) => setData('username', e.target.value)}
/>
<InputError message={errors.username} className="mt-2" />
</FormGroup>
<FormGroup>
<InputLabel htmlFor='password'>
<Lock stroke="#FFFFFF" />
</InputLabel>
<TextInput
id="password"
type="password"
name="password"
type={showPassword ? "text" : "password"}
id='password'
name='password'
value={data.password}
className="mt-1 block w-full"
autoComplete="new-password"
onChange={(e) => setData('password', e.target.value)}
autoComplete='off'
placeholder='Password'
required
onChange={(e) => setData('password', e.target.value)}
className='border-r-0'
/>
<label htmlFor="showPassword" className="swap items-center border border-primary-hover border-l-0">
<input type="checkbox" name="showPassword" id="showPassword" onChange={toggleShowPassword} checked={showPassword} className='hidden' />
<Eye stroke='#002F42' className='swap-off px-1' />
<EyeOff stroke='#002F42' className='swap-on px-1' />
</label>
<InputError message={errors.password} className="mt-2" />
</div>
<div className="mt-4">
<InputLabel htmlFor="password_confirmation" value="Confirm Password" />
</FormGroup>
<FormGroup>
<InputLabel htmlFor='password_confirmation'>
<Unlock stroke="#FFFFFF" />
</InputLabel>
<TextInput
id="password_confirmation"
type="password"
name="password_confirmation"
type={"password"}
id='password_confirmation'
name='password_confirmation'
value={data.password_confirmation}
className="mt-1 block w-full"
autoComplete="new-password"
onChange={(e) => setData('password_confirmation', e.target.value)}
autoComplete='off'
placeholder='Confirm Password'
required
onChange={(e) => setData('password_confirmation', e.target.value)}
/>
<InputError message={errors.password_confirmation} className="mt-2" />
</div>
</FormGroup>
<div className="flex items-center justify-end mt-4">
<Link
href={route('login')}
className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
className="btn btn-link text-secondary-main"
>
Already registered?
</Link>
<PrimaryButton className="ms-4" disabled={processing}>
Register
<PrimaryButton type='submit' disabled={processing}>
Sign Up
<LogIn stroke='#FFFFFF' />
</PrimaryButton>
</div>
</form>
</div>
</div>
</div>
<Modal show={isSuccessModalOpen} onClose={() => setIsSuccessModalOpen(false)} maxWidth="lg" styling='success'>
<div className="p-4 flex flex-col items-center">
<CheckCircle stroke='#007505' size={80} />
<h2 className="text-xl font-bold mt-2">{ status }</h2>
<p className="mt-4">{ feedback }</p>
<button onClick={handleCloseSuccessModal} className="mt-4 w-full btn bg-success-main text-lg text-white hover:bg-success-hover active:bg-success-pressed">
Login Now
</button>
</div>
</Modal>
<Modal show={isErrorModalOpen} onClose={() => setIsErrorModalOpen(false)} maxWidth="lg" styling='error'>
<div className="p-4 flex flex-col items-center">
<XOctagon stroke='#B20000' size={80} />
<h2 className="text-xl font-bold mt-2">{ status }</h2>
<p className="mt-4">{ feedback }</p>
<button onClick={() => setIsErrorModalOpen(false)} className="mt-4 w-full btn bg-error-main text-lg text-white hover:bg-error-hover active:bg-error-pressed">
Close
</button>
</div>
</Modal>
</div>
</GuestLayout>
);
}

3
resources/js/Pages/Welcome.tsx

@ -1,5 +1,6 @@
import { Head } from '@inertiajs/react';
import Guest from '@/Layouts/GuestLayout';
import { Search } from 'react-feather';
export default function Welcome() {
return (
@ -29,7 +30,7 @@ export default function Welcome() {
className="input rounded-l-full join-item bg-primary-background w-80 border border-primary-hover focus:outline-none focus:border-4 focus:border-primary-hover focus:bg-neutral-10"
/>
<button className="btn transition join-item rounded-r-full bg-primary-main border border-primary-hover hover:bg-primary-hover hover:border-primary-hover active:bg-primary-pressed active:border-primary-hover">
<img src="assets/images/icons/ico-search.png" alt="Search Icon" className="-ml-1" />
<Search stroke="#FFFFFF" />
</button>
</div>
</div>

Loading…
Cancel
Save