Backend Development

Laravel Inertia React Roles Permissions CRUD Part2

Laravel Inertia React Roles Permissions CRUD

In this part of making CRUD for Roles and Permissions in Laravel and Inertia we will continue.

 

 

Previous Part

Making the Controllers

I created two controllers for the roles and permissions and populated them with the appropriate code:

php artisan make:controller PermissionsController 
php artisan make:controller RolesController 

Next open each controller and update with the code shown below:

PermissionsController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use Inertia\Inertia;
use Spatie\Permission\Models\Permission;

class PermissionsController extends Controller
{
    public function index()
    {
        $permissions = Permission::paginate(10);

        return Inertia::render('permissions/index', [
            'permissions' => $permissions
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|min:3|unique:permissions,name'
        ]);

        $permission = Permission::create([
            'name' => $validated['name']
        ]);

        Session::flash("success", "Permission added successfully");

        return to_route('permissions.index');
    }

    public function update(Request $request, $id)
    {
        $validated = $request->validate([
            'name' => 'required|min:3|unique:permissions,name,'.$id
        ]);

        $permission = Permission::findById($id);
        $permission->name = $validated['name'];
        $permission->save();

        Session::flash("success", "Permission updated successfully");

        return to_route('permissions.index');
    }

    public function destroy($id)
    {
        $permission = Permission::findById($id);

        $permission->delete();

        Session::flash("success", "Permission deleted successfully");

        return to_route('permissions.index');
    }
}

RolesController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Inertia\Inertia;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class RolesController extends Controller
{
    public function index()
    {
        $roles = Role::paginate(10);

        return Inertia::render('roles/index', [
            'roles' => $roles
        ]);
    }

    public function create()
    {
        $permissions = Permission::all();

        return Inertia::render('roles/create', [
            'permissions' => $permissions
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
           'name' => 'required|min:3|unique:roles,name'
        ]);

        $role = Role::create($validated);

        if($request->permissions) {

            $permissions = Permission::whereIn("id", $request->permissions)->pluck('name');

            $role->syncPermissions($permissions);
        }

        return to_route('roles.index')->with("success", "Role added successfully");
    }

    public function edit($id)
    {
        $role = Role::with(['permissions'])->find($id);

        $permissions = Permission::all();

        return Inertia::render('roles/edit', [
            'role' => $role,
            'permissions' => $permissions
        ]);
    }

    public function update(Request $request, $id)
    {
        $validated = $request->validate([
            'name' => 'required|min:3|unique:roles,name,' . $id
        ]);

        $role = Role::findById($id);

        $role->name = $validated['name'];

        $role->save();

        $permissions = Permission::whereIn("id", $request->permissions)->pluck('name');

        $role->syncPermissions($permissions);

        return to_route('roles.index')->with("success", "Role updated successfully");
    }

    public function destroy($id)
    {
        $role = Role::findById($id);

        $role->delete();

        return to_route('roles.index')->with("success", "Role Deleted successfully");
    }
}

These are two laravel resource controllers, there is no magic in this code except for the call to Inertia::render() in methods like index() or create().

The Inertia::render() related to the Inertia package and render the frontend view, in this case the frontend will be a react component located in /resources/js/Pages/

Now we have to update the HandleInertiaRequests::share() method like so:

public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            'flash' => [
                'success' => fn () => $request->session()->get('success')
            ],
        ]);
    }

The share() method allows to share data globally in inertia and we can access these data in frontend as props passed to the components.

Let’s add the routes for the above controllers, so open routes/web.php and add these routes

routes/web.php

Route::middleware(['auth'])->group(function() {

    Route::prefix('permissions')->group(function () {
        Route::get('/', [\App\Http\Controllers\PermissionsController::class, 'index'])->name('permissions.index');

        Route::post("/", [\App\Http\Controllers\PermissionsController::class, 'store']);

        Route::put("/{id}", [\App\Http\Controllers\PermissionsController::class, 'update']);

        Route::delete("/{id}", [\App\Http\Controllers\PermissionsController::class, 'destroy']);
    });

    Route::prefix('roles')->group(function () {
        Route::get('/', [\App\Http\Controllers\RolesController::class, 'index'])->name('roles.index');

        Route::get('/create', [\App\Http\Controllers\RolesController::class, 'create']);

        Route::get('/{id}', [\App\Http\Controllers\RolesController::class, 'edit']);

        Route::post("/", [\App\Http\Controllers\RolesController::class, 'store']);

        Route::put("/{id}", [\App\Http\Controllers\RolesController::class, 'update']);

        Route::delete("/{id}", [\App\Http\Controllers\RolesController::class, 'destroy']);
    });

});

As you might know that Inertia requires that we declare the routes server side and it doesn’t require client side routes. Let’s move to work on the frontend part.

 

React Components

First create directory resources/js/Pages/. This is where all the React pages will be located. Then inside of Pages/ directory create these:

  • resources/js/Pages/permissions
  • resources/js/Pages/roles

 

Displaying All Permissions

Create new jsx component inside resources/js/Pages/permissions called index.jsx like so:

resources/js/Pages/permissions/index.jsx

import {useState} from "react";
import { router } from '@inertiajs/react'
import Layout from "../../shared/Layout.jsx";

export default function ListPermissions({permissions}) {

    

    return (
        <Layout>
            <div className="mx-5">
                <div className="flex justify-between my-6">
                    <h2 className="text-2xl">
                        All Permissions
                    </h2>
                    <button type="button" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Create Permission</button>
                </div>
                <div className="relative">
                    <table className="w-full text-sm text-left rtl:text-right text-gray-500">
                        <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
                        <tr>
                            <th className="px-6 py-3">#</th>
                            <th className="px-6 py-3">Name</th>
                            <th className="px-6 py-3">Guard</th>
                            <th className="px-6 py-3">Actions</th>
                        </tr>
                        </thead>
                        <tbody>
                        {
                            permissions.data.map(permission => {
                                return (
                                    <tr key={permission.id} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-600">
                                        <td className="px-6 py-4">{permission.id}</td>
                                        <td className="px-6 py-4">{permission.name}</td>
                                        <td className="px-6 py-4">{permission.guard_name}</td>
                                        <td className="px-6 py-4">
                                            <a href="#" className="bg-green-400 text-white rounded-lg hover:bg-green-800 focus:ring-4 font-medium px-2 py-1 mx-2" >Edit</a>
                                            <a href="#" className="bg-red-400 text-white rounded-lg hover:bg-red-800 focus:ring-4 font-medium px-2 py-1 mx-2">Delete</a>
                                        </td>
                                    </tr>
                                )
                            })
                        }
                        </tbody>
                    </table>

                    

                </div>

            </div>
        </Layout>

    )
}

This is page to display all permissions. You might think from where the permissions prop coming. It’s passed from the PermissionController::index() above if you check the index() method, you will it takes the view “permissions/index” and a second argument “permissions”:

return Inertia::render('permissions/index', [
            'permissions' => $permissions
        ]);

Next to render the permissions all we have to do is invoking the map() function on the permissions prop. The permissions is empty right now but we will create some permissions shortly.

 

Layout Component

In the above code we used a component called Layout to wrap our pages. Let’s create this component in a separate directory.

Create resources/js/shared/Layout.jsx

import React from "react";
import {usePage} from "@inertiajs/react";

export default function Layout({children}) {
    const { flash } = usePage().props

    return (
        <div>
            {flash.success && (
                <div className="alert bg-green-200 px-4 py-6">{flash.success}</div>
            )}

            {children}
        </div>
    )
}

The Layout component accepts the children prop. Then we access the flash data provided by laravel using usePage() hook and accessing “props” property. The flash shared from HandleInertiaRequests::share() method.

 

Adding Permissions

To add permissions i create a simple modal for this.

Create this file resources/js/Pages/permissions/create-permission.jsx

import React, {useEffect, useState} from "react";
import {router, usePage} from "@inertiajs/react";

export default function CreatePermission({onClose}) {

    const { errors } = usePage().props;

    const [form, setForm] = useState({name: ''});

    const handleSubmit = e => {
        e.preventDefault();

        router.post("/permissions", form, {
                onSuccess: () => {
                    onClose();
                }
            });
    }

    return (
        <>
            <div id="create-permission-modal" tabIndex="-1" aria-hidden="true"
                 className="overflow-y-auto overflow-x-hidden flex fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
                <div className="relative p-4 w-full max-w-md max-h-full">
                    <div className="relative bg-white rounded-lg shadow dark:bg-gray-700">
                        <div
                            className="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
                            <h3 className="text-xl font-semibold text-gray-900 dark:text-white">
                                Create Permission
                            </h3>
                            <button type="button"
                                    onClick={() => onClose()}
                                    className="end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white"
                                    data-modal-hide="authentication-modal">
                                <svg className="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
                                     fill="none" viewBox="0 0 14 14">
                                    <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round"
                                          strokeWidth="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
                                </svg>
                                <span className="sr-only">Close modal</span>
                            </button>
                        </div>

                        <div className="p-4 md:p-5">
                            <form className="space-y-4" method="post" action="#" onSubmit={handleSubmit}>
                                <div>
                                    <label htmlFor="name"
                                           className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
                                        Permission Name</label>
                                    <input type="text" name="name" value={form.name} onChange={event => { setForm({...form, [event.target.name]: event.target.value}) }  }
                                           className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
                                           />

                                    {errors.name && <div className="text-sm mt-1 text-red-600">{errors.name}</div>}
                                </div>
                                <button type="submit"
                                        className="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
                                    Submit
                                </button>
                            </form>
                        </div>

                    </div>
                </div>
            </div>

            <div  className="bg-gray-900/50 dark:bg-gray-900/80 fixed inset-0 z-40"></div>
        </>
    )
}

Don’t confused by the css classes in this component because this component is a modal styled using tailwindcss classes. The component accepts onClose prop which a custom event to close the model.

I created a react state variable form to hold the form payload. We have only one field which is the permission name, so i bound the form state name to the html input value property:

<input type="text" name="name" value={form.name} onChange={event => { setForm({...form, [event.target.name]: event.target.value}) }  } />

The handleSubmit() function triggered when the onSubmit event called. To send data to server with Inertia we don’t really use something like javascript fetch or axios but instead Inertia gives us the router Api:

router.post("/permissions", form, {
                onSuccess: () => {
                    onClose();
                }
            });

The router.post() makes a post request to server. Here we passed the route url, the data and options object. In the options object we used the onSuccess() callback which tells that the request is done successfully and we close the model.

To display the validation errors in Inertia from laravel validator, we capture the “errors” prop as you see in the top of the component:

const { errors, flash } = usePage().props;

Then we display the error below the field like so:

{errors.name && <div className="text-sm mt-1 text-red-600">{errors.name}</div>}

Now let’s include this modal in index.jsx page:

Open and update resources/js/Pages/permissions/index.jsx

import {useState} from "react";
import { router } from '@inertiajs/react'
import CreatePermission from "./create-permission.jsx";
import Layout from "../../shared/Layout.jsx";

export default function ListPermissions({permissions}) {

    const [showModal, setShowModal] = useState(undefined);

    const handleDelete = (id) => {
        if(confirm("Are you sure you want to delete?")) {
            router.delete(`/permissions/${id}`);
        }
    }

    return (
        <Layout>
            <div className="mx-5">
                <div className="flex justify-between my-6">
                    <h2 className="text-2xl">
                        All Permissions
                    </h2>
                    <button type="button" onClick={() => setShowModal(true)} className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Create Permission</button>
                </div>
                <div className="relative">
                    <table className="w-full text-sm text-left rtl:text-right text-gray-500">
                        <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
                        <tr>
                            <th className="px-6 py-3">#</th>
                            <th className="px-6 py-3">Name</th>
                            <th className="px-6 py-3">Guard</th>
                            <th className="px-6 py-3">Actions</th>
                        </tr>
                        </thead>
                        <tbody>
                        {
                            permissions.data.map(permission => {
                                return (
                                    <tr key={permission.id} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-600">
                                        <td className="px-6 py-4">{permission.id}</td>
                                        <td className="px-6 py-4">{permission.name}</td>
                                        <td className="px-6 py-4">{permission.guard_name}</td>
                                        <td className="px-6 py-4">
                                            <a href="#" onClick={event => { event.preventDefault(); setShowModal(permission) } } className="bg-green-400 text-white rounded-lg hover:bg-green-800 focus:ring-4 font-medium px-2 py-1 mx-2" >Edit</a>
                                            <a href="#" onClick={event => {event.preventDefault(); handleDelete(permission.id)} } className="bg-red-400 text-white rounded-lg hover:bg-red-800 focus:ring-4 font-medium px-2 py-1 mx-2">Delete</a>
                                        </td>
                                    </tr>
                                )
                            })
                        }
                        </tbody>
                    </table>

                </div>

                {
                    showModal !== undefined && <CreatePermission onClose={() => setShowModal(undefined)} permission={showModal} />
                }

            </div>
        </Layout>

    )
}

At this point you can add permissions by clicking on the button above the grid.

 

Updating Permissions

To update permission we will use the same modal however we will make simple additions to allow for update.

create-permission.jsx

First in the export default statement add the permission prop like so

export default function CreatePermission({onClose, permission}) 

Next as this is update we need to populate the form with the permission we have to edit. So add this code after the useState() statement:

React.useEffect(() => {
        if(permission && permission.hasOwnProperty('name')) {
            setForm({...form, name: permission.name});
        }
    }, [permission]);

Finally update the handleSubmit() function like so:

const handleSubmit = e => {
        e.preventDefault();

        // Create
        if(permission === true) {
            router.post("/permissions", form, {
                onSuccess: () => {
                    onClose();
                }
            });

            return;
        }

        router.put(`/permissions/${permission.id}`, form, {
            onSuccess: () => {
                onClose();
            }
        });
    }

Now our modal allows for adding and updating permissions.

 

Displaying Roles

Create page resources/js/Pages/roles/index.jsx

import {useState} from "react";
import {Link, router} from '@inertiajs/react'
import Layout from "../../shared/Layout.jsx";

export default function ListRoles({roles}) {

    const handleDelete = (id) => {
        if(confirm("Are you sure you want to delete?")) {
            router.delete(`/roles/${id}`);
        }
    }

    return (
        <Layout>
            <div className="mx-5">
                <div className="flex justify-between my-6">
                    <h2 className="text-2xl">
                        All Roles
                    </h2>
                    <Link href="/roles/create" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Create Role</Link>
                </div>
                <div className="relative">
                    <table className="w-full text-sm text-left rtl:text-right text-gray-500">
                        <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
                        <tr>
                            <th className="px-6 py-3">#</th>
                            <th className="px-6 py-3">Name</th>
                            <th className="px-6 py-3">Guard</th>
                            <th className="px-6 py-3">Actions</th>
                        </tr>
                        </thead>
                        <tbody>
                        {
                            roles.data.map(role => {
                                return (
                                    <tr key={role.id} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-600">
                                        <td className="px-6 py-4">{role.id}</td>
                                        <td className="px-6 py-4">{role.name}</td>
                                        <td className="px-6 py-4">{role.guard_name}</td>
                                        <td className="px-6 py-4">
                                            <Link href={`/roles/${role.id}`} className="bg-green-400 text-white rounded-lg hover:bg-green-800 focus:ring-4 font-medium px-2 py-1 mx-2">Edit</Link>
                                            <a href="#" onClick={event => {event.preventDefault(); handleDelete(role.id)} } className="bg-red-400 text-white rounded-lg hover:bg-red-800 focus:ring-4 font-medium px-2 py-1 mx-2">Delete</a>
                                        </td>
                                    </tr>
                                )
                            })
                        }
                        </tbody>
                    </table>


                </div>

            </div>
        </Layout>

    )
}

 

Adding & Updating Roles

Create file resources/js/Pages/roles/create.jsx

import React, {useState} from "react";
import {router, usePage} from '@inertiajs/react'
import Layout from "../../shared/Layout.jsx";

export default function CreateRole({permissions}) {

    const {errors} = usePage().props;

    const [form, setForm] = useState({name: '', permissions: []});

    const handleSubmit = e => {
        e.preventDefault();

        router.post("/roles", form);
    }

    const handleSelectPermission = e => {
        if(e.target.checked) {
            const checkExist = form.permissions.find(p => p == e.target.value);
            if(!checkExist) {
                setForm({...form, permissions: [...form.permissions, e.target.value] });
            }
        } else {
            const filtered = form.permissions.filter(p => p != e.target.value);
            setForm({...form, permissions: filtered});
        }
    }

    return (
        <Layout>
            <div className="mx-5">
                <div className="flex justify-between my-6">
                    <h2 className="text-2xl">
                        Create Role
                    </h2>
                </div>
                <div className="relative">
                    <form method="post" className="space-y-6" onSubmit={handleSubmit}>
                        <div className="grid grid-cols-2 gap-4">
                            <div>
                                <label className="block text-sm font-medium leading-6 text-gray-900">Role Name</label>
                                <input type="text" name="name" value={form.name} onChange={event => { setForm({...form, [event.target.name]: event.target.value}) }  } className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"/>
                                {errors.name && <div className="text-sm mt-1 text-red-600">{errors.name}</div>}

                            </div>

                            <div>
                                <h3 className="text-lg font-bold">Permissions</h3>

                                <div className="grid grid-cols-2 gap-2 mt-4">
                                    {
                                        permissions.map(permission => {
                                            return (
                                                <div key={permission.id}>
                                                    <input type="checkbox" name="permissions" value={permission.id} id={permission.name} onChange={handleSelectPermission} className="mx-2" />
                                                    <label
                                                        className="text-sm font-medium leading-6 text-gray-900" htmlFor={permission.name}>{permission.name}</label>
                                                </div>
                                            )
                                        })
                                    }
                                </div>
                            </div>
                        </div>


                        <button type="submit"
                                className="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
                            Submit
                        </button>
                    </form>
                </div>

            </div>
        </Layout>

    )
}

Create file resources/js/Pages/roles/edit.jsx

import React, {useEffect, useState} from "react";
import {router, usePage} from '@inertiajs/react'
import Layout from "../../shared/Layout.jsx";

export default function EditRole({permissions, role}) {

    const {errors} = usePage().props;

    const [form, setForm] = useState({name: role.name, permissions: []});

    useEffect(() => {
        if(role) {
            const permIds = role.permissions.map(p => p.id);

            setForm({...form, permissions: permIds});
        }
    }, [role]);

    const handleSubmit = e => {
        e.preventDefault();

        router.put(`/roles/${role.id}`, form);
    }

    const handleSelectPermission = e => {
        if(e.target.checked) {
            const checkExist = form.permissions.find(p => p == e.target.value);
            if(!checkExist) {
                setForm({...form, permissions: [...form.permissions, parseInt(e.target.value)] });
            }
        } else {
            const filtered = form.permissions.filter(p => p != parseInt(e.target.value));
            setForm({...form, permissions: filtered});
        }
    }

    return (
        <Layout>
            <div className="mx-5">
                <div className="flex justify-between my-6">
                    <h2 className="text-2xl">
                        Update Role #{role.id}
                    </h2>
                </div>
                <div className="relative">
                    <form method="post" className="space-y-6" onSubmit={handleSubmit}>
                        <div className="grid grid-cols-2 gap-4">
                            <div>
                                <label className="block text-sm font-medium leading-6 text-gray-900">Role Name</label>
                                <input type="text" name="name" value={form.name} onChange={event => { setForm({...form, [event.target.name]: event.target.value}) }  } className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"/>
                                {errors.name && <div className="text-sm mt-1 text-red-600">{errors.name}</div>}

                            </div>

                            <div>
                                <h3 className="text-lg font-bold">Permissions</h3>

                                <div className="grid grid-cols-2 gap-2 mt-4">
                                    {
                                        permissions.map(permission => {
                                            return (
                                                <div key={permission.id}>
                                                    <input type="checkbox" name="permissions" value={permission.id} id={permission.name} onChange={handleSelectPermission} checked={form.permissions.includes(permission.id)} className="mx-2" />
                                                    <label
                                                        className="text-sm font-medium leading-6 text-gray-900" htmlFor={permission.name}>{permission.name}</label>
                                                </div>
                                            )
                                        })
                                    }
                                </div>
                            </div>
                        </div>


                        <button type="submit"
                                className="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
                            Submit
                        </button>
                    </form>
                </div>

            </div>
        </Layout>

    )
}

The code now is fully functional, you can add permissions, create roles and assign permissions to roles. The final point which you can do by yourself is attaching the roles to users.

 

Sourcecode on github

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments