init commit
This commit is contained in:
commit
74c479bc61
18
.env
Normal file
18
.env
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
APP_NAME=transcriptor
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
APP_URL=http://0.0.0.0:8004
|
||||
ASSET_URL=http://0.0.0.0:8004
|
||||
|
||||
DB_CONNECTION=mariadb
|
||||
DB_QUEUE_CONNECTION=mariadb
|
||||
DB_HOST=192.168.0.187
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=transcriptor
|
||||
DB_USERNAME=t0is
|
||||
DB_PASSWORD=Silenceisgolden555
|
||||
|
||||
APP_KEY=base64:ZbNIu92nsvQmghttxsgjENh6Aqk4xR+o6LU7Wt9mpy8=
|
||||
|
||||
|
||||
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/vendor/
|
||||
node_modules/
|
||||
package-lock.json
|
||||
composer.lock
|
||||
.idea
|
||||
/src/storage/debugbar
|
33
README.md
Normal file
33
README.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Laravel Jetstream React (Typescript) Starter Kit
|
||||
|
||||
## Introduction
|
||||
|
||||
A React starter kit based on Laravel Jetstream which provides a robust, modern starting point for building Laravel applications with a React frontend using [Inertia](https://inertiajs.com).
|
||||
|
||||
Inertia allows you to build modern, single-page React applications using classic server-side routing and controllers. This lets you enjoy the frontend power of React combined with the incredible backend productivity of Laravel and lightning-fast Vite compilation.
|
||||
|
||||
This React starter kit utilizes React 19, TypeScript, Tailwind, and the [HeadlessUI](https://headlessui.com/) component library.
|
||||
|
||||
## Getting Started
|
||||
|
||||
```bash
|
||||
laravel new --using=adrum/laravel-jetstream-react-typescript
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation for Official Laravel Jetstream can be found on the [Laravel website](https://jetstream.laravel.com/). This project is not an official Laravel Jestream starter kit, but most of the documentation for Jetstream should apply to this project as well.
|
||||
|
||||
Note: The installer has already been run for you, so you can skip the `jetstream:install` command. Feel free to disable Jetstream features you don't need in the `conifg/jetstream.php` file.
|
||||
|
||||
## Other Starter Kits
|
||||
|
||||
Check out my other Laravel starter kits:
|
||||
|
||||
- [Laravel 12+ React (Mantine) Starter Kit](https://github.com/adrum/laravel-react-mantine-starter-kit): A React starter kit based on the oficial Laravel 12 React Starter Kit which provides a robust, modern starting point for building Laravel applications with a React frontend using Inertia.
|
||||
- [Laravel Jetstream + React (Typescript) Starter Kit](https://github.com/adrum/laravel-jetstream-react-typescript): A React starter kit based on Laravel Jetstream which provides a robust, modern starting point for building Laravel applications with a React frontend using Inertia.
|
||||
- [Laravel Jetstream + React (Mantine) Starter Kit](https://github.com/adrum/laravel-jetstream-react-mantine): Same as the above, except it swaps HeadlessUI with [Mantine](https://mantine.dev).
|
||||
|
||||
## License
|
||||
|
||||
The Laravel Jetstream React (Typescript) Starter Kit starter kit is open-sourced software licensed under the MIT license.
|
53
app/Actions/Fortify/CreateNewUser.php
Normal file
53
app/Actions/Fortify/CreateNewUser.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Laravel\Fortify\Contracts\CreatesNewUsers;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
|
||||
class CreateNewUser implements CreatesNewUsers
|
||||
{
|
||||
use PasswordValidationRules;
|
||||
|
||||
/**
|
||||
* Create a newly registered user.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function create(array $input): User
|
||||
{
|
||||
Validator::make($input, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
||||
'password' => $this->passwordRules(),
|
||||
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
|
||||
])->validate();
|
||||
|
||||
return DB::transaction(function () use ($input) {
|
||||
return tap(User::create([
|
||||
'name' => $input['name'],
|
||||
'email' => $input['email'],
|
||||
'password' => Hash::make($input['password']),
|
||||
]), function (User $user) {
|
||||
$this->createTeam($user);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a personal team for the user.
|
||||
*/
|
||||
protected function createTeam(User $user): void
|
||||
{
|
||||
$user->ownedTeams()->save(Team::forceCreate([
|
||||
'user_id' => $user->id,
|
||||
'name' => explode(' ', $user->name, 2)[0]."'s Team",
|
||||
'personal_team' => true,
|
||||
]));
|
||||
}
|
||||
}
|
18
app/Actions/Fortify/PasswordValidationRules.php
Normal file
18
app/Actions/Fortify/PasswordValidationRules.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
|
||||
trait PasswordValidationRules
|
||||
{
|
||||
/**
|
||||
* Get the validation rules used to validate passwords.
|
||||
*
|
||||
* @return array<int, \Illuminate\Contracts\Validation\Rule|array<mixed>|string>
|
||||
*/
|
||||
protected function passwordRules(): array
|
||||
{
|
||||
return ['required', 'string', Password::default(), 'confirmed'];
|
||||
}
|
||||
}
|
29
app/Actions/Fortify/ResetUserPassword.php
Normal file
29
app/Actions/Fortify/ResetUserPassword.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Laravel\Fortify\Contracts\ResetsUserPasswords;
|
||||
|
||||
class ResetUserPassword implements ResetsUserPasswords
|
||||
{
|
||||
use PasswordValidationRules;
|
||||
|
||||
/**
|
||||
* Validate and reset the user's forgotten password.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function reset(User $user, array $input): void
|
||||
{
|
||||
Validator::make($input, [
|
||||
'password' => $this->passwordRules(),
|
||||
])->validate();
|
||||
|
||||
$user->forceFill([
|
||||
'password' => Hash::make($input['password']),
|
||||
])->save();
|
||||
}
|
||||
}
|
32
app/Actions/Fortify/UpdateUserPassword.php
Normal file
32
app/Actions/Fortify/UpdateUserPassword.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
|
||||
|
||||
class UpdateUserPassword implements UpdatesUserPasswords
|
||||
{
|
||||
use PasswordValidationRules;
|
||||
|
||||
/**
|
||||
* Validate and update the user's password.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function update(User $user, array $input): void
|
||||
{
|
||||
Validator::make($input, [
|
||||
'current_password' => ['required', 'string', 'current_password:web'],
|
||||
'password' => $this->passwordRules(),
|
||||
], [
|
||||
'current_password.current_password' => __('The provided password does not match your current password.'),
|
||||
])->validateWithBag('updatePassword');
|
||||
|
||||
$user->forceFill([
|
||||
'password' => Hash::make($input['password']),
|
||||
])->save();
|
||||
}
|
||||
}
|
56
app/Actions/Fortify/UpdateUserProfileInformation.php
Normal file
56
app/Actions/Fortify/UpdateUserProfileInformation.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
|
||||
|
||||
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
||||
{
|
||||
/**
|
||||
* Validate and update the given user's profile information.
|
||||
*
|
||||
* @param array<string, mixed> $input
|
||||
*/
|
||||
public function update(User $user, array $input): void
|
||||
{
|
||||
Validator::make($input, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
|
||||
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
|
||||
])->validateWithBag('updateProfileInformation');
|
||||
|
||||
if (isset($input['photo'])) {
|
||||
$user->updateProfilePhoto($input['photo']);
|
||||
}
|
||||
|
||||
if ($input['email'] !== $user->email &&
|
||||
$user instanceof MustVerifyEmail) {
|
||||
$this->updateVerifiedUser($user, $input);
|
||||
} else {
|
||||
$user->forceFill([
|
||||
'name' => $input['name'],
|
||||
'email' => $input['email'],
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given verified user's profile information.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
protected function updateVerifiedUser(User $user, array $input): void
|
||||
{
|
||||
$user->forceFill([
|
||||
'name' => $input['name'],
|
||||
'email' => $input['email'],
|
||||
'email_verified_at' => null,
|
||||
])->save();
|
||||
|
||||
$user->sendEmailVerificationNotification();
|
||||
}
|
||||
}
|
81
app/Actions/Jetstream/AddTeamMember.php
Normal file
81
app/Actions/Jetstream/AddTeamMember.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Laravel\Jetstream\Contracts\AddsTeamMembers;
|
||||
use Laravel\Jetstream\Events\AddingTeamMember;
|
||||
use Laravel\Jetstream\Events\TeamMemberAdded;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\Rules\Role;
|
||||
|
||||
class AddTeamMember implements AddsTeamMembers
|
||||
{
|
||||
/**
|
||||
* Add a new team member to the given team.
|
||||
*/
|
||||
public function add(User $user, Team $team, string $email, ?string $role = null): void
|
||||
{
|
||||
Gate::forUser($user)->authorize('addTeamMember', $team);
|
||||
|
||||
$this->validate($team, $email, $role);
|
||||
|
||||
$newTeamMember = Jetstream::findUserByEmailOrFail($email);
|
||||
|
||||
AddingTeamMember::dispatch($team, $newTeamMember);
|
||||
|
||||
$team->users()->attach(
|
||||
$newTeamMember, ['role' => $role]
|
||||
);
|
||||
|
||||
TeamMemberAdded::dispatch($team, $newTeamMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the add member operation.
|
||||
*/
|
||||
protected function validate(Team $team, string $email, ?string $role): void
|
||||
{
|
||||
Validator::make([
|
||||
'email' => $email,
|
||||
'role' => $role,
|
||||
], $this->rules(), [
|
||||
'email.exists' => __('We were unable to find a registered user with this email address.'),
|
||||
])->after(
|
||||
$this->ensureUserIsNotAlreadyOnTeam($team, $email)
|
||||
)->validateWithBag('addTeamMember');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for adding a team member.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
|
||||
*/
|
||||
protected function rules(): array
|
||||
{
|
||||
return array_filter([
|
||||
'email' => ['required', 'email', 'exists:users'],
|
||||
'role' => Jetstream::hasRoles()
|
||||
? ['required', 'string', new Role]
|
||||
: null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the user is not already on the team.
|
||||
*/
|
||||
protected function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
|
||||
{
|
||||
return function ($validator) use ($team, $email) {
|
||||
$validator->errors()->addIf(
|
||||
$team->hasUserWithEmail($email),
|
||||
'email',
|
||||
__('This user already belongs to the team.')
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
37
app/Actions/Jetstream/CreateTeam.php
Normal file
37
app/Actions/Jetstream/CreateTeam.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Laravel\Jetstream\Contracts\CreatesTeams;
|
||||
use Laravel\Jetstream\Events\AddingTeam;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
|
||||
class CreateTeam implements CreatesTeams
|
||||
{
|
||||
/**
|
||||
* Validate and create a new team for the given user.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function create(User $user, array $input): Team
|
||||
{
|
||||
Gate::forUser($user)->authorize('create', Jetstream::newTeamModel());
|
||||
|
||||
Validator::make($input, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
])->validateWithBag('createTeam');
|
||||
|
||||
AddingTeam::dispatch($user);
|
||||
|
||||
$user->switchTeam($team = $user->ownedTeams()->create([
|
||||
'name' => $input['name'],
|
||||
'personal_team' => false,
|
||||
]));
|
||||
|
||||
return $team;
|
||||
}
|
||||
}
|
17
app/Actions/Jetstream/DeleteTeam.php
Normal file
17
app/Actions/Jetstream/DeleteTeam.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use Laravel\Jetstream\Contracts\DeletesTeams;
|
||||
|
||||
class DeleteTeam implements DeletesTeams
|
||||
{
|
||||
/**
|
||||
* Delete the given team.
|
||||
*/
|
||||
public function delete(Team $team): void
|
||||
{
|
||||
$team->purge();
|
||||
}
|
||||
}
|
44
app/Actions/Jetstream/DeleteUser.php
Normal file
44
app/Actions/Jetstream/DeleteUser.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Jetstream\Contracts\DeletesTeams;
|
||||
use Laravel\Jetstream\Contracts\DeletesUsers;
|
||||
|
||||
class DeleteUser implements DeletesUsers
|
||||
{
|
||||
/**
|
||||
* Create a new action instance.
|
||||
*/
|
||||
public function __construct(protected DeletesTeams $deletesTeams)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given user.
|
||||
*/
|
||||
public function delete(User $user): void
|
||||
{
|
||||
DB::transaction(function () use ($user) {
|
||||
$this->deleteTeams($user);
|
||||
$user->deleteProfilePhoto();
|
||||
$user->tokens->each->delete();
|
||||
$user->delete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the teams and team associations attached to the user.
|
||||
*/
|
||||
protected function deleteTeams(User $user): void
|
||||
{
|
||||
$user->teams()->detach();
|
||||
|
||||
$user->ownedTeams->each(function (Team $team) {
|
||||
$this->deletesTeams->delete($team);
|
||||
});
|
||||
}
|
||||
}
|
88
app/Actions/Jetstream/InviteTeamMember.php
Normal file
88
app/Actions/Jetstream/InviteTeamMember.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Laravel\Jetstream\Contracts\InvitesTeamMembers;
|
||||
use Laravel\Jetstream\Events\InvitingTeamMember;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\Mail\TeamInvitation;
|
||||
use Laravel\Jetstream\Rules\Role;
|
||||
|
||||
class InviteTeamMember implements InvitesTeamMembers
|
||||
{
|
||||
/**
|
||||
* Invite a new team member to the given team.
|
||||
*/
|
||||
public function invite(User $user, Team $team, string $email, ?string $role = null): void
|
||||
{
|
||||
Gate::forUser($user)->authorize('addTeamMember', $team);
|
||||
|
||||
$this->validate($team, $email, $role);
|
||||
|
||||
InvitingTeamMember::dispatch($team, $email, $role);
|
||||
|
||||
$invitation = $team->teamInvitations()->create([
|
||||
'email' => $email,
|
||||
'role' => $role,
|
||||
]);
|
||||
|
||||
Mail::to($email)->send(new TeamInvitation($invitation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the invite member operation.
|
||||
*/
|
||||
protected function validate(Team $team, string $email, ?string $role): void
|
||||
{
|
||||
Validator::make([
|
||||
'email' => $email,
|
||||
'role' => $role,
|
||||
], $this->rules($team), [
|
||||
'email.unique' => __('This user has already been invited to the team.'),
|
||||
])->after(
|
||||
$this->ensureUserIsNotAlreadyOnTeam($team, $email)
|
||||
)->validateWithBag('addTeamMember');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for inviting a team member.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
|
||||
*/
|
||||
protected function rules(Team $team): array
|
||||
{
|
||||
return array_filter([
|
||||
'email' => [
|
||||
'required', 'email',
|
||||
Rule::unique(Jetstream::teamInvitationModel())->where(function (Builder $query) use ($team) {
|
||||
$query->where('team_id', $team->id);
|
||||
}),
|
||||
],
|
||||
'role' => Jetstream::hasRoles()
|
||||
? ['required', 'string', new Role]
|
||||
: null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the user is not already on the team.
|
||||
*/
|
||||
protected function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
|
||||
{
|
||||
return function ($validator) use ($team, $email) {
|
||||
$validator->errors()->addIf(
|
||||
$team->hasUserWithEmail($email),
|
||||
'email',
|
||||
__('This user already belongs to the team.')
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
51
app/Actions/Jetstream/RemoveTeamMember.php
Normal file
51
app/Actions/Jetstream/RemoveTeamMember.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Laravel\Jetstream\Contracts\RemovesTeamMembers;
|
||||
use Laravel\Jetstream\Events\TeamMemberRemoved;
|
||||
|
||||
class RemoveTeamMember implements RemovesTeamMembers
|
||||
{
|
||||
/**
|
||||
* Remove the team member from the given team.
|
||||
*/
|
||||
public function remove(User $user, Team $team, User $teamMember): void
|
||||
{
|
||||
$this->authorize($user, $team, $teamMember);
|
||||
|
||||
$this->ensureUserDoesNotOwnTeam($teamMember, $team);
|
||||
|
||||
$team->removeUser($teamMember);
|
||||
|
||||
TeamMemberRemoved::dispatch($team, $teamMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize that the user can remove the team member.
|
||||
*/
|
||||
protected function authorize(User $user, Team $team, User $teamMember): void
|
||||
{
|
||||
if (! Gate::forUser($user)->check('removeTeamMember', $team) &&
|
||||
$user->id !== $teamMember->id) {
|
||||
throw new AuthorizationException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the currently authenticated user does not own the team.
|
||||
*/
|
||||
protected function ensureUserDoesNotOwnTeam(User $teamMember, Team $team): void
|
||||
{
|
||||
if ($teamMember->id === $team->owner->id) {
|
||||
throw ValidationException::withMessages([
|
||||
'team' => [__('You may not leave a team that you created.')],
|
||||
])->errorBag('removeTeamMember');
|
||||
}
|
||||
}
|
||||
}
|
30
app/Actions/Jetstream/UpdateTeamName.php
Normal file
30
app/Actions/Jetstream/UpdateTeamName.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Laravel\Jetstream\Contracts\UpdatesTeamNames;
|
||||
|
||||
class UpdateTeamName implements UpdatesTeamNames
|
||||
{
|
||||
/**
|
||||
* Validate and update the given team's name.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*/
|
||||
public function update(User $user, Team $team, array $input): void
|
||||
{
|
||||
Gate::forUser($user)->authorize('update', $team);
|
||||
|
||||
Validator::make($input, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
])->validateWithBag('updateTeamName');
|
||||
|
||||
$team->forceFill([
|
||||
'name' => $input['name'],
|
||||
])->save();
|
||||
}
|
||||
}
|
32
app/Http/Controllers/ChannelController.php
Normal file
32
app/Http/Controllers/ChannelController.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Channel;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Video;
|
||||
|
||||
class ChannelController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of videos.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getChannels(Request $request)
|
||||
{
|
||||
// Start a query on the Video model
|
||||
$query = Channel::query();
|
||||
|
||||
if ($request->has('languages')) {
|
||||
$query->whereIn('language', $request->input('languages'));
|
||||
}
|
||||
|
||||
// Retrieve the videos (you can add pagination if desired)
|
||||
$channels = $query->get();
|
||||
|
||||
// Return the videos as a JSON response
|
||||
return response()->json($channels);
|
||||
}
|
||||
}
|
60
app/Http/Controllers/ClipController.php
Normal file
60
app/Http/Controllers/ClipController.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Clip;
|
||||
|
||||
class ClipController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of videos.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getClips(Request $request)
|
||||
{
|
||||
// Start query with a join on videos to enable ordering by external_date
|
||||
$query = Clip::query()
|
||||
->join('videos', 'clips.video_id', '=', 'videos.id')
|
||||
->with(['video', 'video.transcriptions', 'video.channel'])
|
||||
->select('clips.*') // Ensures only Clip attributes are returned
|
||||
->orderBy('videos.external_date', 'desc');
|
||||
|
||||
// Filter by channel_ids
|
||||
if ($request->has('channel_ids')) {
|
||||
$query->whereHas('video', function ($q) use ($request) {
|
||||
$q->whereIn('channel_id', $request->input('channel_ids'));
|
||||
});
|
||||
}
|
||||
|
||||
// Filter by specific video_id
|
||||
if ($request->has('video_id')) {
|
||||
$query->whereHas('video', function ($q) use ($request) {
|
||||
$q->where('id', $request->input('video_id'));
|
||||
});
|
||||
}
|
||||
|
||||
// Filter by languages (via video.channel.language)
|
||||
if ($request->has('languages')) {
|
||||
$languages = $request->input('languages');
|
||||
$query->whereHas('video.channel', function ($q) use ($languages) {
|
||||
$q->whereIn('language', $languages);
|
||||
});
|
||||
}
|
||||
|
||||
// Filter by external_date range
|
||||
if ($request->has('start_date') && $request->has('end_date')) {
|
||||
$query->whereBetween('videos.external_date', [
|
||||
$request->input('start_date'),
|
||||
$request->input('end_date'),
|
||||
]);
|
||||
}
|
||||
|
||||
// Retrieve the results (consider using paginate() for large sets)
|
||||
$clips = $query->get();
|
||||
|
||||
return response()->json($clips);
|
||||
}
|
||||
}
|
8
app/Http/Controllers/Controller.php
Normal file
8
app/Http/Controllers/Controller.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
76
app/Http/Controllers/StatsController.php
Normal file
76
app/Http/Controllers/StatsController.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\Video;
|
||||
use App\Models\Transcription;
|
||||
use App\Models\Clip;
|
||||
|
||||
class StatsController extends Controller
|
||||
{
|
||||
public function getStats()
|
||||
{
|
||||
$thirtyDaysAgo = Carbon::now()->subDays(30);
|
||||
|
||||
// 1. Average transcription duration (last 30 days, valid start & finish, min 120s)
|
||||
$transcriptionDurationAverage = Transcription::whereNotNull('transcription_start')
|
||||
->whereNotNull('transcription_finish')
|
||||
->where('transcription_start', '>=', $thirtyDaysAgo)
|
||||
->whereRaw('TIMESTAMPDIFF(SECOND, transcription_start, transcription_finish) >= 120')
|
||||
->whereRaw('transcription_start > "2025-03-26 23:59:59"')
|
||||
->selectRaw('AVG(TIMESTAMPDIFF(SECOND, transcription_start, transcription_finish)) as avg_duration')
|
||||
->value('avg_duration');
|
||||
|
||||
// 2. Average VOD processing time (last 30 days, downloaded & processed = true)
|
||||
$vodProcessingAverage = Video::where('data_downloaded', true)
|
||||
->where('processed', true)
|
||||
->where('created_at', '>=', $thirtyDaysAgo)
|
||||
->whereNotNull('created_at')
|
||||
->whereNotNull('updated_at')
|
||||
->whereRaw('updated_at > "2025-03-31 23:59:59"')
|
||||
->selectRaw('AVG(TIMESTAMPDIFF(SECOND, created_at, updated_at)) as avg_processing')
|
||||
->value('avg_processing');
|
||||
|
||||
$averageExternalDate = DB::table('videos')
|
||||
->where('data_downloaded', false)
|
||||
->whereNotNull('external_date')
|
||||
->selectRaw('AVG(UNIX_TIMESTAMP(external_date)) as avg_timestamp')
|
||||
->value('avg_timestamp');
|
||||
|
||||
$now = Carbon::now()->timestamp;
|
||||
|
||||
$vodDelayNow = $averageExternalDate ? ($now - $averageExternalDate) : null;
|
||||
|
||||
// 3. Average clip count per day (only clips from the last 30 days)
|
||||
$clipsPerDay = Clip::where('created_at', '>=', $thirtyDaysAgo)
|
||||
->selectRaw('DATE(created_at) as date, COUNT(*) as clip_count')
|
||||
->whereRaw('created_at > "2025-03-28 23:59:59"')
|
||||
->groupBy(DB::raw('DATE(created_at)'))
|
||||
->pluck('clip_count');
|
||||
|
||||
$averageClipsPerDay = $clipsPerDay->avg();
|
||||
|
||||
// 4. Count of videos: downloaded = true & false
|
||||
$videoDownloadStats = Video::selectRaw("
|
||||
SUM(CASE WHEN data_downloaded = 1 THEN 1 ELSE 0 END) as downloaded_true,
|
||||
SUM(CASE WHEN data_downloaded = 0 THEN 1 ELSE 0 END) as downloaded_false
|
||||
")->first();
|
||||
|
||||
// 5. Count of videos with processed = true
|
||||
$processedVideoCount = Video::where('processed', true)->count();
|
||||
|
||||
// Return all the stats
|
||||
return response()->json([
|
||||
'transcription_duration_average' => round($transcriptionDurationAverage, 2),
|
||||
'vod_processing_average' => round($vodDelayNow, 2),
|
||||
'clip_average_per_day' => round($averageClipsPerDay, 0),
|
||||
'video_downloaded_true' => $videoDownloadStats->downloaded_true,
|
||||
'video_downloaded_false' => $videoDownloadStats->downloaded_false,
|
||||
'processed_video_count' => $processedVideoCount,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
46
app/Http/Controllers/VideoController.php
Normal file
46
app/Http/Controllers/VideoController.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Video;
|
||||
|
||||
class VideoController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of videos.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getVideos(Request $request)
|
||||
{
|
||||
// Start a query on the Video model
|
||||
$query = Video::with(['clips', 'transcriptions', 'channel']);
|
||||
|
||||
// Filter by channel_id if provided
|
||||
if ($request->has('channel_ids')) {
|
||||
$query->whereIn('channel_id', $request->input('channel_ids'));
|
||||
}
|
||||
|
||||
// Filter by language if provided
|
||||
// Assuming that the Video model has a relationship to Channel
|
||||
// and the Channel model has a 'language' attribute
|
||||
if ($request->has('languages')) {
|
||||
$languages = $request->input('languages');
|
||||
$query->whereHas('channel', function ($q) use ($languages) {
|
||||
$q->whereIn('language', $languages);
|
||||
});
|
||||
}
|
||||
|
||||
if($request->has('start_date') && $request->has('end_date')) {
|
||||
$query->whereBetween('external_date', [$request->input('start_date'), $request->input('end_date')]);
|
||||
}
|
||||
|
||||
// Retrieve the videos (you can add pagination if desired)
|
||||
$videos = $query->orderBy('external_date', 'desc')->get();
|
||||
|
||||
// Return the videos as a JSON response
|
||||
return response()->json($videos);
|
||||
}
|
||||
}
|
41
app/Http/Middleware/HandleInertiaRequests.php
Normal file
41
app/Http/Middleware/HandleInertiaRequests.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Middleware;
|
||||
use Tighten\Ziggy\Ziggy;
|
||||
|
||||
class HandleInertiaRequests extends Middleware
|
||||
{
|
||||
/**
|
||||
* The root template that is loaded on the first page visit.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rootView = 'app';
|
||||
|
||||
/**
|
||||
* Determine the current asset version.
|
||||
*/
|
||||
public function version(Request $request): ?string
|
||||
{
|
||||
return parent::version($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the props that are shared by default.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function share(Request $request): array
|
||||
{
|
||||
return [
|
||||
...parent::share($request),
|
||||
'ziggy' => fn () => [
|
||||
...(new Ziggy)->toArray(),
|
||||
'location' => $request->url(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
28
app/Models/Channel.php
Normal file
28
app/Models/Channel.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Channel extends Model
|
||||
{
|
||||
protected $table = 'channels';
|
||||
|
||||
protected $fillable = [
|
||||
'channel_name',
|
||||
'twitch_name',
|
||||
'youtube_name',
|
||||
'twitch_id',
|
||||
'youtube_id',
|
||||
'language',
|
||||
'fetching_enabled',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the videos for the channel.
|
||||
*/
|
||||
public function videos()
|
||||
{
|
||||
return $this->hasMany(Video::class);
|
||||
}
|
||||
}
|
24
app/Models/Clip.php
Normal file
24
app/Models/Clip.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Clip extends Model
|
||||
{
|
||||
protected $table = 'clips';
|
||||
|
||||
protected $fillable = [
|
||||
'video_id',
|
||||
'filename',
|
||||
'gdrive_file_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the video that owns the clip.
|
||||
*/
|
||||
public function video()
|
||||
{
|
||||
return $this->belongsTo(Video::class);
|
||||
}
|
||||
}
|
15
app/Models/Membership.php
Normal file
15
app/Models/Membership.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Laravel\Jetstream\Membership as JetstreamMembership;
|
||||
|
||||
class Membership extends JetstreamMembership
|
||||
{
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $incrementing = true;
|
||||
}
|
48
app/Models/Team.php
Normal file
48
app/Models/Team.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Laravel\Jetstream\Events\TeamCreated;
|
||||
use Laravel\Jetstream\Events\TeamDeleted;
|
||||
use Laravel\Jetstream\Events\TeamUpdated;
|
||||
use Laravel\Jetstream\Team as JetstreamTeam;
|
||||
|
||||
class Team extends JetstreamTeam
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\TeamFactory> */
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'personal_team',
|
||||
];
|
||||
|
||||
/**
|
||||
* The event map for the model.
|
||||
*
|
||||
* @var array<string, class-string>
|
||||
*/
|
||||
protected $dispatchesEvents = [
|
||||
'created' => TeamCreated::class,
|
||||
'updated' => TeamUpdated::class,
|
||||
'deleted' => TeamDeleted::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'personal_team' => 'boolean',
|
||||
];
|
||||
}
|
||||
}
|
28
app/Models/TeamInvitation.php
Normal file
28
app/Models/TeamInvitation.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\TeamInvitation as JetstreamTeamInvitation;
|
||||
|
||||
class TeamInvitation extends JetstreamTeamInvitation
|
||||
{
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'email',
|
||||
'role',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the team that the invitation belongs to.
|
||||
*/
|
||||
public function team(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Jetstream::teamModel());
|
||||
}
|
||||
}
|
28
app/Models/Transcription.php
Normal file
28
app/Models/Transcription.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Transcription extends Model
|
||||
{
|
||||
protected $table = 'transcriptions';
|
||||
|
||||
// If you prefer to manage the timestamps manually since your "created_at" is named "transcription_start"
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
'video_id',
|
||||
'filename',
|
||||
'transcription_start',
|
||||
'transcription_finish',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the video that owns the transcription.
|
||||
*/
|
||||
public function video()
|
||||
{
|
||||
return $this->belongsTo(Video::class);
|
||||
}
|
||||
}
|
69
app/Models/User.php
Normal file
69
app/Models/User.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Fortify\TwoFactorAuthenticatable;
|
||||
use Laravel\Jetstream\HasProfilePhoto;
|
||||
use Laravel\Jetstream\HasTeams;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens;
|
||||
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasFactory;
|
||||
use HasProfilePhoto;
|
||||
use HasTeams;
|
||||
use Notifiable;
|
||||
use TwoFactorAuthenticatable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
'two_factor_recovery_codes',
|
||||
'two_factor_secret',
|
||||
];
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $appends = [
|
||||
'profile_photo_url',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
}
|
46
app/Models/Video.php
Normal file
46
app/Models/Video.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Video extends Model
|
||||
{
|
||||
protected $table = 'videos';
|
||||
|
||||
protected $fillable = [
|
||||
'channel_id',
|
||||
'external_id',
|
||||
'external_date',
|
||||
'name',
|
||||
'url',
|
||||
'length',
|
||||
'data_downloading',
|
||||
'data_downloaded',
|
||||
'processed',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the channel that owns the video.
|
||||
*/
|
||||
public function channel()
|
||||
{
|
||||
return $this->belongsTo(Channel::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the transcriptions for the video.
|
||||
*/
|
||||
public function transcriptions()
|
||||
{
|
||||
return $this->hasMany(Transcription::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the clips for the video.
|
||||
*/
|
||||
public function clips()
|
||||
{
|
||||
return $this->hasMany(Clip::class);
|
||||
}
|
||||
}
|
76
app/Policies/TeamPolicy.php
Normal file
76
app/Policies/TeamPolicy.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class TeamPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Team $team): bool
|
||||
{
|
||||
return $user->belongsToTeam($team);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Team $team): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can add team members.
|
||||
*/
|
||||
public function addTeamMember(User $user, Team $team): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update team member permissions.
|
||||
*/
|
||||
public function updateTeamMember(User $user, Team $team): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can remove team members.
|
||||
*/
|
||||
public function removeTeamMember(User $user, Team $team): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Team $team): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
}
|
||||
}
|
24
app/Providers/AppServiceProvider.php
Normal file
24
app/Providers/AppServiceProvider.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
46
app/Providers/FortifyServiceProvider.php
Normal file
46
app/Providers/FortifyServiceProvider.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Actions\Fortify\CreateNewUser;
|
||||
use App\Actions\Fortify\ResetUserPassword;
|
||||
use App\Actions\Fortify\UpdateUserPassword;
|
||||
use App\Actions\Fortify\UpdateUserProfileInformation;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Fortify\Fortify;
|
||||
|
||||
class FortifyServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Fortify::createUsersUsing(CreateNewUser::class);
|
||||
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
|
||||
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
|
||||
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
|
||||
|
||||
RateLimiter::for('login', function (Request $request) {
|
||||
$throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());
|
||||
|
||||
return Limit::perMinute(5)->by($throttleKey);
|
||||
});
|
||||
|
||||
RateLimiter::for('two-factor', function (Request $request) {
|
||||
return Limit::perMinute(5)->by($request->session()->get('login.id'));
|
||||
});
|
||||
}
|
||||
}
|
61
app/Providers/JetstreamServiceProvider.php
Normal file
61
app/Providers/JetstreamServiceProvider.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Actions\Jetstream\AddTeamMember;
|
||||
use App\Actions\Jetstream\CreateTeam;
|
||||
use App\Actions\Jetstream\DeleteTeam;
|
||||
use App\Actions\Jetstream\DeleteUser;
|
||||
use App\Actions\Jetstream\InviteTeamMember;
|
||||
use App\Actions\Jetstream\RemoveTeamMember;
|
||||
use App\Actions\Jetstream\UpdateTeamName;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
|
||||
class JetstreamServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->configurePermissions();
|
||||
|
||||
Jetstream::createTeamsUsing(CreateTeam::class);
|
||||
Jetstream::updateTeamNamesUsing(UpdateTeamName::class);
|
||||
Jetstream::addTeamMembersUsing(AddTeamMember::class);
|
||||
Jetstream::inviteTeamMembersUsing(InviteTeamMember::class);
|
||||
Jetstream::removeTeamMembersUsing(RemoveTeamMember::class);
|
||||
Jetstream::deleteTeamsUsing(DeleteTeam::class);
|
||||
Jetstream::deleteUsersUsing(DeleteUser::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the roles and permissions that are available within the application.
|
||||
*/
|
||||
protected function configurePermissions(): void
|
||||
{
|
||||
Jetstream::defaultApiTokenPermissions(['read']);
|
||||
|
||||
Jetstream::role('admin', 'Administrator', [
|
||||
'create',
|
||||
'read',
|
||||
'update',
|
||||
'delete',
|
||||
])->description('Administrator users can perform any action.');
|
||||
|
||||
Jetstream::role('editor', 'Editor', [
|
||||
'read',
|
||||
'create',
|
||||
'update',
|
||||
])->description('Editor users have the ability to read, create, and update.');
|
||||
}
|
||||
}
|
18
artisan
Executable file
18
artisan
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the command...
|
||||
/** @var Application $app */
|
||||
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||
|
||||
$status = $app->handleCommand(new ArgvInput);
|
||||
|
||||
exit($status);
|
24
bootstrap/app.php
Normal file
24
bootstrap/app.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->web(append: [
|
||||
\App\Http\Middleware\HandleInertiaRequests::class,
|
||||
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
|
||||
]);
|
||||
|
||||
//
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
})->create();
|
2
bootstrap/cache/.gitignore
vendored
Normal file
2
bootstrap/cache/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
7
bootstrap/providers.php
Normal file
7
bootstrap/providers.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\FortifyServiceProvider::class,
|
||||
App\Providers\JetstreamServiceProvider::class,
|
||||
];
|
48
bootstrap/ssr/app.js
Normal file
48
bootstrap/ssr/app.js
Normal file
@ -0,0 +1,48 @@
|
||||
var _a;
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import axios from "axios";
|
||||
import _ from "lodash";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { createInertiaApp } from "@inertiajs/react";
|
||||
import { createContext, useContext } from "react";
|
||||
window._ = _;
|
||||
window.axios = axios;
|
||||
window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
|
||||
const RouteContext = createContext(null);
|
||||
function useRoute() {
|
||||
const fn = useContext(RouteContext);
|
||||
if (!fn) {
|
||||
throw new Error("Route function must be provided");
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
async function resolvePageComponent(path, pages) {
|
||||
for (const p of Array.isArray(path) ? path : [path]) {
|
||||
const page = pages[p];
|
||||
if (typeof page === "undefined") {
|
||||
continue;
|
||||
}
|
||||
return typeof page === "function" ? page() : page;
|
||||
}
|
||||
throw new Error(`Page not found: ${path}`);
|
||||
}
|
||||
const appName = ((_a = window.document.getElementsByTagName("title")[0]) == null ? void 0 : _a.innerText) || "Laravel";
|
||||
createInertiaApp({
|
||||
title: (title) => `${title} - ${appName}`,
|
||||
progress: {
|
||||
color: "#4B5563"
|
||||
},
|
||||
resolve: (name) => resolvePageComponent(
|
||||
`./Pages/${name}.tsx`,
|
||||
/* @__PURE__ */ Object.assign({ "./Pages/API/Index.tsx": () => import("./assets/Index-CwIeEkIw.js"), "./Pages/API/Partials/APITokenManager.tsx": () => import("./assets/APITokenManager-iZxUx3eK.js"), "./Pages/Auth/ConfirmPassword.tsx": () => import("./assets/ConfirmPassword-ju6YtACP.js"), "./Pages/Auth/ForgotPassword.tsx": () => import("./assets/ForgotPassword-BhYnh0qc.js"), "./Pages/Auth/Login.tsx": () => import("./assets/Login-P_qEmbLO.js"), "./Pages/Auth/Register.tsx": () => import("./assets/Register-anJ95HWS.js"), "./Pages/Auth/ResetPassword.tsx": () => import("./assets/ResetPassword-DAOSACWm.js"), "./Pages/Auth/TwoFactorChallenge.tsx": () => import("./assets/TwoFactorChallenge-Tkr6HCx-.js"), "./Pages/Auth/VerifyEmail.tsx": () => import("./assets/VerifyEmail--hB-n-6S.js"), "./Pages/Dashboard.tsx": () => import("./assets/Dashboard-CkDsUhZk.js"), "./Pages/PrivacyPolicy.tsx": () => import("./assets/PrivacyPolicy-DYEevN3b.js"), "./Pages/Profile/Partials/DeleteUserForm.tsx": () => import("./assets/DeleteUserForm-Ptw0GKXr.js"), "./Pages/Profile/Partials/LogoutOtherBrowserSessionsForm.tsx": () => import("./assets/LogoutOtherBrowserSessionsForm-Bd8DyQdZ.js"), "./Pages/Profile/Partials/TwoFactorAuthenticationForm.tsx": () => import("./assets/TwoFactorAuthenticationForm-BLalZpWn.js"), "./Pages/Profile/Partials/UpdatePasswordForm.tsx": () => import("./assets/UpdatePasswordForm-B_100APE.js"), "./Pages/Profile/Partials/UpdateProfileInformationForm.tsx": () => import("./assets/UpdateProfileInformationForm-g6OOT46r.js"), "./Pages/Profile/Show.tsx": () => import("./assets/Show-DAwzGQF4.js"), "./Pages/Teams/Create.tsx": () => import("./assets/Create-Bq48ODsT.js"), "./Pages/Teams/Partials/CreateTeamForm.tsx": () => import("./assets/CreateTeamForm-CmUI_Zfp.js"), "./Pages/Teams/Partials/DeleteTeamForm.tsx": () => import("./assets/DeleteTeamForm-CDG-Mx5L.js"), "./Pages/Teams/Partials/TeamMemberManager.tsx": () => import("./assets/TeamMemberManager-vS8Og7eY.js"), "./Pages/Teams/Partials/UpdateTeamNameForm.tsx": () => import("./assets/UpdateTeamNameForm-CArH28KV.js"), "./Pages/Teams/Show.tsx": () => import("./assets/Show-C_aCmrEJ.js"), "./Pages/TermsOfService.tsx": () => import("./assets/TermsOfService-CfLQttvD.js"), "./Pages/Welcome.tsx": () => import("./assets/Welcome-Bnby2VG4.js") })
|
||||
),
|
||||
setup({ el, App, props }) {
|
||||
const root = createRoot(el);
|
||||
return root.render(
|
||||
/* @__PURE__ */ jsx(RouteContext.Provider, { value: window.route, children: /* @__PURE__ */ jsx(App, { ...props }) })
|
||||
);
|
||||
}
|
||||
});
|
||||
export {
|
||||
useRoute as u
|
||||
};
|
306
bootstrap/ssr/assets/APITokenManager-iZxUx3eK.js
Normal file
306
bootstrap/ssr/assets/APITokenManager-iZxUx3eK.js
Normal file
@ -0,0 +1,306 @@
|
||||
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState } from "react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as ActionMessage } from "./ActionMessage-s_mcCJ3s.js";
|
||||
import { A as ActionSection } from "./Modal-D5yHmTM4.js";
|
||||
import { C as Checkbox } from "./Checkbox-XR8K_oHK.js";
|
||||
import { C as ConfirmationModal } from "./ConfirmationModal-BYr2Juy2.js";
|
||||
import { D as DangerButton } from "./DangerButton-BAZynYAq.js";
|
||||
import { D as DialogModal } from "./DialogModal-D0pyMzH2.js";
|
||||
import { F as FormSection } from "./FormSection-DI6t3wFC.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { S as SecondaryButton } from "./SecondaryButton-G68tKuYQ.js";
|
||||
import { S as SectionBorder } from "./SectionBorder-Dh4nHf2e.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "@headlessui/react";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "react-dom";
|
||||
function APITokenManager({
|
||||
tokens,
|
||||
availablePermissions,
|
||||
defaultPermissions
|
||||
}) {
|
||||
var _a, _b, _c;
|
||||
const route = useRoute();
|
||||
const createApiTokenForm = useForm({
|
||||
name: "",
|
||||
permissions: defaultPermissions
|
||||
});
|
||||
const updateApiTokenForm = useForm({
|
||||
permissions: []
|
||||
});
|
||||
const deleteApiTokenForm = useForm({});
|
||||
const [displayingToken, setDisplayingToken] = useState(false);
|
||||
const [managingPermissionsFor, setManagingPermissionsFor] = useState(null);
|
||||
const [apiTokenBeingDeleted, setApiTokenBeingDeleted] = useState(null);
|
||||
const page = useTypedPage();
|
||||
function createApiToken() {
|
||||
createApiTokenForm.post(route("api-tokens.store"), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
setDisplayingToken(true);
|
||||
createApiTokenForm.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
function manageApiTokenPermissions(token) {
|
||||
updateApiTokenForm.setData("permissions", token.abilities);
|
||||
setManagingPermissionsFor(token);
|
||||
}
|
||||
function updateApiToken() {
|
||||
if (!managingPermissionsFor) {
|
||||
return;
|
||||
}
|
||||
updateApiTokenForm.put(
|
||||
route("api-tokens.update", [managingPermissionsFor]),
|
||||
{
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
onSuccess: () => setManagingPermissionsFor(null)
|
||||
}
|
||||
);
|
||||
}
|
||||
function confirmApiTokenDeletion(token) {
|
||||
setApiTokenBeingDeleted(token);
|
||||
}
|
||||
function deleteApiToken() {
|
||||
if (!apiTokenBeingDeleted) {
|
||||
return;
|
||||
}
|
||||
deleteApiTokenForm.delete(
|
||||
route("api-tokens.destroy", [apiTokenBeingDeleted]),
|
||||
{
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
onSuccess: () => setApiTokenBeingDeleted(null)
|
||||
}
|
||||
);
|
||||
}
|
||||
return /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsxs(
|
||||
FormSection,
|
||||
{
|
||||
onSubmit: createApiToken,
|
||||
title: "Create API Token",
|
||||
description: "API tokens allow third-party services to authenticate with our application on your behalf.",
|
||||
renderActions: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
ActionMessage,
|
||||
{
|
||||
on: createApiTokenForm.recentlySuccessful,
|
||||
className: "mr-3",
|
||||
children: "Created."
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({
|
||||
"opacity-25": createApiTokenForm.processing
|
||||
}),
|
||||
disabled: createApiTokenForm.processing,
|
||||
children: "Create"
|
||||
}
|
||||
)
|
||||
] }),
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "name", children: "Name" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "name",
|
||||
type: "text",
|
||||
className: "mt-1 block w-full",
|
||||
value: createApiTokenForm.data.name,
|
||||
onChange: (e) => createApiTokenForm.setData("name", e.currentTarget.value),
|
||||
autoFocus: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
InputError,
|
||||
{
|
||||
message: createApiTokenForm.errors.name,
|
||||
className: "mt-2"
|
||||
}
|
||||
)
|
||||
] }),
|
||||
availablePermissions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "col-span-6", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "permissions", children: "Permissions" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-2 grid grid-cols-1 md:grid-cols-2 gap-4", children: availablePermissions.map((permission) => /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("label", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
Checkbox,
|
||||
{
|
||||
value: permission,
|
||||
checked: createApiTokenForm.data.permissions.includes(
|
||||
permission
|
||||
),
|
||||
onChange: (e) => {
|
||||
if (createApiTokenForm.data.permissions.includes(
|
||||
e.currentTarget.value
|
||||
)) {
|
||||
createApiTokenForm.setData(
|
||||
"permissions",
|
||||
createApiTokenForm.data.permissions.filter(
|
||||
(p) => p !== e.currentTarget.value
|
||||
)
|
||||
);
|
||||
} else {
|
||||
createApiTokenForm.setData("permissions", [
|
||||
e.currentTarget.value,
|
||||
...createApiTokenForm.data.permissions
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("span", { className: "ml-2 text-sm text-gray-600 dark:text-gray-400", children: permission })
|
||||
] }) }, permission)) })
|
||||
] })
|
||||
]
|
||||
}
|
||||
),
|
||||
tokens.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(SectionBorder, {}),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-10 sm:mt-0", children: /* @__PURE__ */ jsx(
|
||||
ActionSection,
|
||||
{
|
||||
title: "Manage API Tokens",
|
||||
description: "You may delete any of your existing tokens if they are no longer needed.",
|
||||
children: /* @__PURE__ */ jsx("div", { className: "space-y-6", children: tokens.map((token) => /* @__PURE__ */ jsxs(
|
||||
"div",
|
||||
{
|
||||
className: "flex items-center justify-between",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "break-all dark:text-white", children: token.name }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
token.last_used_ago && /* @__PURE__ */ jsxs("div", { className: "text-sm text-gray-400", children: [
|
||||
"Last used ",
|
||||
token.last_used_ago
|
||||
] }),
|
||||
availablePermissions.length > 0 ? /* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: "cursor-pointer ml-6 text-sm text-gray-400 underline",
|
||||
onClick: () => manageApiTokenPermissions(token),
|
||||
children: "Permissions"
|
||||
}
|
||||
) : null,
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: "cursor-pointer ml-6 text-sm text-red-500",
|
||||
onClick: () => confirmApiTokenDeletion(token),
|
||||
children: "Delete"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
},
|
||||
token.id
|
||||
)) })
|
||||
}
|
||||
) })
|
||||
] }) : null,
|
||||
/* @__PURE__ */ jsxs(
|
||||
DialogModal,
|
||||
{
|
||||
isOpen: displayingToken,
|
||||
onClose: () => setDisplayingToken(false),
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs(DialogModal.Content, { title: "API Token", children: [
|
||||
/* @__PURE__ */ jsx("div", { children: "Please copy your new API token. For your security, it won't be shown again." }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-4 bg-gray-100 dark:bg-gray-900 px-4 py-2 rounded-sm font-mono text-sm text-gray-500", children: (_c = (_b = (_a = page.props) == null ? void 0 : _a.jetstream) == null ? void 0 : _b.flash) == null ? void 0 : _c.token })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx(DialogModal.Footer, { children: /* @__PURE__ */ jsx(SecondaryButton, { onClick: () => setDisplayingToken(false), children: "Close" }) })
|
||||
]
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs(
|
||||
DialogModal,
|
||||
{
|
||||
isOpen: !!managingPermissionsFor,
|
||||
onClose: () => setManagingPermissionsFor(null),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(DialogModal.Content, { title: "API Token Permissions", children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: availablePermissions.map((permission) => /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("label", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
Checkbox,
|
||||
{
|
||||
value: permission,
|
||||
checked: updateApiTokenForm.data.permissions.includes(
|
||||
permission
|
||||
),
|
||||
onChange: (e) => {
|
||||
if (updateApiTokenForm.data.permissions.includes(
|
||||
e.currentTarget.value
|
||||
)) {
|
||||
updateApiTokenForm.setData(
|
||||
"permissions",
|
||||
updateApiTokenForm.data.permissions.filter(
|
||||
(p) => p !== e.currentTarget.value
|
||||
)
|
||||
);
|
||||
} else {
|
||||
updateApiTokenForm.setData("permissions", [
|
||||
e.currentTarget.value,
|
||||
...updateApiTokenForm.data.permissions
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("span", { className: "ml-2 text-sm text-gray-600 dark:text-gray-400", children: permission })
|
||||
] }) }, permission)) }) }),
|
||||
/* @__PURE__ */ jsxs(DialogModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: () => setManagingPermissionsFor(null), children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
onClick: updateApiToken,
|
||||
className: classNames("ml-2", {
|
||||
"opacity-25": updateApiTokenForm.processing
|
||||
}),
|
||||
disabled: updateApiTokenForm.processing,
|
||||
children: "Save"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs(
|
||||
ConfirmationModal,
|
||||
{
|
||||
isOpen: !!apiTokenBeingDeleted,
|
||||
onClose: () => setApiTokenBeingDeleted(null),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(ConfirmationModal.Content, { title: "Delete API Token", children: "Are you sure you would like to delete this API token?" }),
|
||||
/* @__PURE__ */ jsxs(ConfirmationModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: () => setApiTokenBeingDeleted(null), children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
DangerButton,
|
||||
{
|
||||
onClick: deleteApiToken,
|
||||
className: classNames("ml-2", {
|
||||
"opacity-25": deleteApiTokenForm.processing
|
||||
}),
|
||||
disabled: deleteApiTokenForm.processing,
|
||||
children: "Delete"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
}
|
||||
)
|
||||
] });
|
||||
}
|
||||
export {
|
||||
APITokenManager as default
|
||||
};
|
21
bootstrap/ssr/assets/ActionMessage-s_mcCJ3s.js
Normal file
21
bootstrap/ssr/assets/ActionMessage-s_mcCJ3s.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import { Transition } from "@headlessui/react";
|
||||
function ActionMessage({
|
||||
on,
|
||||
className,
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(
|
||||
Transition,
|
||||
{
|
||||
show: on,
|
||||
leave: "transition ease-in duration-1000",
|
||||
"leave-from-class": "opacity-100",
|
||||
leaveTo: "opacity-0",
|
||||
children: /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-600 dark:text-gray-400", children })
|
||||
}
|
||||
) });
|
||||
}
|
||||
export {
|
||||
ActionMessage as A
|
||||
};
|
591
bootstrap/ssr/assets/AppLayout-DitNPgwT.js
Normal file
591
bootstrap/ssr/assets/AppLayout-DitNPgwT.js
Normal file
@ -0,0 +1,591 @@
|
||||
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
||||
import { router } from "@inertiajs/core";
|
||||
import { Link, Head } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState } from "react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import { Transition } from "@headlessui/react";
|
||||
function ApplicationMark(props) {
|
||||
return /* @__PURE__ */ jsxs(
|
||||
"svg",
|
||||
{
|
||||
viewBox: "0 0 48 48",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
...props,
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M11.395 44.428C4.557 40.198 0 32.632 0 24 0 10.745 10.745 0 24 0a23.891 23.891 0 0113.997 4.502c-.2 17.907-11.097 33.245-26.602 39.926z",
|
||||
fill: "#6875F5"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M14.134 45.885A23.914 23.914 0 0024 48c13.255 0 24-10.745 24-24 0-3.516-.756-6.856-2.115-9.866-4.659 15.143-16.608 27.092-31.75 31.751z",
|
||||
fill: "#6875F5"
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
function Banner() {
|
||||
var _a, _b;
|
||||
const [show, setShow] = useState(true);
|
||||
const { props } = useTypedPage();
|
||||
const style = ((_a = props.jetstream.flash) == null ? void 0 : _a.bannerStyle) || "success";
|
||||
const message = ((_b = props.jetstream.flash) == null ? void 0 : _b.banner) || "";
|
||||
return /* @__PURE__ */ jsx("div", { children: show && message ? /* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: classNames({
|
||||
"bg-indigo-500": style == "success",
|
||||
"bg-red-700": style == "danger"
|
||||
}),
|
||||
children: /* @__PURE__ */ jsx("div", { className: "max-w-(--breakpoint-xl) mx-auto py-2 px-3 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between flex-wrap", children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "w-0 flex-1 flex items-center min-w-0", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"span",
|
||||
{
|
||||
className: classNames("flex p-2 rounded-lg", {
|
||||
"bg-indigo-600": style == "success",
|
||||
"bg-red-600": style == "danger"
|
||||
}),
|
||||
children: (() => {
|
||||
switch (style) {
|
||||
case "success":
|
||||
return /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "h-5 w-5 text-white",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
stroke: "currentColor",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
case "danger":
|
||||
return /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "h-5 w-5 text-white",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
stroke: "currentColor",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
})()
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("p", { className: "ml-3 font-medium text-sm text-white truncate", children: message })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "shrink-0 sm:ml-3", children: /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: classNames(
|
||||
"-mr-1 flex p-2 rounded-md focus:outline-hidden sm:-mr-2 transition",
|
||||
{
|
||||
"hover:bg-indigo-600 focus:bg-indigo-600": style == "success",
|
||||
"hover:bg-red-600 focus:bg-red-600": style == "danger"
|
||||
}
|
||||
),
|
||||
"aria-label": "Dismiss",
|
||||
onClick: (e) => {
|
||||
e.preventDefault();
|
||||
setShow(false);
|
||||
},
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "h-5 w-5 text-white",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
stroke: "currentColor",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
d: "M6 18L18 6M6 6l12 12"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
) })
|
||||
] }) })
|
||||
}
|
||||
) : null });
|
||||
}
|
||||
function Dropdown({
|
||||
align = "right",
|
||||
width = "48",
|
||||
contentClasses = "py-1 bg-white dark:bg-gray-700",
|
||||
renderTrigger,
|
||||
children
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const widthClass = {
|
||||
"48": "w-48"
|
||||
}[width.toString()];
|
||||
const alignmentClasses = (() => {
|
||||
if (align === "left") {
|
||||
return "origin-top-left left-0";
|
||||
} else if (align === "right") {
|
||||
return "origin-top-right right-0";
|
||||
} else {
|
||||
return "origin-top";
|
||||
}
|
||||
})();
|
||||
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
||||
/* @__PURE__ */ jsx("div", { onClick: () => setOpen(!open), children: renderTrigger() }),
|
||||
/* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: "fixed inset-0 z-40",
|
||||
style: { display: open ? "block" : "none" },
|
||||
onClick: () => setOpen(false)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
Transition,
|
||||
{
|
||||
show: open,
|
||||
enter: "transition ease-out duration-200",
|
||||
enterFrom: "transform opacity-0 scale-95",
|
||||
enterTo: "transform opacity-100 scale-100",
|
||||
leave: "transition ease-in duration-75",
|
||||
leaveFrom: "transform opacity-100 scale-100",
|
||||
leaveTo: "transform opacity-0 scale-95",
|
||||
children: /* @__PURE__ */ jsx("div", { className: "relative z-50", children: /* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: classNames(
|
||||
"absolute mt-2 rounded-md shadow-lg",
|
||||
widthClass,
|
||||
alignmentClasses
|
||||
),
|
||||
onClick: () => setOpen(false),
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: classNames(
|
||||
"rounded-md ring-1 ring-black ring-opacity-5",
|
||||
contentClasses
|
||||
),
|
||||
children
|
||||
}
|
||||
)
|
||||
}
|
||||
) })
|
||||
}
|
||||
)
|
||||
] });
|
||||
}
|
||||
function DropdownLink({
|
||||
as,
|
||||
href,
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx("div", { children: (() => {
|
||||
switch (as) {
|
||||
case "button":
|
||||
return /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
type: "submit",
|
||||
className: "block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-hidden focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out",
|
||||
children
|
||||
}
|
||||
);
|
||||
case "a":
|
||||
return /* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href,
|
||||
className: "block px-4 py-2 text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-hidden focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out",
|
||||
children
|
||||
}
|
||||
);
|
||||
default:
|
||||
return /* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: href || "",
|
||||
className: "block px-4 py-2 text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-hidden focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out",
|
||||
children
|
||||
}
|
||||
);
|
||||
}
|
||||
})() });
|
||||
}
|
||||
function NavLink({
|
||||
active,
|
||||
href,
|
||||
children
|
||||
}) {
|
||||
const classes = active ? "inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 dark:border-indigo-600 text-sm font-medium leading-5 text-gray-900 dark:text-gray-100 focus:outline-hidden focus:border-indigo-700 transition duration-150 ease-in-out" : "inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-hidden focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out";
|
||||
return /* @__PURE__ */ jsx(Link, { href, className: classes, children });
|
||||
}
|
||||
function ResponsiveNavLink({
|
||||
active,
|
||||
href,
|
||||
children,
|
||||
...props
|
||||
}) {
|
||||
const classes = active ? "block w-full pl-3 pr-4 py-2 border-l-4 border-indigo-400 dark:border-indigo-600 text-left text-base font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/50 focus:outline-hidden focus:text-indigo-800 dark:focus:text-indigo-200 focus:bg-indigo-100 dark:focus:bg-indigo-900 focus:border-indigo-700 dark:focus:border-indigo-300 transition duration-150 ease-in-out" : "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-left text-base font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-hidden focus:text-gray-800 dark:focus:text-gray-200 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-600 transition duration-150 ease-in-out";
|
||||
return /* @__PURE__ */ jsx("div", { children: "as" in props && props.as === "button" ? /* @__PURE__ */ jsx("button", { className: classNames("w-full text-left", classes), children }) : /* @__PURE__ */ jsx(Link, { href: href || "", className: classes, children }) });
|
||||
}
|
||||
function AppLayout({
|
||||
title,
|
||||
renderHeader,
|
||||
children
|
||||
}) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
||||
const page = useTypedPage();
|
||||
const route = useRoute();
|
||||
const [showingNavigationDropdown, setShowingNavigationDropdown] = useState(false);
|
||||
function switchToTeam(e, team) {
|
||||
e.preventDefault();
|
||||
router.put(
|
||||
route("current-team.update"),
|
||||
{
|
||||
team_id: team.id
|
||||
},
|
||||
{
|
||||
preserveState: false
|
||||
}
|
||||
);
|
||||
}
|
||||
function logout(e) {
|
||||
e.preventDefault();
|
||||
router.post(route("logout"));
|
||||
}
|
||||
return /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title }),
|
||||
/* @__PURE__ */ jsx(Banner, {}),
|
||||
/* @__PURE__ */ jsxs("div", { className: "min-h-screen bg-gray-100 dark:bg-gray-900", children: [
|
||||
/* @__PURE__ */ jsxs("nav", { className: "bg-white dark:bg-gray-800 border-b border-gray-100 dark:border-gray-700", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "flex justify-between h-16", children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center", children: /* @__PURE__ */ jsx(Link, { href: route("dashboard"), children: /* @__PURE__ */ jsx(ApplicationMark, { className: "block h-9 w-auto" }) }) }),
|
||||
/* @__PURE__ */ jsx("div", { className: "hidden space-x-8 sm:-my-px sm:ml-10 sm:flex", children: /* @__PURE__ */ jsx(
|
||||
NavLink,
|
||||
{
|
||||
href: route("dashboard"),
|
||||
active: route().current("dashboard"),
|
||||
children: "Dashboard"
|
||||
}
|
||||
) })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "hidden sm:flex sm:items-center sm:ml-6", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "ml-3 relative", children: page.props.jetstream.hasTeamFeatures ? /* @__PURE__ */ jsx(
|
||||
Dropdown,
|
||||
{
|
||||
align: "right",
|
||||
width: "60",
|
||||
renderTrigger: () => {
|
||||
var _a2, _b2;
|
||||
return /* @__PURE__ */ jsx("span", { className: "inline-flex rounded-md", children: /* @__PURE__ */ jsxs(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: "inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-hidden focus:bg-gray-50 dark:focus:bg-gray-700 active:bg-gray-50 dark:active:bg-gray-700 transition ease-in-out duration-150",
|
||||
children: [
|
||||
(_b2 = (_a2 = page.props.auth.user) == null ? void 0 : _a2.current_team) == null ? void 0 : _b2.name,
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "ml-2 -mr-0.5 h-4 w-4",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 20 20",
|
||||
fill: "currentColor",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
fillRule: "evenodd",
|
||||
d: "M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z",
|
||||
clipRule: "evenodd"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
) });
|
||||
},
|
||||
children: /* @__PURE__ */ jsx("div", { className: "w-60", children: page.props.jetstream.hasTeamFeatures ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "block px-4 py-2 text-xs text-gray-400", children: "Manage Team" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
DropdownLink,
|
||||
{
|
||||
href: route("teams.show", [
|
||||
(_a = page.props.auth.user) == null ? void 0 : _a.current_team
|
||||
]),
|
||||
children: "Team Settings"
|
||||
}
|
||||
),
|
||||
page.props.jetstream.canCreateTeams ? /* @__PURE__ */ jsx(DropdownLink, { href: route("teams.create"), children: "Create New Team" }) : null,
|
||||
/* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-600" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "block px-4 py-2 text-xs text-gray-400", children: "Switch Teams" }),
|
||||
(_c = (_b = page.props.auth.user) == null ? void 0 : _b.all_teams) == null ? void 0 : _c.map((team) => {
|
||||
var _a2;
|
||||
return /* @__PURE__ */ jsx(
|
||||
"form",
|
||||
{
|
||||
onSubmit: (e) => switchToTeam(e, team),
|
||||
children: /* @__PURE__ */ jsx(DropdownLink, { as: "button", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
team.id == ((_a2 = page.props.auth.user) == null ? void 0 : _a2.current_team_id) && /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "mr-2 h-5 w-5 text-green-400",
|
||||
fill: "none",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
stroke: "currentColor",
|
||||
viewBox: "0 0 24 24",
|
||||
children: /* @__PURE__ */ jsx("path", { d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("div", { children: team.name })
|
||||
] }) })
|
||||
},
|
||||
team.id
|
||||
);
|
||||
})
|
||||
] }) : null })
|
||||
}
|
||||
) : null }),
|
||||
/* @__PURE__ */ jsx("div", { className: "ml-3 relative", children: /* @__PURE__ */ jsxs(
|
||||
Dropdown,
|
||||
{
|
||||
align: "right",
|
||||
width: "48",
|
||||
renderTrigger: () => {
|
||||
var _a2, _b2, _c2;
|
||||
return page.props.jetstream.managesProfilePhotos ? /* @__PURE__ */ jsx("button", { className: "flex text-sm border-2 border-transparent rounded-full focus:outline-hidden focus:border-gray-300 transition", children: /* @__PURE__ */ jsx(
|
||||
"img",
|
||||
{
|
||||
className: "h-8 w-8 rounded-full object-cover",
|
||||
src: (_a2 = page.props.auth.user) == null ? void 0 : _a2.profile_photo_url,
|
||||
alt: (_b2 = page.props.auth.user) == null ? void 0 : _b2.name
|
||||
}
|
||||
) }) : /* @__PURE__ */ jsx("span", { className: "inline-flex rounded-md", children: /* @__PURE__ */ jsxs(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: "inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-hidden focus:bg-gray-50 dark:focus:bg-gray-700 active:bg-gray-50 dark:active:bg-gray-700 transition ease-in-out duration-150",
|
||||
children: [
|
||||
(_c2 = page.props.auth.user) == null ? void 0 : _c2.name,
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "ml-2 -mr-0.5 h-4 w-4",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 20 20",
|
||||
fill: "currentColor",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M19.5 8.25l-7.5 7.5-7.5-7.5"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
) });
|
||||
},
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "block px-4 py-2 text-xs text-gray-400", children: "Manage Account" }),
|
||||
/* @__PURE__ */ jsx(DropdownLink, { href: route("profile.show"), children: "Profile" }),
|
||||
page.props.jetstream.hasApiFeatures ? /* @__PURE__ */ jsx(DropdownLink, { href: route("api-tokens.index"), children: "API Tokens" }) : null,
|
||||
/* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-600" }),
|
||||
/* @__PURE__ */ jsx("form", { onSubmit: logout, children: /* @__PURE__ */ jsx(DropdownLink, { as: "button", children: "Log Out" }) })
|
||||
]
|
||||
}
|
||||
) })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "-mr-2 flex items-center sm:hidden", children: /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
onClick: () => setShowingNavigationDropdown(!showingNavigationDropdown),
|
||||
className: "inline-flex items-center justify-center p-2 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-900 focus:outline-hidden focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-500 dark:focus:text-gray-400 transition duration-150 ease-in-out",
|
||||
children: /* @__PURE__ */ jsxs(
|
||||
"svg",
|
||||
{
|
||||
className: "h-6 w-6",
|
||||
stroke: "currentColor",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
className: classNames({
|
||||
hidden: showingNavigationDropdown,
|
||||
"inline-flex": !showingNavigationDropdown
|
||||
}),
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
d: "M4 6h16M4 12h16M4 18h16"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
className: classNames({
|
||||
hidden: !showingNavigationDropdown,
|
||||
"inline-flex": showingNavigationDropdown
|
||||
}),
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
d: "M6 18L18 6M6 6l12 12"
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
) })
|
||||
] }) }),
|
||||
/* @__PURE__ */ jsxs(
|
||||
"div",
|
||||
{
|
||||
className: classNames("sm:hidden", {
|
||||
block: showingNavigationDropdown,
|
||||
hidden: !showingNavigationDropdown
|
||||
}),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "pt-2 pb-3 space-y-1", children: /* @__PURE__ */ jsx(
|
||||
ResponsiveNavLink,
|
||||
{
|
||||
href: route("dashboard"),
|
||||
active: route().current("dashboard"),
|
||||
children: "Dashboard"
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "pt-4 pb-1 border-t border-gray-200 dark:border-gray-600", children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center px-4", children: [
|
||||
page.props.jetstream.managesProfilePhotos ? /* @__PURE__ */ jsx("div", { className: "shrink-0 mr-3", children: /* @__PURE__ */ jsx(
|
||||
"img",
|
||||
{
|
||||
className: "h-10 w-10 rounded-full object-cover",
|
||||
src: (_d = page.props.auth.user) == null ? void 0 : _d.profile_photo_url,
|
||||
alt: (_e = page.props.auth.user) == null ? void 0 : _e.name
|
||||
}
|
||||
) }) : null,
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "font-medium text-base text-gray-800 dark:text-gray-200", children: (_f = page.props.auth.user) == null ? void 0 : _f.name }),
|
||||
/* @__PURE__ */ jsx("div", { className: "font-medium text-sm text-gray-500", children: (_g = page.props.auth.user) == null ? void 0 : _g.email })
|
||||
] })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-1", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
ResponsiveNavLink,
|
||||
{
|
||||
href: route("profile.show"),
|
||||
active: route().current("profile.show"),
|
||||
children: "Profile"
|
||||
}
|
||||
),
|
||||
page.props.jetstream.hasApiFeatures ? /* @__PURE__ */ jsx(
|
||||
ResponsiveNavLink,
|
||||
{
|
||||
href: route("api-tokens.index"),
|
||||
active: route().current("api-tokens.index"),
|
||||
children: "API Tokens"
|
||||
}
|
||||
) : null,
|
||||
/* @__PURE__ */ jsx("form", { method: "POST", onSubmit: logout, children: /* @__PURE__ */ jsx(ResponsiveNavLink, { as: "button", children: "Log Out" }) }),
|
||||
page.props.jetstream.hasTeamFeatures ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-600" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "block px-4 py-2 text-xs text-gray-400", children: "Manage Team" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
ResponsiveNavLink,
|
||||
{
|
||||
href: route("teams.show", [
|
||||
(_h = page.props.auth.user) == null ? void 0 : _h.current_team
|
||||
]),
|
||||
active: route().current("teams.show"),
|
||||
children: "Team Settings"
|
||||
}
|
||||
),
|
||||
page.props.jetstream.canCreateTeams ? /* @__PURE__ */ jsx(
|
||||
ResponsiveNavLink,
|
||||
{
|
||||
href: route("teams.create"),
|
||||
active: route().current("teams.create"),
|
||||
children: "Create New Team"
|
||||
}
|
||||
) : null,
|
||||
/* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-600" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "block px-4 py-2 text-xs text-gray-400", children: "Switch Teams" }),
|
||||
(_j = (_i = page.props.auth.user) == null ? void 0 : _i.all_teams) == null ? void 0 : _j.map((team) => {
|
||||
var _a2;
|
||||
return /* @__PURE__ */ jsx("form", { onSubmit: (e) => switchToTeam(e, team), children: /* @__PURE__ */ jsx(ResponsiveNavLink, { as: "button", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
team.id == ((_a2 = page.props.auth.user) == null ? void 0 : _a2.current_team_id) && /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "mr-2 h-5 w-5 text-green-400",
|
||||
fill: "none",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
stroke: "currentColor",
|
||||
viewBox: "0 0 24 24",
|
||||
children: /* @__PURE__ */ jsx("path", { d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("div", { children: team.name })
|
||||
] }) }) }, team.id);
|
||||
})
|
||||
] }) : null
|
||||
] })
|
||||
] })
|
||||
]
|
||||
}
|
||||
)
|
||||
] }),
|
||||
renderHeader ? /* @__PURE__ */ jsx("header", { className: "bg-white dark:bg-gray-800 shadow-sm", children: /* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8", children: renderHeader() }) }) : null,
|
||||
/* @__PURE__ */ jsx("main", { children })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
AppLayout as A
|
||||
};
|
13
bootstrap/ssr/assets/AuthenticationCard--MCzdtHR.js
Normal file
13
bootstrap/ssr/assets/AuthenticationCard--MCzdtHR.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { A as AuthenticationCardLogo } from "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function AuthenticationCard({
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsxs("div", { className: "min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100 dark:bg-gray-900", children: [
|
||||
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(AuthenticationCardLogo, {}) }),
|
||||
/* @__PURE__ */ jsx("div", { className: "w-full sm:max-w-md mt-6 px-6 py-4 bg-white dark:bg-gray-800 shadow-md overflow-hidden sm:rounded-lg", children })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
AuthenticationCard as A
|
||||
};
|
32
bootstrap/ssr/assets/AuthenticationCardLogo-CZgVhhfE.js
Normal file
32
bootstrap/ssr/assets/AuthenticationCardLogo-CZgVhhfE.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { jsx, jsxs } from "react/jsx-runtime";
|
||||
import { Link } from "@inertiajs/react";
|
||||
function AuthenticationCardLogo() {
|
||||
return /* @__PURE__ */ jsx(Link, { href: "/", children: /* @__PURE__ */ jsxs(
|
||||
"svg",
|
||||
{
|
||||
className: "w-16 h-16",
|
||||
viewBox: "0 0 48 48",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M11.395 44.428C4.557 40.198 0 32.632 0 24 0 10.745 10.745 0 24 0a23.891 23.891 0 0113.997 4.502c-.2 17.907-11.097 33.245-26.602 39.926z",
|
||||
fill: "#6875F5"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M14.134 45.885A23.914 23.914 0 0024 48c13.255 0 24-10.745 24-24 0-3.516-.756-6.856-2.115-9.866-4.659 15.143-16.608 27.092-31.75 31.751z",
|
||||
fill: "#6875F5"
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
) });
|
||||
}
|
||||
export {
|
||||
AuthenticationCardLogo as A
|
||||
};
|
18
bootstrap/ssr/assets/Checkbox-XR8K_oHK.js
Normal file
18
bootstrap/ssr/assets/Checkbox-XR8K_oHK.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import classNames from "classnames";
|
||||
function Checkbox(props) {
|
||||
return /* @__PURE__ */ jsx(
|
||||
"input",
|
||||
{
|
||||
type: "checkbox",
|
||||
...props,
|
||||
className: classNames(
|
||||
"rounded-sm dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-xs focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800",
|
||||
props.className
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
Checkbox as C
|
||||
};
|
59
bootstrap/ssr/assets/ConfirmPassword-ju6YtACP.js
Normal file
59
bootstrap/ssr/assets/ConfirmPassword-ju6YtACP.js
Normal file
@ -0,0 +1,59 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm, Head } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as AuthenticationCard } from "./AuthenticationCard--MCzdtHR.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function ConfirmPassword() {
|
||||
const route = useRoute();
|
||||
const form = useForm({
|
||||
password: ""
|
||||
});
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
form.post(route("password.confirm"), {
|
||||
onFinish: () => form.reset()
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(AuthenticationCard, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Secure Area" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mb-4 text-sm text-gray-600 dark:text-gray-400", children: "This is a secure area of the application. Please confirm your password before continuing." }),
|
||||
/* @__PURE__ */ jsxs("form", { onSubmit, children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password", children: "Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password,
|
||||
onChange: (e) => form.setData("password", e.currentTarget.value),
|
||||
required: true,
|
||||
autoComplete: "current-password",
|
||||
autoFocus: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.password })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "flex justify-end mt-4", children: /* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames("ml-4", { "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Confirm"
|
||||
}
|
||||
) })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
ConfirmPassword as default
|
||||
};
|
45
bootstrap/ssr/assets/ConfirmationModal-BYr2Juy2.js
Normal file
45
bootstrap/ssr/assets/ConfirmationModal-BYr2Juy2.js
Normal file
@ -0,0 +1,45 @@
|
||||
import { jsx, jsxs } from "react/jsx-runtime";
|
||||
import { M as Modal } from "./Modal-D5yHmTM4.js";
|
||||
ConfirmationModal.Content = function ConfirmationModalContent({
|
||||
title,
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx("div", { className: "bg-white dark:bg-gray-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4", children: /* @__PURE__ */ jsxs("div", { className: "sm:flex sm:items-start", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "mx-auto shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10", children: /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "h-6 w-6 text-red-600 dark:text-red-400",
|
||||
stroke: "currentColor",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
}
|
||||
)
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left", children: [
|
||||
/* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: title }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-4 text-sm text-gray-600 dark:text-gray-400", children })
|
||||
] })
|
||||
] }) });
|
||||
};
|
||||
ConfirmationModal.Footer = function ConfirmationModalFooter({
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx("div", { className: "px-6 py-4 bg-gray-100 dark:bg-gray-800 text-right", children });
|
||||
};
|
||||
function ConfirmationModal({
|
||||
children,
|
||||
...props
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx(Modal, { ...props, children });
|
||||
}
|
||||
export {
|
||||
ConfirmationModal as C
|
||||
};
|
32
bootstrap/ssr/assets/Create-Bq48ODsT.js
Normal file
32
bootstrap/ssr/assets/Create-Bq48ODsT.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import CreateTeamForm from "./CreateTeamForm-CmUI_Zfp.js";
|
||||
import { A as AppLayout } from "./AppLayout-DitNPgwT.js";
|
||||
import "@inertiajs/react";
|
||||
import "../app.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "./useTypedPage-Do3SqtsL.js";
|
||||
import "./ActionMessage-s_mcCJ3s.js";
|
||||
import "@headlessui/react";
|
||||
import "./FormSection-DI6t3wFC.js";
|
||||
import "classnames";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "./TextInput-CMJy2hIv.js";
|
||||
import "./InputLabel-DhqxoV6M.js";
|
||||
import "./PrimaryButton-C2B8UWiv.js";
|
||||
import "@inertiajs/core";
|
||||
function Create() {
|
||||
return /* @__PURE__ */ jsx(
|
||||
AppLayout,
|
||||
{
|
||||
title: "Create Team",
|
||||
renderHeader: () => /* @__PURE__ */ jsx("h2", { className: "font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight", children: "Create Team" }),
|
||||
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto py-10 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsx(CreateTeamForm, {}) }) })
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
Create as default
|
||||
};
|
86
bootstrap/ssr/assets/CreateTeamForm-CmUI_Zfp.js
Normal file
86
bootstrap/ssr/assets/CreateTeamForm-CmUI_Zfp.js
Normal file
@ -0,0 +1,86 @@
|
||||
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import { A as ActionMessage } from "./ActionMessage-s_mcCJ3s.js";
|
||||
import { F as FormSection } from "./FormSection-DI6t3wFC.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import classNames from "classnames";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "@headlessui/react";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
function CreateTeamForm() {
|
||||
var _a, _b, _c, _d;
|
||||
const route = useRoute();
|
||||
const page = useTypedPage();
|
||||
const form = useForm({
|
||||
name: ""
|
||||
});
|
||||
function createTeam() {
|
||||
form.post(route("teams.store"), {
|
||||
errorBag: "createTeam",
|
||||
preserveScroll: true
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
FormSection,
|
||||
{
|
||||
onSubmit: createTeam,
|
||||
title: "Team Details",
|
||||
description: "Create a new team to collaborate with others on projects.",
|
||||
renderActions: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(ActionMessage, { on: form.recentlySuccessful, className: "mr-3", children: "Saved." }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Save"
|
||||
}
|
||||
)
|
||||
] }),
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { value: "Team Owner" }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center mt-2", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"img",
|
||||
{
|
||||
className: "w-12 h-12 rounded-full object-cover",
|
||||
src: (_a = page.props.auth.user) == null ? void 0 : _a.profile_photo_url,
|
||||
alt: (_b = page.props.auth.user) == null ? void 0 : _b.name
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs("div", { className: "ml-4 leading-tight", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "text-gray-900 dark:text-white", children: (_c = page.props.auth.user) == null ? void 0 : _c.name }),
|
||||
/* @__PURE__ */ jsx("div", { className: "text-gray-700 dark:text-gray-300 text-sm", children: (_d = page.props.auth.user) == null ? void 0 : _d.email })
|
||||
] })
|
||||
] })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "name", value: "Team Name" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "name",
|
||||
type: "text",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.name,
|
||||
onChange: (e) => form.setData("name", e.currentTarget.value),
|
||||
autoFocus: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.name, className: "mt-2" })
|
||||
] })
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
CreateTeamForm as default
|
||||
};
|
21
bootstrap/ssr/assets/DangerButton-BAZynYAq.js
Normal file
21
bootstrap/ssr/assets/DangerButton-BAZynYAq.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import classNames from "classnames";
|
||||
function DangerButton({
|
||||
children,
|
||||
...props
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
...props,
|
||||
className: classNames(
|
||||
"inline-flex items-center justify-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-hidden focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150",
|
||||
props.className
|
||||
),
|
||||
children
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
DangerButton as D
|
||||
};
|
217
bootstrap/ssr/assets/Dashboard-CkDsUhZk.js
Normal file
217
bootstrap/ssr/assets/Dashboard-CkDsUhZk.js
Normal file
@ -0,0 +1,217 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { A as AppLayout } from "./AppLayout-DitNPgwT.js";
|
||||
import "@inertiajs/core";
|
||||
import "@inertiajs/react";
|
||||
import "classnames";
|
||||
import "react";
|
||||
import "../app.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "./useTypedPage-Do3SqtsL.js";
|
||||
import "@headlessui/react";
|
||||
function ApplicationLogo({ className }) {
|
||||
return /* @__PURE__ */ jsxs(
|
||||
"svg",
|
||||
{
|
||||
viewBox: "0 0 317 48",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
className,
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M74.09 30.04V13h-4.14v21H82.1v-3.96h-8.01zM95.379 19v1.77c-1.08-1.35-2.7-2.19-4.89-2.19-3.99 0-7.29 3.45-7.29 7.92s3.3 7.92 7.29 7.92c2.19 0 3.81-.84 4.89-2.19V34h3.87V19h-3.87zm-4.17 11.73c-2.37 0-4.14-1.71-4.14-4.23 0-2.52 1.77-4.23 4.14-4.23 2.4 0 4.17 1.71 4.17 4.23 0 2.52-1.77 4.23-4.17 4.23zM106.628 21.58V19h-3.87v15h3.87v-7.17c0-3.15 2.55-4.05 4.56-3.81V18.7c-1.89 0-3.78.84-4.56 2.88zM124.295 19v1.77c-1.08-1.35-2.7-2.19-4.89-2.19-3.99 0-7.29 3.45-7.29 7.92s3.3 7.92 7.29 7.92c2.19 0 3.81-.84 4.89-2.19V34h3.87V19h-3.87zm-4.17 11.73c-2.37 0-4.14-1.71-4.14-4.23 0-2.52 1.77-4.23 4.14-4.23 2.4 0 4.17 1.71 4.17 4.23 0 2.52-1.77 4.23-4.17 4.23zM141.544 19l-3.66 10.5-3.63-10.5h-4.26l5.7 15h4.41l5.7-15h-4.26zM150.354 28.09h11.31c.09-.51.15-1.02.15-1.59 0-4.41-3.15-7.92-7.59-7.92-4.71 0-7.92 3.45-7.92 7.92s3.18 7.92 8.22 7.92c2.88 0 5.13-1.17 6.54-3.21l-3.12-1.8c-.66.87-1.86 1.5-3.36 1.5-2.04 0-3.69-.84-4.23-2.82zm-.06-3c.45-1.92 1.86-3.03 3.93-3.03 1.62 0 3.24.87 3.72 3.03h-7.65zM164.516 34h3.87V12.1h-3.87V34zM185.248 34.36c3.69 0 6.9-2.01 6.9-6.3V13h-2.1v15.06c0 3.03-2.07 4.26-4.8 4.26-2.19 0-3.93-.78-4.62-2.61l-1.77 1.05c1.05 2.43 3.57 3.6 6.39 3.6zM203.124 18.64c-4.65 0-7.83 3.45-7.83 7.86 0 4.53 3.24 7.86 7.98 7.86 3.03 0 5.34-1.41 6.6-3.45l-1.74-1.02c-.81 1.44-2.46 2.55-4.83 2.55-3.18 0-5.55-1.89-5.97-4.95h13.17c.03-.3.06-.63.06-.93 0-4.11-2.85-7.92-7.44-7.92zm0 1.92c2.58 0 4.98 1.71 5.4 5.01h-11.19c.39-2.94 2.64-5.01 5.79-5.01zM221.224 20.92V19h-4.32v-4.2l-1.98.6V19h-3.15v1.92h3.15v9.09c0 3.6 2.25 4.59 6.3 3.99v-1.74c-2.91.12-4.32.33-4.32-2.25v-9.09h4.32zM225.176 22.93c0-1.62 1.59-2.37 3.15-2.37 1.44 0 2.97.57 3.6 2.1l1.65-.96c-.87-1.86-2.79-3.06-5.25-3.06-3 0-5.13 1.89-5.13 4.29 0 5.52 8.76 3.39 8.76 7.11 0 1.77-1.68 2.4-3.45 2.4-2.01 0-3.57-.99-4.11-2.52l-1.68.99c.75 1.92 2.79 3.45 5.79 3.45 3.21 0 5.43-1.77 5.43-4.32 0-5.52-8.76-3.39-8.76-7.11zM244.603 20.92V19h-4.32v-4.2l-1.98.6V19h-3.15v1.92h3.15v9.09c0 3.6 2.25 4.59 6.3 3.99v-1.74c-2.91.12-4.32.33-4.32-2.25v-9.09h4.32zM249.883 21.49V19h-1.98v15h1.98v-8.34c0-3.72 2.34-4.98 4.74-4.98v-1.92c-1.92 0-3.69.63-4.74 2.73zM263.358 18.64c-4.65 0-7.83 3.45-7.83 7.86 0 4.53 3.24 7.86 7.98 7.86 3.03 0 5.34-1.41 6.6-3.45l-1.74-1.02c-.81 1.44-2.46 2.55-4.83 2.55-3.18 0-5.55-1.89-5.97-4.95h13.17c.03-.3.06-.63.06-.93 0-4.11-2.85-7.92-7.44-7.92zm0 1.92c2.58 0 4.98 1.71 5.4 5.01h-11.19c.39-2.94 2.64-5.01 5.79-5.01zM286.848 19v2.94c-1.26-2.01-3.39-3.3-6.06-3.3-4.23 0-7.74 3.42-7.74 7.86s3.51 7.86 7.74 7.86c2.67 0 4.8-1.29 6.06-3.3V34h1.98V19h-1.98zm-5.91 13.44c-3.33 0-5.91-2.61-5.91-5.94 0-3.33 2.58-5.94 5.91-5.94s5.91 2.61 5.91 5.94c0 3.33-2.58 5.94-5.91 5.94zM309.01 18.64c-1.92 0-3.75.87-4.86 2.73-.84-1.74-2.46-2.73-4.56-2.73-1.8 0-3.42.72-4.59 2.55V19h-1.98v15H295v-8.31c0-3.72 2.16-5.13 4.32-5.13 2.13 0 3.51 1.41 3.51 4.08V34h1.98v-8.31c0-3.72 1.86-5.13 4.17-5.13 2.13 0 3.66 1.41 3.66 4.08V34h1.98v-9.36c0-3.75-2.31-6-5.61-6z",
|
||||
fill: "fill-black dark:fill-white"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M11.395 44.428C4.557 40.198 0 32.632 0 24 0 10.745 10.745 0 24 0a23.891 23.891 0 0113.997 4.502c-.2 17.907-11.097 33.245-26.602 39.926z",
|
||||
fill: "#6875F5"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M14.134 45.885A23.914 23.914 0 0024 48c13.255 0 24-10.745 24-24 0-3.516-.756-6.856-2.115-9.866-4.659 15.143-16.608 27.092-31.75 31.751z",
|
||||
fill: "#6875F5"
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
function Welcome() {
|
||||
return /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "p-6 lg:p-8 bg-white dark:bg-gray-800 dark:bg-linear-to-bl dark:from-gray-700/50 dark:via-transparent border-b border-gray-200 dark:border-gray-700", children: [
|
||||
/* @__PURE__ */ jsx(ApplicationLogo, { className: "block h-12 w-auto" }),
|
||||
/* @__PURE__ */ jsx("h1", { className: "mt-8 text-2xl font-medium text-gray-900 dark:text-white", children: "Welcome to your Jetstream application!" }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-6 text-gray-500 dark:text-gray-400 leading-relaxed", children: "Laravel Jetstream provides a beautiful, robust starting point for your next Laravel application. Laravel is designed to help you build your application using a development environment that is simple, powerful, and enjoyable. We believe you should love expressing your creativity through programming, so we have spent time carefully crafting the Laravel ecosystem to be a breath of fresh air. We hope you love it." })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "bg-gray-200 dark:bg-gray-800 bg-opacity-25 grid grid-cols-1 md:grid-cols-2 gap-6 lg:gap-8 p-6 lg:p-8", children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-6 h-6 stroke-gray-400",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25"
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("h2", { className: "ml-3 text-xl font-semibold text-gray-900 dark:text-white", children: /* @__PURE__ */ jsx("a", { href: "https://laravel.com/docs", children: "Documentation" }) })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: "Laravel has wonderful documentation covering every aspect of the framework. Whether you're new to the framework or have previous experience, we recommend reading all of the documentation from beginning to end." }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-sm", children: /* @__PURE__ */ jsxs(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs",
|
||||
className: "inline-flex items-center font-semibold text-indigo-700 dark:text-indigo-300",
|
||||
children: [
|
||||
"Explore the documentation",
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 20 20",
|
||||
className: "ml-1 w-5 h-5 fill-indigo-500 dark:fill-indigo-200",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
fillRule: "evenodd",
|
||||
d: "M5 10a.75.75 0 01.75-.75h6.638L10.23 7.29a.75.75 0 111.04-1.08l3.5 3.25a.75.75 0 010 1.08l-3.5 3.25a.75.75 0 11-1.04-1.08l2.158-1.96H5.75A.75.75 0 015 10z",
|
||||
clipRule: "evenodd"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
) })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-6 h-6 stroke-gray-400",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
d: "M15.75 10.5l4.72-4.72a.75.75 0 011.28.53v11.38a.75.75 0 01-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25h-9A2.25 2.25 0 002.25 7.5v9a2.25 2.25 0 002.25 2.25z"
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("h2", { className: "ml-3 text-xl font-semibold text-gray-900 dark:text-white", children: /* @__PURE__ */ jsx("a", { href: "https://laracasts.com", children: "Laracasts" }) })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: "Laracasts offers thousands of video tutorials on Laravel, PHP, and JavaScript development. Check them out, see for yourself, and massively level up your development skills in the process." }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-sm", children: /* @__PURE__ */ jsxs(
|
||||
"a",
|
||||
{
|
||||
href: "https://laracasts.com",
|
||||
className: "inline-flex items-center font-semibold text-indigo-700 dark:text-indigo-300",
|
||||
children: [
|
||||
"Start watching Laracasts",
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 20 20",
|
||||
className: "ml-1 w-5 h-5 fill-indigo-500 dark:fill-indigo-200",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
fillRule: "evenodd",
|
||||
d: "M5 10a.75.75 0 01.75-.75h6.638L10.23 7.29a.75.75 0 111.04-1.08l3.5 3.25a.75.75 0 010 1.08l-3.5 3.25a.75.75 0 11-1.04-1.08l2.158-1.96H5.75A.75.75 0 015 10z",
|
||||
clipRule: "evenodd"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
) })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-6 h-6 stroke-gray-400",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("h2", { className: "ml-3 text-xl font-semibold text-gray-900 dark:text-white", children: /* @__PURE__ */ jsx("a", { href: "https://tailwindcss.com/", children: "Tailwind" }) })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: "Laravel Jetstream is built with Tailwind, an amazing utility first CSS framework that doesn't get in your way. You'll be amazed how easily you can build and maintain fresh, modern designs with this wonderful framework at your fingertips." })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-6 h-6 stroke-gray-400",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("h2", { className: "ml-3 text-xl font-semibold text-gray-900 dark:text-white", children: "Authentication" })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: "Authentication and registration views are included with Laravel Jetstream, as well as support for user email verification and resetting forgotten passwords. So, you're free to get started with what matters most: building your application." })
|
||||
] })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
function Dashboard() {
|
||||
return /* @__PURE__ */ jsx(
|
||||
AppLayout,
|
||||
{
|
||||
title: "Dashboard",
|
||||
renderHeader: () => /* @__PURE__ */ jsx("h2", { className: "font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight", children: "Dashboard" }),
|
||||
children: /* @__PURE__ */ jsx("div", { className: "py-12", children: /* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto sm:px-6 lg:px-8", children: /* @__PURE__ */ jsx("div", { className: "bg-white dark:bg-gray-800 overflow-hidden shadow-xl sm:rounded-lg", children: /* @__PURE__ */ jsx(Welcome, {}) }) }) })
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
Dashboard as default
|
||||
};
|
64
bootstrap/ssr/assets/DeleteTeamForm-CDG-Mx5L.js
Normal file
64
bootstrap/ssr/assets/DeleteTeamForm-CDG-Mx5L.js
Normal file
@ -0,0 +1,64 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as ActionSection } from "./Modal-D5yHmTM4.js";
|
||||
import { C as ConfirmationModal } from "./ConfirmationModal-BYr2Juy2.js";
|
||||
import { D as DangerButton } from "./DangerButton-BAZynYAq.js";
|
||||
import { S as SecondaryButton } from "./SecondaryButton-G68tKuYQ.js";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState } from "react";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "@headlessui/react";
|
||||
import "react-dom";
|
||||
function DeleteTeamForm({ team }) {
|
||||
const route = useRoute();
|
||||
const [confirmingTeamDeletion, setConfirmingTeamDeletion] = useState(false);
|
||||
const form = useForm({});
|
||||
function confirmTeamDeletion() {
|
||||
setConfirmingTeamDeletion(true);
|
||||
}
|
||||
function deleteTeam() {
|
||||
form.delete(route("teams.destroy", [team]), {
|
||||
errorBag: "deleteTeam"
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
ActionSection,
|
||||
{
|
||||
title: "Delete Team",
|
||||
description: "Permanently delete this team.",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "max-w-xl text-sm text-gray-600 dark:text-gray-400", children: "Once a team is deleted, all of its resources and data will be permanently deleted. Before deleting this team, please download any data or information regarding this team that you wish to retain." }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-5", children: /* @__PURE__ */ jsx(DangerButton, { onClick: confirmTeamDeletion, children: "Delete Team" }) }),
|
||||
/* @__PURE__ */ jsxs(
|
||||
ConfirmationModal,
|
||||
{
|
||||
isOpen: confirmingTeamDeletion,
|
||||
onClose: () => setConfirmingTeamDeletion(false),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(ConfirmationModal.Content, { title: "Delete Team", children: "Are you sure you want to delete this team? Once a team is deleted, all of its resources and data will be permanently deleted." }),
|
||||
/* @__PURE__ */ jsxs(ConfirmationModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: () => setConfirmingTeamDeletion(false), children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
DangerButton,
|
||||
{
|
||||
onClick: deleteTeam,
|
||||
className: classNames("ml-2", { "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Delete Team"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
DeleteTeamForm as default
|
||||
};
|
90
bootstrap/ssr/assets/DeleteUserForm-Ptw0GKXr.js
Normal file
90
bootstrap/ssr/assets/DeleteUserForm-Ptw0GKXr.js
Normal file
@ -0,0 +1,90 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState, useRef } from "react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as ActionSection } from "./Modal-D5yHmTM4.js";
|
||||
import { D as DangerButton } from "./DangerButton-BAZynYAq.js";
|
||||
import { D as DialogModal } from "./DialogModal-D0pyMzH2.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { S as SecondaryButton } from "./SecondaryButton-G68tKuYQ.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "@headlessui/react";
|
||||
import "react-dom";
|
||||
function DeleteUserForm() {
|
||||
const route = useRoute();
|
||||
const [confirmingUserDeletion, setConfirmingUserDeletion] = useState(false);
|
||||
const form = useForm({
|
||||
password: ""
|
||||
});
|
||||
const passwordRef = useRef(null);
|
||||
function confirmUserDeletion() {
|
||||
setConfirmingUserDeletion(true);
|
||||
setTimeout(() => {
|
||||
var _a;
|
||||
return (_a = passwordRef.current) == null ? void 0 : _a.focus();
|
||||
}, 250);
|
||||
}
|
||||
function deleteUser() {
|
||||
form.delete(route("current-user.destroy"), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => closeModal(),
|
||||
onError: () => {
|
||||
var _a;
|
||||
return (_a = passwordRef.current) == null ? void 0 : _a.focus();
|
||||
},
|
||||
onFinish: () => form.reset()
|
||||
});
|
||||
}
|
||||
function closeModal() {
|
||||
setConfirmingUserDeletion(false);
|
||||
form.reset();
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
ActionSection,
|
||||
{
|
||||
title: "Delete Account",
|
||||
description: "Permanently delete your account.",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "max-w-xl text-sm text-gray-600 dark:text-gray-400", children: "Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain." }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-5", children: /* @__PURE__ */ jsx(DangerButton, { onClick: confirmUserDeletion, children: "Delete Account" }) }),
|
||||
/* @__PURE__ */ jsxs(DialogModal, { isOpen: confirmingUserDeletion, onClose: closeModal, children: [
|
||||
/* @__PURE__ */ jsxs(DialogModal.Content, { title: "Delete Account", children: [
|
||||
"Are you sure you want to delete your account? Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.",
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
type: "password",
|
||||
className: "mt-1 block w-3/4",
|
||||
placeholder: "Password",
|
||||
value: form.data.password,
|
||||
onChange: (e) => form.setData("password", e.currentTarget.value)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.password, className: "mt-2" })
|
||||
] })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs(DialogModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: closeModal, children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
DangerButton,
|
||||
{
|
||||
onClick: deleteUser,
|
||||
className: classNames("ml-2", { "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Delete Account"
|
||||
}
|
||||
)
|
||||
] })
|
||||
] })
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
DeleteUserForm as default
|
||||
};
|
25
bootstrap/ssr/assets/DialogModal-D0pyMzH2.js
Normal file
25
bootstrap/ssr/assets/DialogModal-D0pyMzH2.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { jsx, jsxs } from "react/jsx-runtime";
|
||||
import { M as Modal } from "./Modal-D5yHmTM4.js";
|
||||
DialogModal.Content = function DialogModalContent({
|
||||
title,
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: title }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-4 text-sm text-gray-600 dark:text-gray-400", children })
|
||||
] });
|
||||
};
|
||||
DialogModal.Footer = function DialogModalFooter({
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx("div", { className: "px-6 py-4 bg-gray-100 dark:bg-gray-800 text-right", children });
|
||||
};
|
||||
function DialogModal({
|
||||
children,
|
||||
...modalProps
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx(Modal, { ...modalProps, children });
|
||||
}
|
||||
export {
|
||||
DialogModal as D
|
||||
};
|
57
bootstrap/ssr/assets/ForgotPassword-BhYnh0qc.js
Normal file
57
bootstrap/ssr/assets/ForgotPassword-BhYnh0qc.js
Normal file
@ -0,0 +1,57 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm, Head } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as AuthenticationCard } from "./AuthenticationCard--MCzdtHR.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function ForgotPassword({ status }) {
|
||||
const route = useRoute();
|
||||
const form = useForm({
|
||||
email: ""
|
||||
});
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
form.post(route("password.email"));
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(AuthenticationCard, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Forgot Password" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mb-4 text-sm text-gray-600 dark:text-gray-400", children: "Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one." }),
|
||||
status && /* @__PURE__ */ jsx("div", { className: "mb-4 font-medium text-sm text-green-600 dark:text-green-400", children: status }),
|
||||
/* @__PURE__ */ jsxs("form", { onSubmit, children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "email", children: "Email" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "email",
|
||||
type: "email",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.email,
|
||||
onChange: (e) => form.setData("email", e.currentTarget.value),
|
||||
required: true,
|
||||
autoFocus: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.email })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end mt-4", children: /* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Email Password Reset Link"
|
||||
}
|
||||
) })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
ForgotPassword as default
|
||||
};
|
40
bootstrap/ssr/assets/FormSection-DI6t3wFC.js
Normal file
40
bootstrap/ssr/assets/FormSection-DI6t3wFC.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import classNames from "classnames";
|
||||
import { S as SectionTitle } from "./SectionTitle-DnuUNpyS.js";
|
||||
function FormSection({
|
||||
onSubmit,
|
||||
renderActions,
|
||||
title,
|
||||
description,
|
||||
children
|
||||
}) {
|
||||
const hasActions = !!renderActions;
|
||||
return /* @__PURE__ */ jsxs("div", { className: "md:grid md:grid-cols-3 md:gap-6", children: [
|
||||
/* @__PURE__ */ jsx(SectionTitle, { title, description }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-5 md:mt-0 md:col-span-2", children: /* @__PURE__ */ jsxs(
|
||||
"form",
|
||||
{
|
||||
onSubmit: (e) => {
|
||||
e.preventDefault();
|
||||
onSubmit();
|
||||
},
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: classNames(
|
||||
"px-4 py-5 bg-white dark:bg-gray-800 sm:p-6 shadow-sm",
|
||||
hasActions ? "sm:rounded-tl-md sm:rounded-tr-md" : "sm:rounded-md"
|
||||
),
|
||||
children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-6 gap-6", children })
|
||||
}
|
||||
),
|
||||
hasActions && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end px-4 py-3 bg-gray-50 dark:bg-gray-800 text-right sm:px-6 shadow-sm sm:rounded-bl-md sm:rounded-br-md", children: renderActions == null ? void 0 : renderActions() })
|
||||
]
|
||||
}
|
||||
) })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
FormSection as F
|
||||
};
|
51
bootstrap/ssr/assets/Index-CwIeEkIw.js
Normal file
51
bootstrap/ssr/assets/Index-CwIeEkIw.js
Normal file
@ -0,0 +1,51 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import APITokenManager from "./APITokenManager-iZxUx3eK.js";
|
||||
import { A as AppLayout } from "./AppLayout-DitNPgwT.js";
|
||||
import "@inertiajs/react";
|
||||
import "classnames";
|
||||
import "react";
|
||||
import "../app.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "./ActionMessage-s_mcCJ3s.js";
|
||||
import "@headlessui/react";
|
||||
import "./Modal-D5yHmTM4.js";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "react-dom";
|
||||
import "./Checkbox-XR8K_oHK.js";
|
||||
import "./ConfirmationModal-BYr2Juy2.js";
|
||||
import "./DangerButton-BAZynYAq.js";
|
||||
import "./DialogModal-D0pyMzH2.js";
|
||||
import "./FormSection-DI6t3wFC.js";
|
||||
import "./TextInput-CMJy2hIv.js";
|
||||
import "./InputLabel-DhqxoV6M.js";
|
||||
import "./PrimaryButton-C2B8UWiv.js";
|
||||
import "./SecondaryButton-G68tKuYQ.js";
|
||||
import "./SectionBorder-Dh4nHf2e.js";
|
||||
import "./useTypedPage-Do3SqtsL.js";
|
||||
import "@inertiajs/core";
|
||||
function ApiTokenIndex({
|
||||
tokens,
|
||||
availablePermissions,
|
||||
defaultPermissions
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx(
|
||||
AppLayout,
|
||||
{
|
||||
title: "API Tokens",
|
||||
renderHeader: () => /* @__PURE__ */ jsx("h2", { className: "font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight", children: "API Tokens" }),
|
||||
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto py-10 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsx(
|
||||
APITokenManager,
|
||||
{
|
||||
tokens,
|
||||
availablePermissions,
|
||||
defaultPermissions
|
||||
}
|
||||
) }) })
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
ApiTokenIndex as default
|
||||
};
|
18
bootstrap/ssr/assets/InputLabel-DhqxoV6M.js
Normal file
18
bootstrap/ssr/assets/InputLabel-DhqxoV6M.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
function InputLabel({
|
||||
value,
|
||||
htmlFor,
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx(
|
||||
"label",
|
||||
{
|
||||
className: "block font-medium text-sm text-gray-700 dark:text-gray-300",
|
||||
htmlFor,
|
||||
children: value || children
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
InputLabel as I
|
||||
};
|
108
bootstrap/ssr/assets/Login-P_qEmbLO.js
Normal file
108
bootstrap/ssr/assets/Login-P_qEmbLO.js
Normal file
@ -0,0 +1,108 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm, Head, Link } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as AuthenticationCard } from "./AuthenticationCard--MCzdtHR.js";
|
||||
import { C as Checkbox } from "./Checkbox-XR8K_oHK.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function Login({ canResetPassword, status }) {
|
||||
const route = useRoute();
|
||||
const form = useForm({
|
||||
email: "",
|
||||
password: "",
|
||||
remember: ""
|
||||
});
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
form.post(route("login"), {
|
||||
onFinish: () => form.reset("password")
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(AuthenticationCard, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Login" }),
|
||||
status && /* @__PURE__ */ jsx("div", { className: "mb-4 font-medium text-sm text-green-600 dark:text-green-400", children: status }),
|
||||
/* @__PURE__ */ jsxs("form", { onSubmit, children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "email", children: "Email" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "email",
|
||||
type: "email",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.email,
|
||||
onChange: (e) => form.setData("email", e.currentTarget.value),
|
||||
required: true,
|
||||
autoFocus: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.email })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password", children: "Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password,
|
||||
onChange: (e) => form.setData("password", e.currentTarget.value),
|
||||
required: true,
|
||||
autoComplete: "current-password"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.password })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsxs("label", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
Checkbox,
|
||||
{
|
||||
name: "remember",
|
||||
checked: form.data.remember === "on",
|
||||
onChange: (e) => form.setData("remember", e.currentTarget.checked ? "on" : "")
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("span", { className: "ml-2 text-sm text-gray-600 dark:text-gray-400", children: "Remember me" })
|
||||
] }) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2 md:flex-row md:items-center md:justify-between md:space-y-0 mt-4", children: [
|
||||
canResetPassword && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("password.request"),
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
|
||||
children: "Forgot your password?"
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("register"),
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
|
||||
children: "Need an account?"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames("ml-4", { "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Log in"
|
||||
}
|
||||
)
|
||||
] })
|
||||
] })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
Login as default
|
||||
};
|
142
bootstrap/ssr/assets/LogoutOtherBrowserSessionsForm-Bd8DyQdZ.js
Normal file
142
bootstrap/ssr/assets/LogoutOtherBrowserSessionsForm-Bd8DyQdZ.js
Normal file
@ -0,0 +1,142 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState, useRef } from "react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as ActionMessage } from "./ActionMessage-s_mcCJ3s.js";
|
||||
import { A as ActionSection } from "./Modal-D5yHmTM4.js";
|
||||
import { D as DialogModal } from "./DialogModal-D0pyMzH2.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { S as SecondaryButton } from "./SecondaryButton-G68tKuYQ.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "@headlessui/react";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "react-dom";
|
||||
function LogoutOtherBrowserSessions({ sessions }) {
|
||||
const [confirmingLogout, setConfirmingLogout] = useState(false);
|
||||
const route = useRoute();
|
||||
const passwordRef = useRef(null);
|
||||
const form = useForm({
|
||||
password: ""
|
||||
});
|
||||
function confirmLogout() {
|
||||
setConfirmingLogout(true);
|
||||
setTimeout(() => {
|
||||
var _a;
|
||||
return (_a = passwordRef.current) == null ? void 0 : _a.focus();
|
||||
}, 250);
|
||||
}
|
||||
function logoutOtherBrowserSessions() {
|
||||
form.delete(route("other-browser-sessions.destroy"), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => closeModal(),
|
||||
onError: () => {
|
||||
var _a;
|
||||
return (_a = passwordRef.current) == null ? void 0 : _a.focus();
|
||||
},
|
||||
onFinish: () => form.reset()
|
||||
});
|
||||
}
|
||||
function closeModal() {
|
||||
setConfirmingLogout(false);
|
||||
form.reset();
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
ActionSection,
|
||||
{
|
||||
title: "Browser Sessions",
|
||||
description: "Manage and log out your active sessions on other browsers and devices.",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "max-w-xl text-sm text-gray-600 dark:text-gray-400", children: "If necessary, you may log out of all of your other browser sessions across all of your devices. Some of your recent sessions are listed below; however, this list may not be exhaustive. If you feel your account has been compromised, you should also update your password." }),
|
||||
sessions.length > 0 ? /* @__PURE__ */ jsx("div", { className: "mt-5 space-y-6", children: sessions.map((session, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx("div", { children: session.agent.is_desktop ? /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
fill: "none",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
viewBox: "0 0 24 24",
|
||||
stroke: "currentColor",
|
||||
className: "w-8 h-8 text-gray-500",
|
||||
children: /* @__PURE__ */ jsx("path", { d: "M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" })
|
||||
}
|
||||
) : /* @__PURE__ */ jsxs(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "2",
|
||||
stroke: "currentColor",
|
||||
fill: "none",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
className: "w-8 h-8 text-gray-500",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("path", { d: "M0 0h24v24H0z", stroke: "none" }),
|
||||
/* @__PURE__ */ jsx("rect", { x: "7", y: "4", width: "10", height: "16", rx: "1" }),
|
||||
/* @__PURE__ */ jsx("path", { d: "M11 5h2M12 17v.01" })
|
||||
]
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "ml-3", children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: [
|
||||
session.agent.platform,
|
||||
" - ",
|
||||
session.agent.browser
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
|
||||
session.ip_address,
|
||||
",",
|
||||
session.is_current_device ? /* @__PURE__ */ jsx("span", { className: "text-green-500 font-semibold", children: "This device" }) : /* @__PURE__ */ jsxs("span", { children: [
|
||||
"Last active ",
|
||||
session.last_active
|
||||
] })
|
||||
] }) })
|
||||
] })
|
||||
] }, i)) }) : null,
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center mt-5", children: [
|
||||
/* @__PURE__ */ jsx(PrimaryButton, { onClick: confirmLogout, children: "Log Out Other Browser Sessions" }),
|
||||
/* @__PURE__ */ jsx(ActionMessage, { on: form.recentlySuccessful, className: "ml-3", children: "Done." })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs(DialogModal, { isOpen: confirmingLogout, onClose: closeModal, children: [
|
||||
/* @__PURE__ */ jsxs(DialogModal.Content, { title: "Log Out Other Browser Sessions", children: [
|
||||
"Please enter your password to confirm you would like to log out of your other browser sessions across all of your devices.",
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
type: "password",
|
||||
className: "mt-1 block w-3/4",
|
||||
placeholder: "Password",
|
||||
ref: passwordRef,
|
||||
value: form.data.password,
|
||||
onChange: (e) => form.setData("password", e.currentTarget.value)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.password, className: "mt-2" })
|
||||
] })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs(DialogModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: closeModal, children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
onClick: logoutOtherBrowserSessions,
|
||||
className: classNames("ml-2", { "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Log Out Other Browser Sessions"
|
||||
}
|
||||
)
|
||||
] })
|
||||
] })
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
LogoutOtherBrowserSessions as default
|
||||
};
|
95
bootstrap/ssr/assets/Modal-D5yHmTM4.js
Normal file
95
bootstrap/ssr/assets/Modal-D5yHmTM4.js
Normal file
@ -0,0 +1,95 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { S as SectionTitle } from "./SectionTitle-DnuUNpyS.js";
|
||||
import { Transition, Dialog, TransitionChild } from "@headlessui/react";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
function ActionSection({
|
||||
title,
|
||||
description,
|
||||
children
|
||||
}) {
|
||||
return /* @__PURE__ */ jsxs("div", { className: "md:grid md:grid-cols-3 md:gap-6", children: [
|
||||
/* @__PURE__ */ jsx(SectionTitle, { title, description }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-5 md:mt-0 md:col-span-2", children: /* @__PURE__ */ jsx("div", { className: "px-4 py-5 sm:p-6 bg-white dark:bg-gray-800 shadow-sm sm:rounded-lg", children }) })
|
||||
] });
|
||||
}
|
||||
function Modal({
|
||||
isOpen,
|
||||
onClose,
|
||||
maxWidth = "2xl",
|
||||
children
|
||||
}) {
|
||||
const maxWidthClass = {
|
||||
sm: "sm:max-w-sm",
|
||||
md: "sm:max-w-md",
|
||||
lg: "sm:max-w-lg",
|
||||
xl: "sm:max-w-xl",
|
||||
"2xl": "sm:max-w-2xl"
|
||||
}[maxWidth];
|
||||
if (typeof window === "undefined") {
|
||||
return null;
|
||||
}
|
||||
return ReactDOM.createPortal(
|
||||
/* @__PURE__ */ jsx(Transition, { show: isOpen, as: React.Fragment, children: /* @__PURE__ */ jsx(
|
||||
Dialog,
|
||||
{
|
||||
as: "div",
|
||||
static: true,
|
||||
className: "fixed z-10 inset-0 overflow-y-auto",
|
||||
open: isOpen,
|
||||
onClose,
|
||||
children: /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
TransitionChild,
|
||||
{
|
||||
as: React.Fragment,
|
||||
enter: "ease-out duration-300",
|
||||
enterFrom: "opacity-0",
|
||||
enterTo: "opacity-100",
|
||||
leave: "ease-in duration-200",
|
||||
leaveFrom: "opacity-100",
|
||||
leaveTo: "opacity-0",
|
||||
children: /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-gray-500 dark:bg-gray-900 bg-opacity-75 transition-opacity" })
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
"span",
|
||||
{
|
||||
className: "hidden sm:inline-block sm:align-middle sm:h-screen",
|
||||
"aria-hidden": "true",
|
||||
children: ""
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
TransitionChild,
|
||||
{
|
||||
as: React.Fragment,
|
||||
enter: "ease-out duration-300",
|
||||
enterFrom: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
|
||||
enterTo: "opacity-100 translate-y-0 sm:scale-100",
|
||||
leave: "ease-in duration-200",
|
||||
leaveFrom: "opacity-100 translate-y-0 sm:scale-100",
|
||||
leaveTo: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: classNames(
|
||||
"inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:w-full",
|
||||
maxWidthClass
|
||||
),
|
||||
children
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
] })
|
||||
}
|
||||
) }),
|
||||
document.body
|
||||
);
|
||||
}
|
||||
export {
|
||||
ActionSection as A,
|
||||
Modal as M
|
||||
};
|
21
bootstrap/ssr/assets/PrimaryButton-C2B8UWiv.js
Normal file
21
bootstrap/ssr/assets/PrimaryButton-C2B8UWiv.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import classNames from "classnames";
|
||||
function PrimaryButton({
|
||||
children,
|
||||
...props
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
...props,
|
||||
className: classNames(
|
||||
"inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150",
|
||||
props.className
|
||||
),
|
||||
children
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
PrimaryButton as P
|
||||
};
|
21
bootstrap/ssr/assets/PrivacyPolicy-DYEevN3b.js
Normal file
21
bootstrap/ssr/assets/PrivacyPolicy-DYEevN3b.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { A as AuthenticationCardLogo } from "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
import { Head } from "@inertiajs/react";
|
||||
function PrivacyPolicy({ policy }) {
|
||||
return /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Privacy Policy" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "font-sans text-gray-900 dark:text-gray-100 antialiased", children: /* @__PURE__ */ jsx("div", { className: "pt-4 bg-gray-100 dark:bg-gray-900", children: /* @__PURE__ */ jsxs("div", { className: "min-h-screen flex flex-col items-center pt-6 sm:pt-0", children: [
|
||||
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(AuthenticationCardLogo, {}) }),
|
||||
/* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: "w-full sm:max-w-2xl mt-6 p-6 bg-white dark:bg-gray-800 shadow-md overflow-hidden sm:rounded-lg prose dark:prose-invert",
|
||||
dangerouslySetInnerHTML: { __html: policy }
|
||||
}
|
||||
)
|
||||
] }) }) })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
PrivacyPolicy as default
|
||||
};
|
165
bootstrap/ssr/assets/Register-anJ95HWS.js
Normal file
165
bootstrap/ssr/assets/Register-anJ95HWS.js
Normal file
@ -0,0 +1,165 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm, Head, Link } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import { A as AuthenticationCard } from "./AuthenticationCard--MCzdtHR.js";
|
||||
import { C as Checkbox } from "./Checkbox-XR8K_oHK.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function Register() {
|
||||
const page = useTypedPage();
|
||||
const route = useRoute();
|
||||
const form = useForm({
|
||||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
password_confirmation: "",
|
||||
terms: false
|
||||
});
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
form.post(route("register"), {
|
||||
onFinish: () => form.reset("password", "password_confirmation")
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(AuthenticationCard, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Register" }),
|
||||
/* @__PURE__ */ jsxs("form", { onSubmit, children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "name", children: "Name" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "name",
|
||||
type: "text",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.name,
|
||||
onChange: (e) => form.setData("name", e.currentTarget.value),
|
||||
required: true,
|
||||
autoFocus: true,
|
||||
autoComplete: "name"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.name })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "email", children: "Email" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "email",
|
||||
type: "email",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.email,
|
||||
onChange: (e) => form.setData("email", e.currentTarget.value),
|
||||
required: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.email })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password", children: "Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password,
|
||||
onChange: (e) => form.setData("password", e.currentTarget.value),
|
||||
required: true,
|
||||
autoComplete: "new-password"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.password })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password_confirmation", children: "Confirm Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password_confirmation",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password_confirmation,
|
||||
onChange: (e) => form.setData("password_confirmation", e.currentTarget.value),
|
||||
required: true,
|
||||
autoComplete: "new-password"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
InputError,
|
||||
{
|
||||
className: "mt-2",
|
||||
message: form.errors.password_confirmation
|
||||
}
|
||||
)
|
||||
] }),
|
||||
page.props.jetstream.hasTermsAndPrivacyPolicyFeature && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsxs(InputLabel, { htmlFor: "terms", children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
Checkbox,
|
||||
{
|
||||
name: "terms",
|
||||
id: "terms",
|
||||
checked: form.data.terms,
|
||||
onChange: (e) => form.setData("terms", e.currentTarget.checked),
|
||||
required: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs("div", { className: "ml-2", children: [
|
||||
"I agree to the",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
target: "_blank",
|
||||
href: route("terms.show"),
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
|
||||
children: "Terms of Service"
|
||||
}
|
||||
),
|
||||
"and",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
target: "_blank",
|
||||
href: route("policy.show"),
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
|
||||
children: "Privacy Policy"
|
||||
}
|
||||
)
|
||||
] })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.terms })
|
||||
] }) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end mt-4", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("login"),
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
|
||||
children: "Already registered?"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames("ml-4", { "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Register"
|
||||
}
|
||||
)
|
||||
] })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
Register as default
|
||||
};
|
98
bootstrap/ssr/assets/ResetPassword-DAOSACWm.js
Normal file
98
bootstrap/ssr/assets/ResetPassword-DAOSACWm.js
Normal file
@ -0,0 +1,98 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm, Head } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as AuthenticationCard } from "./AuthenticationCard--MCzdtHR.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function ResetPassword({ token, email }) {
|
||||
const route = useRoute();
|
||||
const form = useForm({
|
||||
token,
|
||||
email,
|
||||
password: "",
|
||||
password_confirmation: ""
|
||||
});
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
form.post(route("password.update"), {
|
||||
onFinish: () => form.reset("password", "password_confirmation")
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(AuthenticationCard, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Reset Password" }),
|
||||
/* @__PURE__ */ jsxs("form", { onSubmit, children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "email", children: "Email" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "email",
|
||||
type: "email",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.email,
|
||||
onChange: (e) => form.setData("email", e.currentTarget.value),
|
||||
required: true,
|
||||
autoFocus: true
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.email })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password", children: "Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password,
|
||||
onChange: (e) => form.setData("password", e.currentTarget.value),
|
||||
required: true,
|
||||
autoComplete: "new-password"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.password })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password_confirmation", children: "Confirm Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password_confirmation",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password_confirmation,
|
||||
onChange: (e) => form.setData("password_confirmation", e.currentTarget.value),
|
||||
required: true,
|
||||
autoComplete: "new-password"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
InputError,
|
||||
{
|
||||
className: "mt-2",
|
||||
message: form.errors.password_confirmation
|
||||
}
|
||||
)
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end mt-4", children: /* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Reset Password"
|
||||
}
|
||||
) })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
ResetPassword as default
|
||||
};
|
21
bootstrap/ssr/assets/SecondaryButton-G68tKuYQ.js
Normal file
21
bootstrap/ssr/assets/SecondaryButton-G68tKuYQ.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import classNames from "classnames";
|
||||
function SecondaryButton({
|
||||
children,
|
||||
...props
|
||||
}) {
|
||||
return /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
...props,
|
||||
className: classNames(
|
||||
"inline-flex items-center px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-xs hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150",
|
||||
props.className
|
||||
),
|
||||
children
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
SecondaryButton as S
|
||||
};
|
7
bootstrap/ssr/assets/SectionBorder-Dh4nHf2e.js
Normal file
7
bootstrap/ssr/assets/SectionBorder-Dh4nHf2e.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
function SectionBorder() {
|
||||
return /* @__PURE__ */ jsx("div", { className: "hidden sm:block", children: /* @__PURE__ */ jsx("div", { className: "py-8", children: /* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-700" }) }) });
|
||||
}
|
||||
export {
|
||||
SectionBorder as S
|
||||
};
|
10
bootstrap/ssr/assets/SectionTitle-DnuUNpyS.js
Normal file
10
bootstrap/ssr/assets/SectionTitle-DnuUNpyS.js
Normal file
@ -0,0 +1,10 @@
|
||||
import { jsx, jsxs } from "react/jsx-runtime";
|
||||
function SectionTitle({ title, description }) {
|
||||
return /* @__PURE__ */ jsx("div", { className: "md:col-span-1", children: /* @__PURE__ */ jsxs("div", { className: "px-4 sm:px-0", children: [
|
||||
/* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: title }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-gray-600 dark:text-gray-400", children: description })
|
||||
] }) });
|
||||
}
|
||||
export {
|
||||
SectionTitle as S
|
||||
};
|
55
bootstrap/ssr/assets/Show-C_aCmrEJ.js
Normal file
55
bootstrap/ssr/assets/Show-C_aCmrEJ.js
Normal file
@ -0,0 +1,55 @@
|
||||
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
||||
import DeleteTeamForm from "./DeleteTeamForm-CDG-Mx5L.js";
|
||||
import TeamMemberManager from "./TeamMemberManager-vS8Og7eY.js";
|
||||
import UpdateTeamNameForm from "./UpdateTeamNameForm-CArH28KV.js";
|
||||
import { S as SectionBorder } from "./SectionBorder-Dh4nHf2e.js";
|
||||
import { A as AppLayout } from "./AppLayout-DitNPgwT.js";
|
||||
import "../app.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "@inertiajs/react";
|
||||
import "react";
|
||||
import "./Modal-D5yHmTM4.js";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "@headlessui/react";
|
||||
import "classnames";
|
||||
import "react-dom";
|
||||
import "./ConfirmationModal-BYr2Juy2.js";
|
||||
import "./DangerButton-BAZynYAq.js";
|
||||
import "./SecondaryButton-G68tKuYQ.js";
|
||||
import "./useTypedPage-Do3SqtsL.js";
|
||||
import "./ActionMessage-s_mcCJ3s.js";
|
||||
import "./DialogModal-D0pyMzH2.js";
|
||||
import "./FormSection-DI6t3wFC.js";
|
||||
import "./TextInput-CMJy2hIv.js";
|
||||
import "./InputLabel-DhqxoV6M.js";
|
||||
import "./PrimaryButton-C2B8UWiv.js";
|
||||
import "@inertiajs/core";
|
||||
function Show({ team, availableRoles, permissions }) {
|
||||
return /* @__PURE__ */ jsx(
|
||||
AppLayout,
|
||||
{
|
||||
title: "Team Settings",
|
||||
renderHeader: () => /* @__PURE__ */ jsx("h2", { className: "font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight", children: "Team Settings" }),
|
||||
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto py-10 sm:px-6 lg:px-8", children: [
|
||||
/* @__PURE__ */ jsx(UpdateTeamNameForm, { team, permissions }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-10 sm:mt-0", children: /* @__PURE__ */ jsx(
|
||||
TeamMemberManager,
|
||||
{
|
||||
team,
|
||||
availableRoles,
|
||||
userPermissions: permissions
|
||||
}
|
||||
) }),
|
||||
permissions.canDeleteTeam && !team.personal_team ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(SectionBorder, {}),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-10 sm:mt-0", children: /* @__PURE__ */ jsx(DeleteTeamForm, { team }) })
|
||||
] }) : null
|
||||
] }) })
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
Show as default
|
||||
};
|
69
bootstrap/ssr/assets/Show-DAwzGQF4.js
Normal file
69
bootstrap/ssr/assets/Show-DAwzGQF4.js
Normal file
@ -0,0 +1,69 @@
|
||||
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
||||
import DeleteUserForm from "./DeleteUserForm-Ptw0GKXr.js";
|
||||
import LogoutOtherBrowserSessions from "./LogoutOtherBrowserSessionsForm-Bd8DyQdZ.js";
|
||||
import TwoFactorAuthenticationForm from "./TwoFactorAuthenticationForm-BLalZpWn.js";
|
||||
import UpdatePasswordForm from "./UpdatePasswordForm-B_100APE.js";
|
||||
import UpdateProfileInformationForm from "./UpdateProfileInformationForm-g6OOT46r.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import { S as SectionBorder } from "./SectionBorder-Dh4nHf2e.js";
|
||||
import { A as AppLayout } from "./AppLayout-DitNPgwT.js";
|
||||
import "@inertiajs/react";
|
||||
import "classnames";
|
||||
import "react";
|
||||
import "../app.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "./Modal-D5yHmTM4.js";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "@headlessui/react";
|
||||
import "react-dom";
|
||||
import "./DangerButton-BAZynYAq.js";
|
||||
import "./DialogModal-D0pyMzH2.js";
|
||||
import "./TextInput-CMJy2hIv.js";
|
||||
import "./SecondaryButton-G68tKuYQ.js";
|
||||
import "./ActionMessage-s_mcCJ3s.js";
|
||||
import "./PrimaryButton-C2B8UWiv.js";
|
||||
import "@inertiajs/core";
|
||||
import "./InputLabel-DhqxoV6M.js";
|
||||
import "./FormSection-DI6t3wFC.js";
|
||||
function Show({
|
||||
sessions,
|
||||
confirmsTwoFactorAuthentication
|
||||
}) {
|
||||
const page = useTypedPage();
|
||||
return /* @__PURE__ */ jsx(
|
||||
AppLayout,
|
||||
{
|
||||
title: "Profile",
|
||||
renderHeader: () => /* @__PURE__ */ jsx("h2", { className: "font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight", children: "Profile" }),
|
||||
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto py-10 sm:px-6 lg:px-8", children: [
|
||||
page.props.jetstream.canUpdateProfileInformation ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(UpdateProfileInformationForm, { user: page.props.auth.user }),
|
||||
/* @__PURE__ */ jsx(SectionBorder, {})
|
||||
] }) : null,
|
||||
page.props.jetstream.canUpdatePassword ? /* @__PURE__ */ jsxs("div", { className: "mt-10 sm:mt-0", children: [
|
||||
/* @__PURE__ */ jsx(UpdatePasswordForm, {}),
|
||||
/* @__PURE__ */ jsx(SectionBorder, {})
|
||||
] }) : null,
|
||||
page.props.jetstream.canManageTwoFactorAuthentication ? /* @__PURE__ */ jsxs("div", { className: "mt-10 sm:mt-0", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
TwoFactorAuthenticationForm,
|
||||
{
|
||||
requiresConfirmation: confirmsTwoFactorAuthentication
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(SectionBorder, {})
|
||||
] }) : null,
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-10 sm:mt-0", children: /* @__PURE__ */ jsx(LogoutOtherBrowserSessions, { sessions }) }),
|
||||
page.props.jetstream.hasAccountDeletionFeatures ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(SectionBorder, {}),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-10 sm:mt-0", children: /* @__PURE__ */ jsx(DeleteUserForm, {}) })
|
||||
] }) : null
|
||||
] }) })
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
Show as default
|
||||
};
|
436
bootstrap/ssr/assets/TeamMemberManager-vS8Og7eY.js
Normal file
436
bootstrap/ssr/assets/TeamMemberManager-vS8Og7eY.js
Normal file
@ -0,0 +1,436 @@
|
||||
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import { A as ActionMessage } from "./ActionMessage-s_mcCJ3s.js";
|
||||
import { A as ActionSection } from "./Modal-D5yHmTM4.js";
|
||||
import { C as ConfirmationModal } from "./ConfirmationModal-BYr2Juy2.js";
|
||||
import { D as DangerButton } from "./DangerButton-BAZynYAq.js";
|
||||
import { D as DialogModal } from "./DialogModal-D0pyMzH2.js";
|
||||
import { F as FormSection } from "./FormSection-DI6t3wFC.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { S as SecondaryButton } from "./SecondaryButton-G68tKuYQ.js";
|
||||
import { S as SectionBorder } from "./SectionBorder-Dh4nHf2e.js";
|
||||
import { router } from "@inertiajs/core";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState } from "react";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "@headlessui/react";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "react-dom";
|
||||
function TeamMemberManager({
|
||||
team,
|
||||
availableRoles,
|
||||
userPermissions
|
||||
}) {
|
||||
const route = useRoute();
|
||||
const addTeamMemberForm = useForm({
|
||||
email: "",
|
||||
role: null
|
||||
});
|
||||
const updateRoleForm = useForm({
|
||||
role: null
|
||||
});
|
||||
const leaveTeamForm = useForm({});
|
||||
const removeTeamMemberForm = useForm({});
|
||||
const [currentlyManagingRole, setCurrentlyManagingRole] = useState(false);
|
||||
const [managingRoleFor, setManagingRoleFor] = useState(null);
|
||||
const [confirmingLeavingTeam, setConfirmingLeavingTeam] = useState(false);
|
||||
const [teamMemberBeingRemoved, setTeamMemberBeingRemoved] = useState(null);
|
||||
const page = useTypedPage();
|
||||
function addTeamMember() {
|
||||
addTeamMemberForm.post(route("team-members.store", [team]), {
|
||||
errorBag: "addTeamMember",
|
||||
preserveScroll: true,
|
||||
onSuccess: () => addTeamMemberForm.reset()
|
||||
});
|
||||
}
|
||||
function cancelTeamInvitation(invitation) {
|
||||
router.delete(route("team-invitations.destroy", [invitation]), {
|
||||
preserveScroll: true
|
||||
});
|
||||
}
|
||||
function manageRole(teamMember) {
|
||||
setManagingRoleFor(teamMember);
|
||||
updateRoleForm.setData("role", teamMember.membership.role);
|
||||
setCurrentlyManagingRole(true);
|
||||
}
|
||||
function updateRole() {
|
||||
if (!managingRoleFor) {
|
||||
return;
|
||||
}
|
||||
updateRoleForm.put(route("team-members.update", [team, managingRoleFor]), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => setCurrentlyManagingRole(false)
|
||||
});
|
||||
}
|
||||
function confirmLeavingTeam() {
|
||||
setConfirmingLeavingTeam(true);
|
||||
}
|
||||
function leaveTeam() {
|
||||
leaveTeamForm.delete(
|
||||
route("team-members.destroy", [team, page.props.auth.user])
|
||||
);
|
||||
}
|
||||
function confirmTeamMemberRemoval(teamMember) {
|
||||
setTeamMemberBeingRemoved(teamMember);
|
||||
}
|
||||
function removeTeamMember() {
|
||||
if (!teamMemberBeingRemoved) {
|
||||
return;
|
||||
}
|
||||
removeTeamMemberForm.delete(
|
||||
route("team-members.destroy", [team, teamMemberBeingRemoved]),
|
||||
{
|
||||
errorBag: "removeTeamMember",
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
onSuccess: () => setTeamMemberBeingRemoved(null)
|
||||
}
|
||||
);
|
||||
}
|
||||
function displayableRole(role) {
|
||||
var _a;
|
||||
return (_a = availableRoles.find((r) => r.key === role)) == null ? void 0 : _a.name;
|
||||
}
|
||||
return /* @__PURE__ */ jsxs("div", { children: [
|
||||
userPermissions.canAddTeamMembers ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(SectionBorder, {}),
|
||||
/* @__PURE__ */ jsxs(
|
||||
FormSection,
|
||||
{
|
||||
onSubmit: addTeamMember,
|
||||
title: "Add Team Member",
|
||||
description: "Add a new team member to your team, allowing them to collaborate with you.",
|
||||
renderActions: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
ActionMessage,
|
||||
{
|
||||
on: addTeamMemberForm.recentlySuccessful,
|
||||
className: "mr-3",
|
||||
children: "Added."
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({
|
||||
"opacity-25": addTeamMemberForm.processing
|
||||
}),
|
||||
disabled: addTeamMemberForm.processing,
|
||||
children: "Add"
|
||||
}
|
||||
)
|
||||
] }),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "col-span-6", children: /* @__PURE__ */ jsx("div", { className: "max-w-xl text-sm text-gray-600 dark:text-gray-400", children: "Please provide the email address of the person you would like to add to this team." }) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "email", value: "Email" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "email",
|
||||
type: "email",
|
||||
className: "mt-1 block w-full",
|
||||
value: addTeamMemberForm.data.email,
|
||||
onChange: (e) => addTeamMemberForm.setData("email", e.currentTarget.value)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
InputError,
|
||||
{
|
||||
message: addTeamMemberForm.errors.email,
|
||||
className: "mt-2"
|
||||
}
|
||||
)
|
||||
] }),
|
||||
availableRoles.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "col-span-6 lg:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "roles", value: "Role" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
InputError,
|
||||
{
|
||||
message: addTeamMemberForm.errors.role,
|
||||
className: "mt-2"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("div", { className: "relative z-0 mt-1 border border-gray-200 dark:border-gray-700 rounded-lg cursor-pointer", children: availableRoles.map((role, i) => /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: classNames(
|
||||
"relative px-4 py-3 inline-flex w-full rounded-lg focus:z-10 focus:outline-hidden focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-600",
|
||||
{
|
||||
"border-t border-gray-200 dark:border-gray-700 focus:border-none rounded-t-none": i > 0,
|
||||
"rounded-b-none": i != Object.keys(availableRoles).length - 1
|
||||
}
|
||||
),
|
||||
onClick: () => addTeamMemberForm.setData("role", role.key),
|
||||
children: /* @__PURE__ */ jsxs(
|
||||
"div",
|
||||
{
|
||||
className: classNames({
|
||||
"opacity-50": addTeamMemberForm.data.role && addTeamMemberForm.data.role != role.key
|
||||
}),
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: classNames(
|
||||
"text-sm text-gray-600 dark:text-gray-400",
|
||||
{
|
||||
"font-semibold": addTeamMemberForm.data.role == role.key
|
||||
}
|
||||
),
|
||||
children: role.name
|
||||
}
|
||||
),
|
||||
addTeamMemberForm.data.role == role.key ? /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "ml-2 h-5 w-5 text-green-400",
|
||||
fill: "none",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
stroke: "currentColor",
|
||||
viewBox: "0 0 24 24",
|
||||
children: /* @__PURE__ */ jsx("path", { d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })
|
||||
}
|
||||
) : null
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-2 text-xs text-gray-600 dark:text-gray-400", children: role.description })
|
||||
]
|
||||
}
|
||||
)
|
||||
},
|
||||
role.key
|
||||
)) })
|
||||
] }) : null
|
||||
]
|
||||
}
|
||||
)
|
||||
] }) : null,
|
||||
team.team_invitations.length > 0 && userPermissions.canAddTeamMembers ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(SectionBorder, {}),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-10 sm:mt-0" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
ActionSection,
|
||||
{
|
||||
title: "Pending Team Invitations",
|
||||
description: "These people have been invited to your team and have been sent an invitation email. They may join the team by accepting the email invitation.",
|
||||
children: /* @__PURE__ */ jsx("div", { className: "space-y-6", children: team.team_invitations.map((invitation) => /* @__PURE__ */ jsxs(
|
||||
"div",
|
||||
{
|
||||
className: "flex items-center justify-between",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "text-gray-600 dark:text-gray-400", children: invitation.email }),
|
||||
/* @__PURE__ */ jsx("div", { className: "flex items-center", children: userPermissions.canRemoveTeamMembers ? /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
className: "cursor-pointer ml-6 text-sm text-red-500 focus:outline-hidden",
|
||||
onClick: () => cancelTeamInvitation(invitation),
|
||||
children: "Cancel"
|
||||
}
|
||||
) : null })
|
||||
]
|
||||
},
|
||||
invitation.id
|
||||
)) })
|
||||
}
|
||||
)
|
||||
] }) : null,
|
||||
team.users.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(SectionBorder, {}),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-10 sm:mt-0" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
ActionSection,
|
||||
{
|
||||
title: "Team Members",
|
||||
description: "All of the people that are part of this team.",
|
||||
children: /* @__PURE__ */ jsx("div", { className: "space-y-6", children: team.users.map((user) => {
|
||||
var _a;
|
||||
return /* @__PURE__ */ jsxs(
|
||||
"div",
|
||||
{
|
||||
className: "flex items-center justify-between",
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"img",
|
||||
{
|
||||
className: "w-8 h-8 rounded-full",
|
||||
src: user.profile_photo_url,
|
||||
alt: user.name
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("div", { className: "ml-4 dark:text-white", children: user.name })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
userPermissions.canAddTeamMembers && availableRoles.length ? /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
className: "ml-2 text-sm text-gray-400 underline",
|
||||
onClick: () => manageRole(user),
|
||||
children: displayableRole(user.membership.role)
|
||||
}
|
||||
) : availableRoles.length ? /* @__PURE__ */ jsx("div", { className: "ml-2 text-sm text-gray-400", children: displayableRole(user.membership.role) }) : null,
|
||||
((_a = page.props.auth.user) == null ? void 0 : _a.id) === user.id ? /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
className: "cursor-pointer ml-6 text-sm text-red-500",
|
||||
onClick: confirmLeavingTeam,
|
||||
children: "Leave"
|
||||
}
|
||||
) : null,
|
||||
userPermissions.canRemoveTeamMembers ? /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
className: "cursor-pointer ml-6 text-sm text-red-500",
|
||||
onClick: () => confirmTeamMemberRemoval(user),
|
||||
children: "Remove"
|
||||
}
|
||||
) : null
|
||||
] })
|
||||
]
|
||||
},
|
||||
user.id
|
||||
);
|
||||
}) })
|
||||
}
|
||||
)
|
||||
] }) : null,
|
||||
/* @__PURE__ */ jsxs(
|
||||
DialogModal,
|
||||
{
|
||||
isOpen: currentlyManagingRole,
|
||||
onClose: () => setCurrentlyManagingRole(false),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(DialogModal.Content, { title: "Manage Role" }),
|
||||
managingRoleFor ? /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", { className: "relative z-0 mt-1 border border-gray-200 dark:border-gray-700 rounded-lg cursor-pointer", children: availableRoles.map((role, i) => /* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: classNames(
|
||||
"relative px-4 py-3 inline-flex w-full rounded-lg focus:z-10 focus:outline-hidden focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-600",
|
||||
{
|
||||
"border-t border-gray-200 dark:border-gray-700 focus:border-none rounded-t-none": i > 0,
|
||||
"rounded-b-none": i !== Object.keys(availableRoles).length - 1
|
||||
}
|
||||
),
|
||||
onClick: () => updateRoleForm.setData("role", role.key),
|
||||
children: /* @__PURE__ */ jsxs(
|
||||
"div",
|
||||
{
|
||||
className: classNames({
|
||||
"opacity-50": updateRoleForm.data.role && updateRoleForm.data.role !== role.key
|
||||
}),
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: classNames(
|
||||
"text-sm text-gray-600 dark:text-gray-400",
|
||||
{
|
||||
"font-semibold": updateRoleForm.data.role === role.key
|
||||
}
|
||||
),
|
||||
children: role.name
|
||||
}
|
||||
),
|
||||
updateRoleForm.data.role === role.key ? /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
className: "ml-2 h-5 w-5 text-green-400",
|
||||
fill: "none",
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
strokeWidth: "2",
|
||||
stroke: "currentColor",
|
||||
viewBox: "0 0 24 24",
|
||||
children: /* @__PURE__ */ jsx("path", { d: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" })
|
||||
}
|
||||
) : null
|
||||
] }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-2 text-xs text-gray-600 dark:text-gray-400", children: role.description })
|
||||
]
|
||||
}
|
||||
)
|
||||
},
|
||||
role.key
|
||||
)) }) }) : null,
|
||||
/* @__PURE__ */ jsxs(DialogModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: () => setCurrentlyManagingRole(false), children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
onClick: updateRole,
|
||||
className: classNames("ml-2", {
|
||||
"opacity-25": updateRoleForm.processing
|
||||
}),
|
||||
disabled: updateRoleForm.processing,
|
||||
children: "Save"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs(
|
||||
ConfirmationModal,
|
||||
{
|
||||
isOpen: confirmingLeavingTeam,
|
||||
onClose: () => setConfirmingLeavingTeam(false),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(ConfirmationModal.Content, { title: "Leave Team", children: "Are you sure you would like to leave this team?" }),
|
||||
/* @__PURE__ */ jsxs(ConfirmationModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: () => setConfirmingLeavingTeam(false), children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
DangerButton,
|
||||
{
|
||||
onClick: leaveTeam,
|
||||
className: classNames("ml-2", {
|
||||
"opacity-25": leaveTeamForm.processing
|
||||
}),
|
||||
disabled: leaveTeamForm.processing,
|
||||
children: "Leave"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs(
|
||||
ConfirmationModal,
|
||||
{
|
||||
isOpen: !!teamMemberBeingRemoved,
|
||||
onClose: () => setTeamMemberBeingRemoved(null),
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(ConfirmationModal.Content, { title: "Remove Team Member", children: "Are you sure you would like to remove this person from the team?" }),
|
||||
/* @__PURE__ */ jsxs(ConfirmationModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: () => setTeamMemberBeingRemoved(null), children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
DangerButton,
|
||||
{
|
||||
onClick: removeTeamMember,
|
||||
className: classNames("ml-2", {
|
||||
"opacity-25": removeTeamMemberForm.processing
|
||||
}),
|
||||
disabled: removeTeamMemberForm.processing,
|
||||
children: "Remove"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
}
|
||||
)
|
||||
] });
|
||||
}
|
||||
export {
|
||||
TeamMemberManager as default
|
||||
};
|
21
bootstrap/ssr/assets/TermsOfService-CfLQttvD.js
Normal file
21
bootstrap/ssr/assets/TermsOfService-CfLQttvD.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { A as AuthenticationCardLogo } from "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
import { Head } from "@inertiajs/react";
|
||||
function TermsOfService({ terms }) {
|
||||
return /* @__PURE__ */ jsxs("div", { className: "font-sans text-gray-900 dark:text-gray-100 antialiased", children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Terms of Service" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "pt-4 bg-gray-100 dark:bg-gray-900", children: /* @__PURE__ */ jsxs("div", { className: "min-h-screen flex flex-col items-center pt-6 sm:pt-0", children: [
|
||||
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(AuthenticationCardLogo, {}) }),
|
||||
/* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: "w-full sm:max-w-2xl mt-6 p-6 bg-white dark:bg-gray-800 shadow-md overflow-hidden sm:rounded-lg prose dark:prose-invert",
|
||||
dangerouslySetInnerHTML: { __html: terms }
|
||||
}
|
||||
)
|
||||
] }) })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
TermsOfService as default
|
||||
};
|
28
bootstrap/ssr/assets/TextInput-CMJy2hIv.js
Normal file
28
bootstrap/ssr/assets/TextInput-CMJy2hIv.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
import classNames from "classnames";
|
||||
import { forwardRef } from "react";
|
||||
function InputError({
|
||||
message,
|
||||
className,
|
||||
children
|
||||
}) {
|
||||
if (!message && !children) {
|
||||
return null;
|
||||
}
|
||||
return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: message || children }) });
|
||||
}
|
||||
const TextInput = forwardRef((props, ref) => /* @__PURE__ */ jsx(
|
||||
"input",
|
||||
{
|
||||
...props,
|
||||
ref,
|
||||
className: classNames(
|
||||
"border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-xs",
|
||||
props.className
|
||||
)
|
||||
}
|
||||
));
|
||||
export {
|
||||
InputError as I,
|
||||
TextInput as T
|
||||
};
|
290
bootstrap/ssr/assets/TwoFactorAuthenticationForm-BLalZpWn.js
Normal file
290
bootstrap/ssr/assets/TwoFactorAuthenticationForm-BLalZpWn.js
Normal file
@ -0,0 +1,290 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { router } from "@inertiajs/core";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import axios from "axios";
|
||||
import classNames from "classnames";
|
||||
import { useState, useRef } from "react";
|
||||
import { A as ActionSection } from "./Modal-D5yHmTM4.js";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { D as DialogModal } from "./DialogModal-D0pyMzH2.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { S as SecondaryButton } from "./SecondaryButton-G68tKuYQ.js";
|
||||
import { D as DangerButton } from "./DangerButton-BAZynYAq.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
import "@headlessui/react";
|
||||
import "react-dom";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
function ConfirmsPassword({
|
||||
title = "Confirm Password",
|
||||
content = "For your security, please confirm your password to continue.",
|
||||
button = "Confirm",
|
||||
onConfirm,
|
||||
children
|
||||
}) {
|
||||
const route = useRoute();
|
||||
const [confirmingPassword, setConfirmingPassword] = useState(false);
|
||||
const [form, setForm] = useState({
|
||||
password: "",
|
||||
error: "",
|
||||
processing: false
|
||||
});
|
||||
const passwordRef = useRef(null);
|
||||
function startConfirmingPassword() {
|
||||
axios.get(route("password.confirmation")).then((response) => {
|
||||
if (response.data.confirmed) {
|
||||
onConfirm();
|
||||
} else {
|
||||
setConfirmingPassword(true);
|
||||
setTimeout(() => {
|
||||
var _a;
|
||||
return (_a = passwordRef.current) == null ? void 0 : _a.focus();
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
}
|
||||
function confirmPassword() {
|
||||
setForm({ ...form, processing: true });
|
||||
axios.post(route("password.confirm"), {
|
||||
password: form.password
|
||||
}).then(() => {
|
||||
closeModal();
|
||||
setTimeout(() => onConfirm(), 250);
|
||||
}).catch((error) => {
|
||||
var _a;
|
||||
setForm({
|
||||
...form,
|
||||
processing: false,
|
||||
error: error.response.data.errors.password[0]
|
||||
});
|
||||
(_a = passwordRef.current) == null ? void 0 : _a.focus();
|
||||
});
|
||||
}
|
||||
function closeModal() {
|
||||
setConfirmingPassword(false);
|
||||
setForm({ processing: false, password: "", error: "" });
|
||||
}
|
||||
return /* @__PURE__ */ jsxs("span", { children: [
|
||||
/* @__PURE__ */ jsx("span", { onClick: startConfirmingPassword, children }),
|
||||
/* @__PURE__ */ jsxs(DialogModal, { isOpen: confirmingPassword, onClose: closeModal, children: [
|
||||
/* @__PURE__ */ jsxs(DialogModal.Content, { title, children: [
|
||||
content,
|
||||
/* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
ref: passwordRef,
|
||||
type: "password",
|
||||
className: "mt-1 block w-3/4",
|
||||
placeholder: "Password",
|
||||
value: form.password,
|
||||
onChange: (e) => setForm({ ...form, password: e.currentTarget.value })
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.error, className: "mt-2" })
|
||||
] })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs(DialogModal.Footer, { children: [
|
||||
/* @__PURE__ */ jsx(SecondaryButton, { onClick: closeModal, children: "Cancel" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames("ml-2", { "opacity-25": form.processing }),
|
||||
onClick: confirmPassword,
|
||||
disabled: form.processing,
|
||||
children: button
|
||||
}
|
||||
)
|
||||
] })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
function TwoFactorAuthenticationForm({
|
||||
requiresConfirmation
|
||||
}) {
|
||||
var _a, _b, _c;
|
||||
const page = useTypedPage();
|
||||
const [enabling, setEnabling] = useState(false);
|
||||
const [disabling, setDisabling] = useState(false);
|
||||
const [qrCode, setQrCode] = useState(null);
|
||||
const [recoveryCodes, setRecoveryCodes] = useState([]);
|
||||
const [confirming, setConfirming] = useState(false);
|
||||
const [setupKey, setSetupKey] = useState(null);
|
||||
const confirmationForm = useForm({
|
||||
code: ""
|
||||
});
|
||||
const twoFactorEnabled = !enabling && ((_c = (_b = (_a = page.props) == null ? void 0 : _a.auth) == null ? void 0 : _b.user) == null ? void 0 : _c.two_factor_enabled);
|
||||
function enableTwoFactorAuthentication() {
|
||||
setEnabling(true);
|
||||
router.post(
|
||||
"/user/two-factor-authentication",
|
||||
{},
|
||||
{
|
||||
preserveScroll: true,
|
||||
onSuccess() {
|
||||
return Promise.all([
|
||||
showQrCode(),
|
||||
showSetupKey(),
|
||||
showRecoveryCodes()
|
||||
]);
|
||||
},
|
||||
onFinish() {
|
||||
setEnabling(false);
|
||||
setConfirming(requiresConfirmation);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
function showSetupKey() {
|
||||
return axios.get("/user/two-factor-secret-key").then((response) => {
|
||||
setSetupKey(response.data.secretKey);
|
||||
});
|
||||
}
|
||||
function confirmTwoFactorAuthentication() {
|
||||
confirmationForm.post("/user/confirmed-two-factor-authentication", {
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
errorBag: "confirmTwoFactorAuthentication",
|
||||
onSuccess: () => {
|
||||
setConfirming(false);
|
||||
setQrCode(null);
|
||||
setSetupKey(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
function showQrCode() {
|
||||
return axios.get("/user/two-factor-qr-code").then((response) => {
|
||||
setQrCode(response.data.svg);
|
||||
});
|
||||
}
|
||||
function showRecoveryCodes() {
|
||||
return axios.get("/user/two-factor-recovery-codes").then((response) => {
|
||||
setRecoveryCodes(response.data);
|
||||
});
|
||||
}
|
||||
function regenerateRecoveryCodes() {
|
||||
axios.post("/user/two-factor-recovery-codes").then(() => {
|
||||
showRecoveryCodes();
|
||||
});
|
||||
}
|
||||
function disableTwoFactorAuthentication() {
|
||||
setDisabling(true);
|
||||
router.delete("/user/two-factor-authentication", {
|
||||
preserveScroll: true,
|
||||
onSuccess() {
|
||||
setDisabling(false);
|
||||
setConfirming(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
ActionSection,
|
||||
{
|
||||
title: "Two Factor Authentication",
|
||||
description: "Add additional security to your account using two factor authentication.",
|
||||
children: [
|
||||
(() => {
|
||||
if (twoFactorEnabled && !confirming) {
|
||||
return /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: "You have enabled two factor authentication." });
|
||||
}
|
||||
if (confirming) {
|
||||
return /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: "Finish enabling two factor authentication." });
|
||||
}
|
||||
return /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100", children: "You have not enabled two factor authentication." });
|
||||
})(),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-3 max-w-xl text-sm text-gray-600 dark:text-gray-400", children: /* @__PURE__ */ jsx("p", { children: "When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application." }) }),
|
||||
twoFactorEnabled || confirming ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
qrCode ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400", children: confirming ? /* @__PURE__ */ jsx("p", { className: "font-semibold", children: "To finish enabling two factor authentication, scan the following QR code using your phone's authenticator application or enter the setup key and provide the generated OTP code." }) : /* @__PURE__ */ jsx("p", { children: "Two factor authentication is now enabled. Scan the following QR code using your phone's authenticator application or enter the setup key." }) }),
|
||||
/* @__PURE__ */ jsx(
|
||||
"div",
|
||||
{
|
||||
className: "mt-4",
|
||||
dangerouslySetInnerHTML: { __html: qrCode || "" }
|
||||
}
|
||||
),
|
||||
setupKey && /* @__PURE__ */ jsx("div", { className: "mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400", children: /* @__PURE__ */ jsxs("p", { className: "font-semibold", children: [
|
||||
"Setup Key:",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"span",
|
||||
{
|
||||
dangerouslySetInnerHTML: { __html: setupKey || "" }
|
||||
}
|
||||
)
|
||||
] }) }),
|
||||
confirming && /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "code", value: "Code" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "code",
|
||||
type: "text",
|
||||
name: "code",
|
||||
className: "block mt-1 w-1/2",
|
||||
inputMode: "numeric",
|
||||
autoFocus: true,
|
||||
autoComplete: "one-time-code",
|
||||
value: confirmationForm.data.code,
|
||||
onChange: (e) => confirmationForm.setData("code", e.currentTarget.value)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
InputError,
|
||||
{
|
||||
message: confirmationForm.errors.code,
|
||||
className: "mt-2"
|
||||
}
|
||||
)
|
||||
] })
|
||||
] }) : null,
|
||||
recoveryCodes.length > 0 && !confirming ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-4 max-w-xl text-sm text-gray-600 dark:text-gray-400", children: /* @__PURE__ */ jsx("p", { className: "font-semibold", children: "Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost." }) }),
|
||||
/* @__PURE__ */ jsx("div", { className: "grid gap-1 max-w-xl mt-4 px-4 py-4 font-mono text-sm bg-gray-100 dark:bg-gray-900 rounded-lg", children: recoveryCodes.map((code) => /* @__PURE__ */ jsx("div", { children: code }, code)) })
|
||||
] }) : null
|
||||
] }) : null,
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-5", children: twoFactorEnabled || confirming ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
confirming ? /* @__PURE__ */ jsx(ConfirmsPassword, { onConfirm: confirmTwoFactorAuthentication, children: /* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames("mr-3", { "opacity-25": enabling }),
|
||||
disabled: enabling,
|
||||
children: "Confirm"
|
||||
}
|
||||
) }) : null,
|
||||
recoveryCodes.length > 0 && !confirming ? /* @__PURE__ */ jsx(ConfirmsPassword, { onConfirm: regenerateRecoveryCodes, children: /* @__PURE__ */ jsx(SecondaryButton, { className: "mr-3", children: "Regenerate Recovery Codes" }) }) : null,
|
||||
recoveryCodes.length === 0 && !confirming ? /* @__PURE__ */ jsx(ConfirmsPassword, { onConfirm: showRecoveryCodes, children: /* @__PURE__ */ jsx(SecondaryButton, { className: "mr-3", children: "Show Recovery Codes" }) }) : null,
|
||||
confirming ? /* @__PURE__ */ jsx(ConfirmsPassword, { onConfirm: disableTwoFactorAuthentication, children: /* @__PURE__ */ jsx(
|
||||
SecondaryButton,
|
||||
{
|
||||
className: classNames("mr-3", { "opacity-25": disabling }),
|
||||
disabled: disabling,
|
||||
children: "Cancel"
|
||||
}
|
||||
) }) : /* @__PURE__ */ jsx(ConfirmsPassword, { onConfirm: disableTwoFactorAuthentication, children: /* @__PURE__ */ jsx(
|
||||
DangerButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": disabling }),
|
||||
disabled: disabling,
|
||||
children: "Disable"
|
||||
}
|
||||
) })
|
||||
] }) : /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ConfirmsPassword, { onConfirm: enableTwoFactorAuthentication, children: /* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
type: "button",
|
||||
className: classNames({ "opacity-25": enabling }),
|
||||
disabled: enabling,
|
||||
children: "Enable"
|
||||
}
|
||||
) }) }) })
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
TwoFactorAuthenticationForm as default
|
||||
};
|
103
bootstrap/ssr/assets/TwoFactorChallenge-Tkr6HCx-.js
Normal file
103
bootstrap/ssr/assets/TwoFactorChallenge-Tkr6HCx-.js
Normal file
@ -0,0 +1,103 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm, Head } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState, useRef } from "react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as AuthenticationCard } from "./AuthenticationCard--MCzdtHR.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function TwoFactorChallenge() {
|
||||
const route = useRoute();
|
||||
const [recovery, setRecovery] = useState(false);
|
||||
const form = useForm({
|
||||
code: "",
|
||||
recovery_code: ""
|
||||
});
|
||||
const recoveryCodeRef = useRef(null);
|
||||
const codeRef = useRef(null);
|
||||
function toggleRecovery(e) {
|
||||
e.preventDefault();
|
||||
const isRecovery = !recovery;
|
||||
setRecovery(isRecovery);
|
||||
setTimeout(() => {
|
||||
var _a, _b;
|
||||
if (isRecovery) {
|
||||
(_a = recoveryCodeRef.current) == null ? void 0 : _a.focus();
|
||||
form.setData("code", "");
|
||||
} else {
|
||||
(_b = codeRef.current) == null ? void 0 : _b.focus();
|
||||
form.setData("recovery_code", "");
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
form.post(route("two-factor.login"));
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(AuthenticationCard, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Two-Factor Confirmation" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mb-4 text-sm text-gray-600 dark:text-gray-400", children: recovery ? "Please confirm access to your account by entering one of your emergency recovery codes." : "Please confirm access to your account by entering the authentication code provided by your authenticator application." }),
|
||||
/* @__PURE__ */ jsxs("form", { onSubmit, children: [
|
||||
recovery ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "recovery_code", children: "Recovery Code" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "recovery_code",
|
||||
type: "text",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.recovery_code,
|
||||
onChange: (e) => form.setData("recovery_code", e.currentTarget.value),
|
||||
ref: recoveryCodeRef,
|
||||
autoComplete: "one-time-code"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.recovery_code })
|
||||
] }) : /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "code", children: "Code" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "code",
|
||||
type: "text",
|
||||
inputMode: "numeric",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.code,
|
||||
onChange: (e) => form.setData("code", e.currentTarget.value),
|
||||
autoFocus: true,
|
||||
autoComplete: "one-time-code",
|
||||
ref: codeRef
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { className: "mt-2", message: form.errors.code })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end mt-4", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
className: "text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 underline cursor-pointer",
|
||||
onClick: toggleRecovery,
|
||||
children: recovery ? "Use an authentication code" : "Use a recovery code"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames("ml-4", { "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Log in"
|
||||
}
|
||||
)
|
||||
] })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
TwoFactorChallenge as default
|
||||
};
|
120
bootstrap/ssr/assets/UpdatePasswordForm-B_100APE.js
Normal file
120
bootstrap/ssr/assets/UpdatePasswordForm-B_100APE.js
Normal file
@ -0,0 +1,120 @@
|
||||
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useRef } from "react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as ActionMessage } from "./ActionMessage-s_mcCJ3s.js";
|
||||
import { F as FormSection } from "./FormSection-DI6t3wFC.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "@headlessui/react";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
function UpdatePasswordForm() {
|
||||
const route = useRoute();
|
||||
const form = useForm({
|
||||
current_password: "",
|
||||
password: "",
|
||||
password_confirmation: ""
|
||||
});
|
||||
const passwordRef = useRef(null);
|
||||
const currentPasswordRef = useRef(null);
|
||||
function updatePassword() {
|
||||
form.put(route("user-password.update"), {
|
||||
errorBag: "updatePassword",
|
||||
preserveScroll: true,
|
||||
onSuccess: () => form.reset(),
|
||||
onError: () => {
|
||||
var _a, _b;
|
||||
if (form.errors.password) {
|
||||
form.reset("password", "password_confirmation");
|
||||
(_a = passwordRef.current) == null ? void 0 : _a.focus();
|
||||
}
|
||||
if (form.errors.current_password) {
|
||||
form.reset("current_password");
|
||||
(_b = currentPasswordRef.current) == null ? void 0 : _b.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
FormSection,
|
||||
{
|
||||
onSubmit: updatePassword,
|
||||
title: "Update Password",
|
||||
description: "Ensure your account is using a long, random password to stay secure.",
|
||||
renderActions: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(ActionMessage, { on: form.recentlySuccessful, className: "mr-3", children: "Saved." }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Save"
|
||||
}
|
||||
)
|
||||
] }),
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "current_password", children: "Current Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "current_password",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
ref: currentPasswordRef,
|
||||
value: form.data.current_password,
|
||||
onChange: (e) => form.setData("current_password", e.currentTarget.value),
|
||||
autoComplete: "current-password"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.current_password, className: "mt-2" })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password", children: "New Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password,
|
||||
onChange: (e) => form.setData("password", e.currentTarget.value),
|
||||
autoComplete: "new-password",
|
||||
ref: passwordRef
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.password, className: "mt-2" })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "password_confirmation", children: "Confirm Password" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "password_confirmation",
|
||||
type: "password",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.password_confirmation,
|
||||
onChange: (e) => form.setData("password_confirmation", e.currentTarget.value),
|
||||
autoComplete: "new-password"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
InputError,
|
||||
{
|
||||
message: form.errors.password_confirmation,
|
||||
className: "mt-2"
|
||||
}
|
||||
)
|
||||
] })
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
UpdatePasswordForm as default
|
||||
};
|
201
bootstrap/ssr/assets/UpdateProfileInformationForm-g6OOT46r.js
Normal file
201
bootstrap/ssr/assets/UpdateProfileInformationForm-g6OOT46r.js
Normal file
@ -0,0 +1,201 @@
|
||||
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
||||
import { router } from "@inertiajs/core";
|
||||
import { useForm, Link } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { useState, useRef } from "react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as ActionMessage } from "./ActionMessage-s_mcCJ3s.js";
|
||||
import { F as FormSection } from "./FormSection-DI6t3wFC.js";
|
||||
import { I as InputError, T as TextInput } from "./TextInput-CMJy2hIv.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { S as SecondaryButton } from "./SecondaryButton-G68tKuYQ.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "@headlessui/react";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
function UpdateProfileInformationForm({ user }) {
|
||||
const form = useForm({
|
||||
_method: "PUT",
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
photo: null
|
||||
});
|
||||
const route = useRoute();
|
||||
const [photoPreview, setPhotoPreview] = useState(null);
|
||||
const photoRef = useRef(null);
|
||||
const page = useTypedPage();
|
||||
const [verificationLinkSent, setVerificationLinkSent] = useState(false);
|
||||
function updateProfileInformation() {
|
||||
form.post(route("user-profile-information.update"), {
|
||||
errorBag: "updateProfileInformation",
|
||||
preserveScroll: true,
|
||||
onSuccess: () => clearPhotoFileInput()
|
||||
});
|
||||
}
|
||||
function selectNewPhoto() {
|
||||
var _a;
|
||||
(_a = photoRef.current) == null ? void 0 : _a.click();
|
||||
}
|
||||
function updatePhotoPreview() {
|
||||
var _a, _b;
|
||||
const photo = (_b = (_a = photoRef.current) == null ? void 0 : _a.files) == null ? void 0 : _b[0];
|
||||
if (!photo) {
|
||||
return;
|
||||
}
|
||||
form.setData("photo", photo);
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
var _a2;
|
||||
setPhotoPreview((_a2 = e.target) == null ? void 0 : _a2.result);
|
||||
};
|
||||
reader.readAsDataURL(photo);
|
||||
}
|
||||
function deletePhoto() {
|
||||
router.delete(route("current-user-photo.destroy"), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
setPhotoPreview(null);
|
||||
clearPhotoFileInput();
|
||||
}
|
||||
});
|
||||
}
|
||||
function clearPhotoFileInput() {
|
||||
var _a;
|
||||
if ((_a = photoRef.current) == null ? void 0 : _a.value) {
|
||||
photoRef.current.value = "";
|
||||
form.setData("photo", null);
|
||||
}
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
FormSection,
|
||||
{
|
||||
onSubmit: updateProfileInformation,
|
||||
title: "Profile Information",
|
||||
description: `Update your account's profile information and email address.`,
|
||||
renderActions: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(ActionMessage, { on: form.recentlySuccessful, className: "mr-3", children: "Saved." }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Save"
|
||||
}
|
||||
)
|
||||
] }),
|
||||
children: [
|
||||
page.props.jetstream.managesProfilePhotos ? /* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"input",
|
||||
{
|
||||
type: "file",
|
||||
className: "hidden",
|
||||
ref: photoRef,
|
||||
onChange: updatePhotoPreview
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "photo", value: "Photo" }),
|
||||
photoPreview ? (
|
||||
// <!-- New Profile Photo Preview -->
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
|
||||
"span",
|
||||
{
|
||||
className: "block rounded-full w-20 h-20",
|
||||
style: {
|
||||
backgroundSize: "cover",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center center",
|
||||
backgroundImage: `url('${photoPreview}')`
|
||||
}
|
||||
}
|
||||
) })
|
||||
) : (
|
||||
// <!-- Current Profile Photo -->
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
|
||||
"img",
|
||||
{
|
||||
src: user.profile_photo_url,
|
||||
alt: user.name,
|
||||
className: "rounded-full h-20 w-20 object-cover"
|
||||
}
|
||||
) })
|
||||
),
|
||||
/* @__PURE__ */ jsx(
|
||||
SecondaryButton,
|
||||
{
|
||||
className: "mt-2 mr-2",
|
||||
type: "button",
|
||||
onClick: selectNewPhoto,
|
||||
children: "Select A New Photo"
|
||||
}
|
||||
),
|
||||
user.profile_photo_path ? /* @__PURE__ */ jsx(
|
||||
SecondaryButton,
|
||||
{
|
||||
type: "button",
|
||||
className: "mt-2",
|
||||
onClick: deletePhoto,
|
||||
children: "Remove Photo"
|
||||
}
|
||||
) : null,
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.photo, className: "mt-2" })
|
||||
] }) : null,
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "name", value: "Name" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "name",
|
||||
type: "text",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.name,
|
||||
onChange: (e) => form.setData("name", e.currentTarget.value),
|
||||
autoComplete: "name"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.name, className: "mt-2" })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "email", value: "Email" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "email",
|
||||
type: "email",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.email,
|
||||
onChange: (e) => form.setData("email", e.currentTarget.value)
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.email, className: "mt-2" }),
|
||||
page.props.jetstream.hasEmailVerification && user.email_verified_at === null ? /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsxs("p", { className: "text-sm mt-2 dark:text-white", children: [
|
||||
"Your email address is unverified.",
|
||||
/* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("verification.send"),
|
||||
method: "post",
|
||||
as: "button",
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
|
||||
onClick: (e) => {
|
||||
e.preventDefault();
|
||||
setVerificationLinkSent(true);
|
||||
},
|
||||
children: "Click here to re-send the verification email."
|
||||
}
|
||||
)
|
||||
] }),
|
||||
verificationLinkSent && /* @__PURE__ */ jsx("div", { className: "mt-2 font-medium text-sm text-green-600 dark:text-green-400", children: "A new verification link has been sent to your email address." })
|
||||
] }) : null
|
||||
] })
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
UpdateProfileInformationForm as default
|
||||
};
|
83
bootstrap/ssr/assets/UpdateTeamNameForm-CArH28KV.js
Normal file
83
bootstrap/ssr/assets/UpdateTeamNameForm-CArH28KV.js
Normal file
@ -0,0 +1,83 @@
|
||||
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as ActionMessage } from "./ActionMessage-s_mcCJ3s.js";
|
||||
import { F as FormSection } from "./FormSection-DI6t3wFC.js";
|
||||
import { T as TextInput, I as InputError } from "./TextInput-CMJy2hIv.js";
|
||||
import { I as InputLabel } from "./InputLabel-DhqxoV6M.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import { useForm } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "@headlessui/react";
|
||||
import "./SectionTitle-DnuUNpyS.js";
|
||||
function UpdateTeamNameForm({ team, permissions }) {
|
||||
const route = useRoute();
|
||||
const form = useForm({
|
||||
name: team.name
|
||||
});
|
||||
function updateTeamName() {
|
||||
form.put(route("teams.update", [team]), {
|
||||
errorBag: "updateTeamName",
|
||||
preserveScroll: true
|
||||
});
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(
|
||||
FormSection,
|
||||
{
|
||||
onSubmit: updateTeamName,
|
||||
title: "Team Name",
|
||||
description: `The team's name and owner information.`,
|
||||
renderActions: permissions.canUpdateTeam ? () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(ActionMessage, { on: form.recentlySuccessful, className: "mr-3", children: "Saved." }),
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Save"
|
||||
}
|
||||
)
|
||||
] }) : void 0,
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { value: "Team Owner" }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex items-center mt-2", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"img",
|
||||
{
|
||||
className: "w-12 h-12 rounded-full object-cover",
|
||||
src: team.owner.profile_photo_url,
|
||||
alt: team.owner.name
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs("div", { className: "ml-4 leading-tight", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "text-gray-900 dark:text-white", children: team.owner.name }),
|
||||
/* @__PURE__ */ jsx("div", { className: "text-gray-700 dark:text-gray-300 text-sm", children: team.owner.email })
|
||||
] })
|
||||
] })
|
||||
] }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "col-span-6 sm:col-span-4", children: [
|
||||
/* @__PURE__ */ jsx(InputLabel, { htmlFor: "name", value: "Team Name" }),
|
||||
/* @__PURE__ */ jsx(
|
||||
TextInput,
|
||||
{
|
||||
id: "name",
|
||||
type: "text",
|
||||
className: "mt-1 block w-full",
|
||||
value: form.data.name,
|
||||
onChange: (e) => form.setData("name", e.currentTarget.value),
|
||||
disabled: !permissions.canUpdateTeam
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx(InputError, { message: form.errors.name, className: "mt-2" })
|
||||
] })
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
export {
|
||||
UpdateTeamNameForm as default
|
||||
};
|
56
bootstrap/ssr/assets/VerifyEmail--hB-n-6S.js
Normal file
56
bootstrap/ssr/assets/VerifyEmail--hB-n-6S.js
Normal file
@ -0,0 +1,56 @@
|
||||
import { jsxs, jsx } from "react/jsx-runtime";
|
||||
import { useForm, Head, Link } from "@inertiajs/react";
|
||||
import classNames from "classnames";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { A as AuthenticationCard } from "./AuthenticationCard--MCzdtHR.js";
|
||||
import { P as PrimaryButton } from "./PrimaryButton-C2B8UWiv.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
import "./AuthenticationCardLogo-CZgVhhfE.js";
|
||||
function VerifyEmail({ status }) {
|
||||
const route = useRoute();
|
||||
const form = useForm({});
|
||||
const verificationLinkSent = status === "verification-link-sent";
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
form.post(route("verification.send"));
|
||||
}
|
||||
return /* @__PURE__ */ jsxs(AuthenticationCard, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Email Verification" }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mb-4 text-sm text-gray-600 dark:text-gray-400", children: "Before continuing, could you verify your email address by clicking on the link we just emailed to you? If you didn't receive the email, we will gladly send you another." }),
|
||||
verificationLinkSent && /* @__PURE__ */ jsx("div", { className: "mb-4 font-medium text-sm text-green-600 dark:text-green-400", children: "A new verification link has been sent to the email address you provided during registration." }),
|
||||
/* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-between", children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
PrimaryButton,
|
||||
{
|
||||
className: classNames({ "opacity-25": form.processing }),
|
||||
disabled: form.processing,
|
||||
children: "Resend Verification Email"
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("profile.show"),
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800",
|
||||
children: "Edit Profile"
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("logout"),
|
||||
method: "post",
|
||||
as: "button",
|
||||
className: "underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800 ml-2",
|
||||
children: "Log Out"
|
||||
}
|
||||
)
|
||||
] }) })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
VerifyEmail as default
|
||||
};
|
378
bootstrap/ssr/assets/Welcome-Bnby2VG4.js
Normal file
378
bootstrap/ssr/assets/Welcome-Bnby2VG4.js
Normal file
@ -0,0 +1,378 @@
|
||||
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
||||
import { Head, Link } from "@inertiajs/react";
|
||||
import { u as useRoute } from "../app.js";
|
||||
import { u as useTypedPage } from "./useTypedPage-Do3SqtsL.js";
|
||||
import "axios";
|
||||
import "lodash";
|
||||
import "react-dom/client";
|
||||
import "react";
|
||||
function Welcome({
|
||||
canLogin,
|
||||
canRegister,
|
||||
laravelVersion,
|
||||
phpVersion
|
||||
}) {
|
||||
const route = useRoute();
|
||||
const page = useTypedPage();
|
||||
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(Head, { title: "Welcome" }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "relative sm:flex sm:justify-center sm:items-center min-h-screen bg-dots-darker bg-center bg-gray-100 dark:bg-dots-lighter dark:bg-gray-900 selection:bg-red-500 selection:text-white", children: [
|
||||
canLogin ? /* @__PURE__ */ jsx("div", { className: "sm:fixed sm:top-0 sm:right-0 p-6 text-right", children: page.props.auth.user ? /* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("dashboard"),
|
||||
className: "font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Dashboard"
|
||||
}
|
||||
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("login"),
|
||||
className: "font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Log in"
|
||||
}
|
||||
),
|
||||
canRegister ? /* @__PURE__ */ jsx(
|
||||
Link,
|
||||
{
|
||||
href: route("register"),
|
||||
className: "ml-4 font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Register"
|
||||
}
|
||||
) : null
|
||||
] }) }) : null,
|
||||
/* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto p-6 lg:p-8", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
viewBox: "0 0 62 65",
|
||||
fill: "none",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
className: "h-16 w-auto bg-gray-100 dark:bg-gray-900",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
d: "M61.8548 14.6253C61.8778 14.7102 61.8895 14.7978 61.8897 14.8858V28.5615C61.8898 28.737 61.8434 28.9095 61.7554 29.0614C61.6675 29.2132 61.5409 29.3392 61.3887 29.4265L49.9104 36.0351V49.1337C49.9104 49.4902 49.7209 49.8192 49.4118 49.9987L25.4519 63.7916C25.3971 63.8227 25.3372 63.8427 25.2774 63.8639C25.255 63.8714 25.2338 63.8851 25.2101 63.8913C25.0426 63.9354 24.8666 63.9354 24.6991 63.8913C24.6716 63.8838 24.6467 63.8689 24.6205 63.8589C24.5657 63.8389 24.5084 63.8215 24.456 63.7916L0.501061 49.9987C0.348882 49.9113 0.222437 49.7853 0.134469 49.6334C0.0465019 49.4816 0.000120578 49.3092 0 49.1337L0 8.10652C0 8.01678 0.0124642 7.92953 0.0348998 7.84477C0.0423783 7.8161 0.0598282 7.78993 0.0697995 7.76126C0.0884958 7.70891 0.105946 7.65531 0.133367 7.6067C0.152063 7.5743 0.179485 7.54812 0.20192 7.51821C0.230588 7.47832 0.256763 7.43719 0.290416 7.40229C0.319084 7.37362 0.356476 7.35243 0.388883 7.32751C0.425029 7.29759 0.457436 7.26518 0.498568 7.2415L12.4779 0.345059C12.6296 0.257786 12.8015 0.211853 12.9765 0.211853C13.1515 0.211853 13.3234 0.257786 13.475 0.345059L25.4531 7.2415H25.4556C25.4955 7.26643 25.5292 7.29759 25.5653 7.32626C25.5977 7.35119 25.6339 7.37362 25.6625 7.40104C25.6974 7.43719 25.7224 7.47832 25.7523 7.51821C25.7735 7.54812 25.8021 7.5743 25.8196 7.6067C25.8483 7.65656 25.8645 7.70891 25.8844 7.76126C25.8944 7.78993 25.9118 7.8161 25.9193 7.84602C25.9423 7.93096 25.954 8.01853 25.9542 8.10652V33.7317L35.9355 27.9844V14.8846C35.9355 14.7973 35.948 14.7088 35.9704 14.6253C35.9792 14.5954 35.9954 14.5692 36.0053 14.5405C36.0253 14.4882 36.0427 14.4346 36.0702 14.386C36.0888 14.3536 36.1163 14.3274 36.1375 14.2975C36.1674 14.2576 36.1923 14.2165 36.2272 14.1816C36.2559 14.1529 36.292 14.1317 36.3244 14.1068C36.3618 14.0769 36.3942 14.0445 36.4341 14.0208L48.4147 7.12434C48.5663 7.03694 48.7383 6.99094 48.9133 6.99094C49.0883 6.99094 49.2602 7.03694 49.4118 7.12434L61.3899 14.0208C61.4323 14.0457 61.4647 14.0769 61.5021 14.1055C61.5333 14.1305 61.5694 14.1529 61.5981 14.1803C61.633 14.2165 61.6579 14.2576 61.6878 14.2975C61.7103 14.3274 61.7377 14.3536 61.7551 14.386C61.7838 14.4346 61.8 14.4882 61.8199 14.5405C61.8312 14.5692 61.8474 14.5954 61.8548 14.6253ZM59.893 27.9844V16.6121L55.7013 19.0252L49.9104 22.3593V33.7317L59.8942 27.9844H59.893ZM47.9149 48.5566V37.1768L42.2187 40.4299L25.953 49.7133V61.2003L47.9149 48.5566ZM1.99677 9.83281V48.5566L23.9562 61.199V49.7145L12.4841 43.2219L12.4804 43.2194L12.4754 43.2169C12.4368 43.1945 12.4044 43.1621 12.3682 43.1347C12.3371 43.1097 12.3009 43.0898 12.2735 43.0624L12.271 43.0586C12.2386 43.0275 12.2162 42.9888 12.1887 42.9539C12.1638 42.9203 12.1339 42.8916 12.114 42.8567L12.1127 42.853C12.0903 42.8156 12.0766 42.7707 12.0604 42.7283C12.0442 42.6909 12.023 42.656 12.013 42.6161C12.0005 42.5688 11.998 42.5177 11.9931 42.4691C11.9881 42.4317 11.9781 42.3943 11.9781 42.3569V15.5801L6.18848 12.2446L1.99677 9.83281ZM12.9777 2.36177L2.99764 8.10652L12.9752 13.8513L22.9541 8.10527L12.9752 2.36177H12.9777ZM18.1678 38.2138L23.9574 34.8809V9.83281L19.7657 12.2459L13.9749 15.5801V40.6281L18.1678 38.2138ZM48.9133 9.14105L38.9344 14.8858L48.9133 20.6305L58.8909 14.8846L48.9133 9.14105ZM47.9149 22.3593L42.124 19.0252L37.9323 16.6121V27.9844L43.7219 31.3174L47.9149 33.7317V22.3593ZM24.9533 47.987L39.59 39.631L46.9065 35.4555L36.9352 29.7145L25.4544 36.3242L14.9907 42.3482L24.9533 47.987Z",
|
||||
fill: "#FF2D20"
|
||||
}
|
||||
)
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsx("div", { className: "mt-16", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6 lg:gap-8", children: [
|
||||
/* @__PURE__ */ jsxs(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs",
|
||||
className: "scale-100 p-6 bg-white dark:bg-gray-800/50 dark:bg-linear-to-bl from-gray-700/50 via-transparent dark:ring-1 dark:ring-inset dark:ring-white/5 rounded-lg shadow-2xl shadow-gray-500/20 dark:shadow-none flex motion-safe:hover:scale-[1.01] transition-all duration-250 focus:outline focus:outline-2 focus:outline-red-500",
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "h-16 w-16 bg-red-50 dark:bg-red-800/20 flex items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-7 h-7 stroke-red-500",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25"
|
||||
}
|
||||
)
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsx("h2", { className: "mt-6 text-xl font-semibold text-gray-900 dark:text-white", children: "Documentation" }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: "Laravel has wonderful documentation covering every aspect of the framework. Whether you are a newcomer or have prior experience with Laravel, we recommend reading our documentation from beginning to end." })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "self-center shrink-0 stroke-red-500 w-6 h-6 mx-6",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs(
|
||||
"a",
|
||||
{
|
||||
href: "https://laracasts.com",
|
||||
className: "scale-100 p-6 bg-white dark:bg-gray-800/50 dark:bg-linear-to-bl from-gray-700/50 via-transparent dark:ring-1 dark:ring-inset dark:ring-white/5 rounded-lg shadow-2xl shadow-gray-500/20 dark:shadow-none flex motion-safe:hover:scale-[1.01] transition-all duration-250 focus:outline focus:outline-2 focus:outline-red-500",
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "h-16 w-16 bg-red-50 dark:bg-red-800/20 flex items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-7 h-7 stroke-red-500",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
d: "M15.75 10.5l4.72-4.72a.75.75 0 011.28.53v11.38a.75.75 0 01-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25h-9A2.25 2.25 0 002.25 7.5v9a2.25 2.25 0 002.25 2.25z"
|
||||
}
|
||||
)
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsx("h2", { className: "mt-6 text-xl font-semibold text-gray-900 dark:text-white", children: "Laracasts" }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: "Laracasts offers thousands of video tutorials on Laravel, PHP, and JavaScript development. Check them out, see for yourself, and massively level up your development skills in the process." })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "self-center shrink-0 stroke-red-500 w-6 h-6 mx-6",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsxs(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel-news.com",
|
||||
className: "scale-100 p-6 bg-white dark:bg-gray-800/50 dark:bg-linear-to-bl from-gray-700/50 via-transparent dark:ring-1 dark:ring-inset dark:ring-white/5 rounded-lg shadow-2xl shadow-gray-500/20 dark:shadow-none flex motion-safe:hover:scale-[1.01] transition-all duration-250 focus:outline focus:outline-2 focus:outline-red-500",
|
||||
children: [
|
||||
/* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "h-16 w-16 bg-red-50 dark:bg-red-800/20 flex items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-7 h-7 stroke-red-500",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 01-2.25 2.25M16.5 7.5V18a2.25 2.25 0 002.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 002.25 2.25h13.5M6 7.5h3v3H6v-3z"
|
||||
}
|
||||
)
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsx("h2", { className: "mt-6 text-xl font-semibold text-gray-900 dark:text-white", children: "Laravel News" }),
|
||||
/* @__PURE__ */ jsx("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: "Laravel News is a community driven portal and newsletter aggregating all of the latest and most important news in the Laravel ecosystem, including new package releases and tutorials." })
|
||||
] }),
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "self-center shrink-0 stroke-red-500 w-6 h-6 mx-6",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
),
|
||||
/* @__PURE__ */ jsx("div", { className: "scale-100 p-6 bg-white dark:bg-gray-800/50 dark:bg-linear-to-bl from-gray-700/50 via-transparent dark:ring-1 dark:ring-inset dark:ring-white/5 rounded-lg shadow-2xl shadow-gray-500/20 dark:shadow-none flex motion-safe:hover:scale-[1.01] transition-all duration-250 focus:outline focus:outline-2 focus:outline-red-500", children: /* @__PURE__ */ jsxs("div", { children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "h-16 w-16 bg-red-50 dark:bg-red-800/20 flex items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "w-7 h-7 stroke-red-500",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M6.115 5.19l.319 1.913A6 6 0 008.11 10.36L9.75 12l-.387.775c-.217.433-.132.956.21 1.298l1.348 1.348c.21.21.329.497.329.795v1.089c0 .426.24.815.622 1.006l.153.076c.433.217.956.132 1.298-.21l.723-.723a8.7 8.7 0 002.288-4.042 1.087 1.087 0 00-.358-1.099l-1.33-1.108c-.251-.21-.582-.299-.905-.245l-1.17.195a1.125 1.125 0 01-.98-.314l-.295-.295a1.125 1.125 0 010-1.591l.13-.132a1.125 1.125 0 011.3-.21l.603.302a.809.809 0 001.086-1.086L14.25 7.5l1.256-.837a4.5 4.5 0 001.528-1.732l.146-.292M6.115 5.19A9 9 0 1017.18 4.64M6.115 5.19A8.965 8.965 0 0112 3c1.929 0 3.716.607 5.18 1.64"
|
||||
}
|
||||
)
|
||||
}
|
||||
) }),
|
||||
/* @__PURE__ */ jsx("h2", { className: "mt-6 text-xl font-semibold text-gray-900 dark:text-white", children: "Vibrant Ecosystem" }),
|
||||
/* @__PURE__ */ jsxs("p", { className: "mt-4 text-gray-500 dark:text-gray-400 text-sm leading-relaxed", children: [
|
||||
"Laravel's robust library of first-party tools and libraries, such as",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://forge.laravel.com",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Forge"
|
||||
}
|
||||
),
|
||||
",",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://vapor.laravel.com",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Vapor"
|
||||
}
|
||||
),
|
||||
",",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://nova.laravel.com",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Nova"
|
||||
}
|
||||
),
|
||||
", and",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://envoyer.io",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Envoyer"
|
||||
}
|
||||
),
|
||||
" ",
|
||||
"help you take your projects to the next level. Pair them with powerful open source libraries like",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs/billing",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Cashier"
|
||||
}
|
||||
),
|
||||
",",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs/dusk",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Dusk"
|
||||
}
|
||||
),
|
||||
",",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs/broadcasting",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Echo"
|
||||
}
|
||||
),
|
||||
",",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs/horizon",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Horizon"
|
||||
}
|
||||
),
|
||||
",",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs/sanctum",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Sanctum"
|
||||
}
|
||||
),
|
||||
",",
|
||||
" ",
|
||||
/* @__PURE__ */ jsx(
|
||||
"a",
|
||||
{
|
||||
href: "https://laravel.com/docs/telescope",
|
||||
className: "underline hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: "Telescope"
|
||||
}
|
||||
),
|
||||
", and more."
|
||||
] })
|
||||
] }) })
|
||||
] }) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "flex justify-center mt-16 px-6 sm:items-center sm:justify-between", children: [
|
||||
/* @__PURE__ */ jsx("div", { className: "text-center text-sm text-gray-500 dark:text-gray-400 sm:text-left", children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxs(
|
||||
"a",
|
||||
{
|
||||
href: "https://github.com/sponsors/taylorotwell",
|
||||
className: "group inline-flex items-center hover:text-gray-700 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-xs focus:outline-red-500",
|
||||
children: [
|
||||
/* @__PURE__ */ jsx(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
fill: "none",
|
||||
viewBox: "0 0 24 24",
|
||||
strokeWidth: "1.5",
|
||||
className: "-mt-px mr-1 w-5 h-5 stroke-gray-400 dark:stroke-gray-600 group-hover:stroke-gray-600 dark:group-hover:stroke-gray-400",
|
||||
children: /* @__PURE__ */ jsx(
|
||||
"path",
|
||||
{
|
||||
strokeLinecap: "round",
|
||||
strokeLinejoin: "round",
|
||||
d: "M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z"
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
"Sponsor"
|
||||
]
|
||||
}
|
||||
) }) }),
|
||||
/* @__PURE__ */ jsxs("div", { className: "ml-4 text-center text-sm text-gray-500 dark:text-gray-400 sm:text-right sm:ml-0", children: [
|
||||
"Laravel v",
|
||||
laravelVersion,
|
||||
" (PHP v",
|
||||
phpVersion,
|
||||
")"
|
||||
] })
|
||||
] })
|
||||
] })
|
||||
] })
|
||||
] });
|
||||
}
|
||||
export {
|
||||
Welcome as default
|
||||
};
|
7
bootstrap/ssr/assets/useTypedPage-Do3SqtsL.js
Normal file
7
bootstrap/ssr/assets/useTypedPage-Do3SqtsL.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { usePage } from "@inertiajs/react";
|
||||
function useTypedPage() {
|
||||
return usePage();
|
||||
}
|
||||
export {
|
||||
useTypedPage as u
|
||||
};
|
166
bootstrap/ssr/ssr-manifest.json
Normal file
166
bootstrap/ssr/ssr-manifest.json
Normal file
@ -0,0 +1,166 @@
|
||||
{
|
||||
"node_modules/laravel-vite-plugin/inertia-helpers/index.js": [],
|
||||
"resources/css/app.css": [],
|
||||
"resources/js/Components/ActionMessage.tsx": [
|
||||
"/build/assets/ActionMessage-s_mcCJ3s.js"
|
||||
],
|
||||
"resources/js/Components/ActionSection.tsx": [
|
||||
"/build/assets/Modal-D5yHmTM4.js"
|
||||
],
|
||||
"resources/js/Components/ApplicationLogo.tsx": [
|
||||
"/build/assets/Dashboard-CkDsUhZk.js"
|
||||
],
|
||||
"resources/js/Components/ApplicationMark.tsx": [
|
||||
"/build/assets/AppLayout-DitNPgwT.js"
|
||||
],
|
||||
"resources/js/Components/AuthenticationCard.tsx": [
|
||||
"/build/assets/AuthenticationCard--MCzdtHR.js"
|
||||
],
|
||||
"resources/js/Components/AuthenticationCardLogo.tsx": [
|
||||
"/build/assets/AuthenticationCardLogo-CZgVhhfE.js"
|
||||
],
|
||||
"resources/js/Components/Banner.tsx": [
|
||||
"/build/assets/AppLayout-DitNPgwT.js"
|
||||
],
|
||||
"resources/js/Components/Checkbox.tsx": [
|
||||
"/build/assets/Checkbox-XR8K_oHK.js"
|
||||
],
|
||||
"resources/js/Components/ConfirmationModal.tsx": [
|
||||
"/build/assets/ConfirmationModal-BYr2Juy2.js"
|
||||
],
|
||||
"resources/js/Components/ConfirmsPassword.tsx": [
|
||||
"/build/assets/TwoFactorAuthenticationForm-BLalZpWn.js"
|
||||
],
|
||||
"resources/js/Components/DangerButton.tsx": [
|
||||
"/build/assets/DangerButton-BAZynYAq.js"
|
||||
],
|
||||
"resources/js/Components/DialogModal.tsx": [
|
||||
"/build/assets/DialogModal-D0pyMzH2.js"
|
||||
],
|
||||
"resources/js/Components/Dropdown.tsx": [
|
||||
"/build/assets/AppLayout-DitNPgwT.js"
|
||||
],
|
||||
"resources/js/Components/DropdownLink.tsx": [
|
||||
"/build/assets/AppLayout-DitNPgwT.js"
|
||||
],
|
||||
"resources/js/Components/FormSection.tsx": [
|
||||
"/build/assets/FormSection-DI6t3wFC.js"
|
||||
],
|
||||
"resources/js/Components/InputError.tsx": [
|
||||
"/build/assets/TextInput-CMJy2hIv.js"
|
||||
],
|
||||
"resources/js/Components/InputLabel.tsx": [
|
||||
"/build/assets/InputLabel-DhqxoV6M.js"
|
||||
],
|
||||
"resources/js/Components/Modal.tsx": [
|
||||
"/build/assets/Modal-D5yHmTM4.js"
|
||||
],
|
||||
"resources/js/Components/NavLink.tsx": [
|
||||
"/build/assets/AppLayout-DitNPgwT.js"
|
||||
],
|
||||
"resources/js/Components/PrimaryButton.tsx": [
|
||||
"/build/assets/PrimaryButton-C2B8UWiv.js"
|
||||
],
|
||||
"resources/js/Components/ResponsiveNavLink.tsx": [
|
||||
"/build/assets/AppLayout-DitNPgwT.js"
|
||||
],
|
||||
"resources/js/Components/SecondaryButton.tsx": [
|
||||
"/build/assets/SecondaryButton-G68tKuYQ.js"
|
||||
],
|
||||
"resources/js/Components/SectionBorder.tsx": [
|
||||
"/build/assets/SectionBorder-Dh4nHf2e.js"
|
||||
],
|
||||
"resources/js/Components/SectionTitle.tsx": [
|
||||
"/build/assets/SectionTitle-DnuUNpyS.js"
|
||||
],
|
||||
"resources/js/Components/TextInput.tsx": [
|
||||
"/build/assets/TextInput-CMJy2hIv.js"
|
||||
],
|
||||
"resources/js/Components/Welcome.tsx": [
|
||||
"/build/assets/Dashboard-CkDsUhZk.js"
|
||||
],
|
||||
"resources/js/Hooks/useRoute.ts": [],
|
||||
"resources/js/Hooks/useTypedPage.ts": [
|
||||
"/build/assets/useTypedPage-Do3SqtsL.js"
|
||||
],
|
||||
"resources/js/Layouts/AppLayout.tsx": [
|
||||
"/build/assets/AppLayout-DitNPgwT.js"
|
||||
],
|
||||
"resources/js/Pages/API/Index.tsx": [
|
||||
"/build/assets/Index-CwIeEkIw.js"
|
||||
],
|
||||
"resources/js/Pages/API/Partials/APITokenManager.tsx": [
|
||||
"/build/assets/APITokenManager-iZxUx3eK.js"
|
||||
],
|
||||
"resources/js/Pages/Auth/ConfirmPassword.tsx": [
|
||||
"/build/assets/ConfirmPassword-ju6YtACP.js"
|
||||
],
|
||||
"resources/js/Pages/Auth/ForgotPassword.tsx": [
|
||||
"/build/assets/ForgotPassword-BhYnh0qc.js"
|
||||
],
|
||||
"resources/js/Pages/Auth/Login.tsx": [
|
||||
"/build/assets/Login-P_qEmbLO.js"
|
||||
],
|
||||
"resources/js/Pages/Auth/Register.tsx": [
|
||||
"/build/assets/Register-anJ95HWS.js"
|
||||
],
|
||||
"resources/js/Pages/Auth/ResetPassword.tsx": [
|
||||
"/build/assets/ResetPassword-DAOSACWm.js"
|
||||
],
|
||||
"resources/js/Pages/Auth/TwoFactorChallenge.tsx": [
|
||||
"/build/assets/TwoFactorChallenge-Tkr6HCx-.js"
|
||||
],
|
||||
"resources/js/Pages/Auth/VerifyEmail.tsx": [
|
||||
"/build/assets/VerifyEmail--hB-n-6S.js"
|
||||
],
|
||||
"resources/js/Pages/Dashboard.tsx": [
|
||||
"/build/assets/Dashboard-CkDsUhZk.js"
|
||||
],
|
||||
"resources/js/Pages/PrivacyPolicy.tsx": [
|
||||
"/build/assets/PrivacyPolicy-DYEevN3b.js"
|
||||
],
|
||||
"resources/js/Pages/Profile/Partials/DeleteUserForm.tsx": [
|
||||
"/build/assets/DeleteUserForm-Ptw0GKXr.js"
|
||||
],
|
||||
"resources/js/Pages/Profile/Partials/LogoutOtherBrowserSessionsForm.tsx": [
|
||||
"/build/assets/LogoutOtherBrowserSessionsForm-Bd8DyQdZ.js"
|
||||
],
|
||||
"resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.tsx": [
|
||||
"/build/assets/TwoFactorAuthenticationForm-BLalZpWn.js"
|
||||
],
|
||||
"resources/js/Pages/Profile/Partials/UpdatePasswordForm.tsx": [
|
||||
"/build/assets/UpdatePasswordForm-B_100APE.js"
|
||||
],
|
||||
"resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.tsx": [
|
||||
"/build/assets/UpdateProfileInformationForm-g6OOT46r.js"
|
||||
],
|
||||
"resources/js/Pages/Profile/Show.tsx": [
|
||||
"/build/assets/Show-DAwzGQF4.js"
|
||||
],
|
||||
"resources/js/Pages/Teams/Create.tsx": [
|
||||
"/build/assets/Create-Bq48ODsT.js"
|
||||
],
|
||||
"resources/js/Pages/Teams/Partials/CreateTeamForm.tsx": [
|
||||
"/build/assets/CreateTeamForm-CmUI_Zfp.js"
|
||||
],
|
||||
"resources/js/Pages/Teams/Partials/DeleteTeamForm.tsx": [
|
||||
"/build/assets/DeleteTeamForm-CDG-Mx5L.js"
|
||||
],
|
||||
"resources/js/Pages/Teams/Partials/TeamMemberManager.tsx": [
|
||||
"/build/assets/TeamMemberManager-vS8Og7eY.js"
|
||||
],
|
||||
"resources/js/Pages/Teams/Partials/UpdateTeamNameForm.tsx": [
|
||||
"/build/assets/UpdateTeamNameForm-CArH28KV.js"
|
||||
],
|
||||
"resources/js/Pages/Teams/Show.tsx": [
|
||||
"/build/assets/Show-C_aCmrEJ.js"
|
||||
],
|
||||
"resources/js/Pages/TermsOfService.tsx": [
|
||||
"/build/assets/TermsOfService-CfLQttvD.js"
|
||||
],
|
||||
"resources/js/Pages/Welcome.tsx": [
|
||||
"/build/assets/Welcome-Bnby2VG4.js"
|
||||
],
|
||||
"resources/js/app.tsx": [],
|
||||
"resources/js/bootstrap.ts": []
|
||||
}
|
78
composer.json
Normal file
78
composer.json
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "adrum/laravel-jetstream-react-typescript",
|
||||
"type": "project",
|
||||
"description": "A starter kit for the Laravel framework using Jetstream, Inertia.js, React (TS), and HeadlessUI.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"framework"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"inertiajs/inertia-laravel": "^2.0",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/jetstream": "^5.3",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"tightenco/ziggy": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel/pail": "^1.2.2",
|
||||
"laravel/pint": "^1.13",
|
||||
"laravel/sail": "^1.41",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.6",
|
||||
"phpunit/phpunit": "^11.5.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi",
|
||||
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||
"@php artisan migrate --graceful --ansi"
|
||||
],
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true,
|
||||
"php-http/discovery": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
126
config/app.php
Normal file
126
config/app.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value is the name of your application, which will be used when the
|
||||
| framework needs to place the application's name in a notification or
|
||||
| other UI elements where an application name needs to be displayed.
|
||||
|
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Laravel'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Environment
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the "environment" your application is currently
|
||||
| running in. This may determine how you prefer to configure various
|
||||
| services the application utilizes. Set this in your ".env" file.
|
||||
|
|
||||
*/
|
||||
|
||||
'env' => env('APP_ENV', 'production'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Debug Mode
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When your application is in debug mode, detailed error messages with
|
||||
| stack traces will be shown on every error that occurs within your
|
||||
| application. If disabled, a simple generic error page is shown.
|
||||
|
|
||||
*/
|
||||
|
||||
'debug' => (bool) env('APP_DEBUG', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This URL is used by the console to properly generate URLs when using
|
||||
| the Artisan command line tool. You should set this to the root of
|
||||
| the application so that it's available within Artisan commands.
|
||||
|
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default timezone for your application, which
|
||||
| will be used by the PHP date and date-time functions. The timezone
|
||||
| is set to "UTC" by default as it is suitable for most use cases.
|
||||
|
|
||||
*/
|
||||
|
||||
'timezone' => 'UTC',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Locale Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The application locale determines the default locale that will be used
|
||||
| by Laravel's translation / localization methods. This option can be
|
||||
| set to any locale for which you plan to have translation strings.
|
||||
|
|
||||
*/
|
||||
|
||||
'locale' => env('APP_LOCALE', 'en'),
|
||||
|
||||
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
|
||||
|
||||
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This key is utilized by Laravel's encryption services and should be set
|
||||
| to a random, 32 character string to ensure that all encrypted values
|
||||
| are secure. You should do this prior to deploying the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'cipher' => 'AES-256-CBC',
|
||||
|
||||
'key' => env('APP_KEY'),
|
||||
|
||||
'previous_keys' => [
|
||||
...array_filter(
|
||||
explode(',', env('APP_PREVIOUS_KEYS', ''))
|
||||
),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maintenance Mode Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options determine the driver used to determine and
|
||||
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
||||
| allow maintenance mode to be controlled across multiple machines.
|
||||
|
|
||||
| Supported drivers: "file", "cache"
|
||||
|
|
||||
*/
|
||||
|
||||
'maintenance' => [
|
||||
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
|
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||
],
|
||||
|
||||
];
|
115
config/auth.php
Normal file
115
config/auth.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Defaults
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default authentication "guard" and password
|
||||
| reset "broker" for your application. You may change these values
|
||||
| as required, but they're a perfect start for most applications.
|
||||
|
|
||||
*/
|
||||
|
||||
'defaults' => [
|
||||
'guard' => env('AUTH_GUARD', 'web'),
|
||||
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, you may define every authentication guard for your application.
|
||||
| Of course, a great default configuration has been defined for you
|
||||
| which utilizes session storage plus the Eloquent user provider.
|
||||
|
|
||||
| All authentication guards have a user provider, which defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| system used by the application. Typically, Eloquent is utilized.
|
||||
|
|
||||
| Supported: "session"
|
||||
|
|
||||
*/
|
||||
|
||||
'guards' => [
|
||||
'web' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'users',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| User Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| All authentication guards have a user provider, which defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| system used by the application. Typically, Eloquent is utilized.
|
||||
|
|
||||
| If you have multiple user tables or models you may configure multiple
|
||||
| providers to represent the model / table. These providers may then
|
||||
| be assigned to any extra authentication guards you have defined.
|
||||
|
|
||||
| Supported: "database", "eloquent"
|
||||
|
|
||||
*/
|
||||
|
||||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
// 'driver' => 'database',
|
||||
// 'table' => 'users',
|
||||
// ],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Resetting Passwords
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options specify the behavior of Laravel's password
|
||||
| reset functionality, including the table utilized for token storage
|
||||
| and the user provider that is invoked to actually retrieve users.
|
||||
|
|
||||
| The expiry time is the number of minutes that each reset token will be
|
||||
| considered valid. This security feature keeps tokens short-lived so
|
||||
| they have less time to be guessed. You may change this as needed.
|
||||
|
|
||||
| The throttle setting is the number of seconds a user must wait before
|
||||
| generating more password reset tokens. This prevents the user from
|
||||
| quickly generating a very large amount of password reset tokens.
|
||||
|
|
||||
*/
|
||||
|
||||
'passwords' => [
|
||||
'users' => [
|
||||
'provider' => 'users',
|
||||
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
|
||||
'expire' => 60,
|
||||
'throttle' => 60,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Confirmation Timeout
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the amount of seconds before a password confirmation
|
||||
| window expires and users are asked to re-enter their password via the
|
||||
| confirmation screen. By default, the timeout lasts for three hours.
|
||||
|
|
||||
*/
|
||||
|
||||
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
|
||||
|
||||
];
|
108
config/cache.php
Normal file
108
config/cache.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default cache store that will be used by the
|
||||
| framework. This connection is utilized if another isn't explicitly
|
||||
| specified when running a cache operation inside the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('CACHE_STORE', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Stores
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the cache "stores" for your application as
|
||||
| well as their drivers. You may even define multiple stores for the
|
||||
| same cache driver to group types of items stored in your caches.
|
||||
|
|
||||
| Supported drivers: "array", "database", "file", "memcached",
|
||||
| "redis", "dynamodb", "octane", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'stores' => [
|
||||
|
||||
'array' => [
|
||||
'driver' => 'array',
|
||||
'serialize' => false,
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'connection' => env('DB_CACHE_CONNECTION'),
|
||||
'table' => env('DB_CACHE_TABLE', 'cache'),
|
||||
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
|
||||
'lock_table' => env('DB_CACHE_LOCK_TABLE'),
|
||||
],
|
||||
|
||||
'file' => [
|
||||
'driver' => 'file',
|
||||
'path' => storage_path('framework/cache/data'),
|
||||
'lock_path' => storage_path('framework/cache/data'),
|
||||
],
|
||||
|
||||
'memcached' => [
|
||||
'driver' => 'memcached',
|
||||
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
|
||||
'sasl' => [
|
||||
env('MEMCACHED_USERNAME'),
|
||||
env('MEMCACHED_PASSWORD'),
|
||||
],
|
||||
'options' => [
|
||||
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
||||
],
|
||||
'servers' => [
|
||||
[
|
||||
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||
'port' => env('MEMCACHED_PORT', 11211),
|
||||
'weight' => 100,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
|
||||
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
|
||||
],
|
||||
|
||||
'dynamodb' => [
|
||||
'driver' => 'dynamodb',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
|
||||
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||
],
|
||||
|
||||
'octane' => [
|
||||
'driver' => 'octane',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Key Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache
|
||||
| stores, there might be other applications using the same cache. For
|
||||
| that reason, you may prefix every cache key to avoid collisions.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
|
||||
|
||||
];
|
174
config/database.php
Normal file
174
config/database.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Database Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which of the database connections below you wish
|
||||
| to use as your default connection for database operations. This is
|
||||
| the connection which will be utilized unless another connection
|
||||
| is explicitly specified when you execute a query / statement.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('DB_CONNECTION', 'sqlite'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Database Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below are all of the database connections defined for your application.
|
||||
| An example configuration is provided for each database system which
|
||||
| is supported by Laravel. You're free to add / remove connections.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'url' => env('DB_URL'),
|
||||
'database' => env('DB_DATABASE', database_path('database.sqlite')),
|
||||
'prefix' => '',
|
||||
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
|
||||
'busy_timeout' => null,
|
||||
'journal_mode' => null,
|
||||
'synchronous' => null,
|
||||
],
|
||||
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'mariadb' => [
|
||||
'driver' => 'mariadb',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '5432'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'search_path' => 'public',
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
'sqlsrv' => [
|
||||
'driver' => 'sqlsrv',
|
||||
'url' => env('DB_URL'),
|
||||
'host' => env('DB_HOST', 'localhost'),
|
||||
'port' => env('DB_PORT', '1433'),
|
||||
'database' => env('DB_DATABASE', 'laravel'),
|
||||
'username' => env('DB_USERNAME', 'root'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => env('DB_CHARSET', 'utf8'),
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migration Repository Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This table keeps track of all the migrations that have already run for
|
||||
| your application. Using this information, we can determine which of
|
||||
| the migrations on disk haven't actually been run on the database.
|
||||
|
|
||||
*/
|
||||
|
||||
'migrations' => [
|
||||
'table' => 'migrations',
|
||||
'update_date_on_publish' => true,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redis Databases
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Redis is an open source, fast, and advanced key-value store that also
|
||||
| provides a richer body of commands than a typical key-value system
|
||||
| such as Memcached. You may define your connection settings here.
|
||||
|
|
||||
*/
|
||||
|
||||
'redis' => [
|
||||
|
||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||
'persistent' => env('REDIS_PERSISTENT', false),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
],
|
||||
|
||||
'cache' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_CACHE_DB', '1'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
80
config/filesystems.php
Normal file
80
config/filesystems.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Filesystem Disk
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default filesystem disk that should be used
|
||||
| by the framework. The "local" disk, as well as a variety of cloud
|
||||
| based disks are available to your application for file storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('FILESYSTEM_DISK', 'local'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filesystem Disks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below you may configure as many filesystem disks as necessary, and you
|
||||
| may even configure multiple disks for the same driver. Examples for
|
||||
| most supported storage drivers are configured here for reference.
|
||||
|
|
||||
| Supported drivers: "local", "ftp", "sftp", "s3"
|
||||
|
|
||||
*/
|
||||
|
||||
'disks' => [
|
||||
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/private'),
|
||||
'serve' => true,
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
'public' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'visibility' => 'public',
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION'),
|
||||
'bucket' => env('AWS_BUCKET'),
|
||||
'url' => env('AWS_URL'),
|
||||
'endpoint' => env('AWS_ENDPOINT'),
|
||||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Symbolic Links
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the symbolic links that will be created when the
|
||||
| `storage:link` Artisan command is executed. The array keys should be
|
||||
| the locations of the links and the values should be their targets.
|
||||
|
|
||||
*/
|
||||
|
||||
'links' => [
|
||||
public_path('storage') => storage_path('app/public'),
|
||||
],
|
||||
|
||||
];
|
159
config/fortify.php
Normal file
159
config/fortify.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Fortify\Features;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fortify Guard
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which authentication guard Fortify will use while
|
||||
| authenticating users. This value should correspond with one of your
|
||||
| guards that is already present in your "auth" configuration file.
|
||||
|
|
||||
*/
|
||||
|
||||
'guard' => 'web',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fortify Password Broker
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which password broker Fortify can use when a user
|
||||
| is resetting their password. This configured value should match one
|
||||
| of your password brokers setup in your "auth" configuration file.
|
||||
|
|
||||
*/
|
||||
|
||||
'passwords' => 'users',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Username / Email
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value defines which model attribute should be considered as your
|
||||
| application's "username" field. Typically, this might be the email
|
||||
| address of the users but you are free to change this value here.
|
||||
|
|
||||
| Out of the box, Fortify expects forgot password and reset password
|
||||
| requests to have a field named 'email'. If the application uses
|
||||
| another name for the field you may define it below as needed.
|
||||
|
|
||||
*/
|
||||
|
||||
'username' => 'email',
|
||||
|
||||
'email' => 'email',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Lowercase Usernames
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value defines whether usernames should be lowercased before saving
|
||||
| them in the database, as some database system string fields are case
|
||||
| sensitive. You may disable this for your application if necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'lowercase_usernames' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Home Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the path where users will get redirected during
|
||||
| authentication or password reset when the operations are successful
|
||||
| and the user is authenticated. You are free to change this value.
|
||||
|
|
||||
*/
|
||||
|
||||
'home' => '/dashboard',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fortify Routes Prefix / Subdomain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which prefix Fortify will assign to all the routes
|
||||
| that it registers with the application. If necessary, you may change
|
||||
| subdomain under which all of the Fortify routes will be available.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => '',
|
||||
|
||||
'domain' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fortify Routes Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which middleware Fortify will assign to the routes
|
||||
| that it registers with the application. If necessary, you may change
|
||||
| these middleware but typically this provided default is preferred.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => ['web'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Rate Limiting
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, Fortify will throttle logins to five requests per minute for
|
||||
| every email and IP address combination. However, if you would like to
|
||||
| specify a custom rate limiter to call then you may specify it here.
|
||||
|
|
||||
*/
|
||||
|
||||
'limiters' => [
|
||||
'login' => 'login',
|
||||
'two-factor' => 'two-factor',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register View Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify if the routes returning views should be disabled as
|
||||
| you may not need them when building your own application. This may be
|
||||
| especially true if you're writing a custom single-page application.
|
||||
|
|
||||
*/
|
||||
|
||||
'views' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Features
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Some of the Fortify features are optional. You may disable the features
|
||||
| by removing them from this array. You're free to only remove some of
|
||||
| these features or you can even remove all of these if you need to.
|
||||
|
|
||||
*/
|
||||
|
||||
'features' => [
|
||||
Features::registration(),
|
||||
Features::resetPasswords(),
|
||||
// Features::emailVerification(),
|
||||
Features::updateProfileInformation(),
|
||||
Features::updatePasswords(),
|
||||
Features::twoFactorAuthentication([
|
||||
'confirm' => true,
|
||||
'confirmPassword' => true,
|
||||
// 'window' => 0,
|
||||
]),
|
||||
],
|
||||
|
||||
];
|
81
config/jetstream.php
Normal file
81
config/jetstream.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Jetstream\Features;
|
||||
use Laravel\Jetstream\Http\Middleware\AuthenticateSession;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Jetstream Stack
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration value informs Jetstream which "stack" you will be
|
||||
| using for your application. In general, this value is set for you
|
||||
| during installation and will not need to be changed after that.
|
||||
|
|
||||
*/
|
||||
|
||||
'stack' => 'inertia',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Jetstream Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which middleware Jetstream will assign to the routes
|
||||
| that it registers with the application. When necessary, you may modify
|
||||
| these middleware; however, this default value is usually sufficient.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => ['web'],
|
||||
|
||||
'auth_session' => AuthenticateSession::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Jetstream Guard
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the authentication guard Jetstream will use while
|
||||
| authenticating users. This value should correspond with one of your
|
||||
| guards that is already present in your "auth" configuration file.
|
||||
|
|
||||
*/
|
||||
|
||||
'guard' => 'sanctum',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Features
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Some of Jetstream's features are optional. You may disable the features
|
||||
| by removing them from this array. You're free to only remove some of
|
||||
| these features or you can even remove all of these if you need to.
|
||||
|
|
||||
*/
|
||||
|
||||
'features' => [
|
||||
// Features::termsAndPrivacyPolicy(),
|
||||
// Features::profilePhotos(),
|
||||
// Features::api(),
|
||||
Features::teams(['invitations' => true]),
|
||||
Features::accountDeletion(),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Profile Photo Disk
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration value determines the default disk that will be used
|
||||
| when storing profile photos for your application's users. Typically
|
||||
| this will be the "public" disk but you may adjust this if needed.
|
||||
|
|
||||
*/
|
||||
|
||||
'profile_photo_disk' => 'public',
|
||||
|
||||
];
|
132
config/logging.php
Normal file
132
config/logging.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
use Monolog\Processor\PsrLogMessageProcessor;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default log channel that is utilized to write
|
||||
| messages to your logs. The value provided here should match one of
|
||||
| the channels present in the list of "channels" configured below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LOG_CHANNEL', 'stack'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Deprecations Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the log channel that should be used to log warnings
|
||||
| regarding deprecated PHP and library features. This allows you to get
|
||||
| your application ready for upcoming major versions of dependencies.
|
||||
|
|
||||
*/
|
||||
|
||||
'deprecations' => [
|
||||
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
|
||||
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log channels for your application. Laravel
|
||||
| utilizes the Monolog PHP logging library, which includes a variety
|
||||
| of powerful log handlers and formatters that you're free to use.
|
||||
|
|
||||
| Available drivers: "single", "daily", "slack", "syslog",
|
||||
| "errorlog", "monolog", "custom", "stack"
|
||||
|
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => explode(',', env('LOG_STACK', 'single')),
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'days' => env('LOG_DAILY_DAYS', 14),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
|
||||
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
|
||||
'level' => env('LOG_LEVEL', 'critical'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_URL'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
'processors' => [PsrLogMessageProcessor::class],
|
||||
],
|
||||
|
||||
'stderr' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'handler' => StreamHandler::class,
|
||||
'handler_with' => [
|
||||
'stream' => 'php://stderr',
|
||||
],
|
||||
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||
'processors' => [PsrLogMessageProcessor::class],
|
||||
],
|
||||
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'replace_placeholders' => true,
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => NullHandler::class,
|
||||
],
|
||||
|
||||
'emergency' => [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
116
config/mail.php
Normal file
116
config/mail.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mailer
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default mailer that is used to send all email
|
||||
| messages unless another mailer is explicitly specified when sending
|
||||
| the message. All additional mailers can be configured within the
|
||||
| "mailers" array. Examples of each type of mailer are provided.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('MAIL_MAILER', 'log'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mailer Configurations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure all of the mailers used by your application plus
|
||||
| their respective settings. Several examples have been configured for
|
||||
| you and you are free to add your own as your application requires.
|
||||
|
|
||||
| Laravel supports a variety of mail "transport" drivers that can be used
|
||||
| when delivering an email. You may specify which one you're using for
|
||||
| your mailers below. You may also add additional mailers if needed.
|
||||
|
|
||||
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
|
||||
| "postmark", "resend", "log", "array",
|
||||
| "failover", "roundrobin"
|
||||
|
|
||||
*/
|
||||
|
||||
'mailers' => [
|
||||
|
||||
'smtp' => [
|
||||
'transport' => 'smtp',
|
||||
'scheme' => env('MAIL_SCHEME'),
|
||||
'url' => env('MAIL_URL'),
|
||||
'host' => env('MAIL_HOST', '127.0.0.1'),
|
||||
'port' => env('MAIL_PORT', 2525),
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'timeout' => null,
|
||||
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'transport' => 'ses',
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'transport' => 'postmark',
|
||||
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
|
||||
// 'client' => [
|
||||
// 'timeout' => 5,
|
||||
// ],
|
||||
],
|
||||
|
||||
'resend' => [
|
||||
'transport' => 'resend',
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
'transport' => 'sendmail',
|
||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'transport' => 'log',
|
||||
'channel' => env('MAIL_LOG_CHANNEL'),
|
||||
],
|
||||
|
||||
'array' => [
|
||||
'transport' => 'array',
|
||||
],
|
||||
|
||||
'failover' => [
|
||||
'transport' => 'failover',
|
||||
'mailers' => [
|
||||
'smtp',
|
||||
'log',
|
||||
],
|
||||
],
|
||||
|
||||
'roundrobin' => [
|
||||
'transport' => 'roundrobin',
|
||||
'mailers' => [
|
||||
'ses',
|
||||
'postmark',
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global "From" Address
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You may wish for all emails sent by your application to be sent from
|
||||
| the same address. Here you may specify a name and address that is
|
||||
| used globally for all emails that are sent by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'from' => [
|
||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
||||
'name' => env('MAIL_FROM_NAME', 'Example'),
|
||||
],
|
||||
|
||||
];
|
112
config/queue.php
Normal file
112
config/queue.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Queue Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Laravel's queue supports a variety of backends via a single, unified
|
||||
| API, giving you convenient access to each backend using identical
|
||||
| syntax for each. The default queue connection is defined below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('QUEUE_CONNECTION', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the connection options for every queue backend
|
||||
| used by your application. An example configuration is provided for
|
||||
| each backend supported by Laravel. You're also free to add more.
|
||||
|
|
||||
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sync' => [
|
||||
'driver' => 'sync',
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'connection' => env('DB_QUEUE_CONNECTION'),
|
||||
'table' => env('DB_QUEUE_TABLE', 'jobs'),
|
||||
'queue' => env('DB_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'beanstalkd' => [
|
||||
'driver' => 'beanstalkd',
|
||||
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
|
||||
'queue' => env('BEANSTALKD_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => 0,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'sqs' => [
|
||||
'driver' => 'sqs',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
|
||||
'queue' => env('SQS_QUEUE', 'default'),
|
||||
'suffix' => env('SQS_SUFFIX'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
|
||||
'queue' => env('REDIS_QUEUE', 'default'),
|
||||
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
|
||||
'block_for' => null,
|
||||
'after_commit' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Job Batching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following options configure the database and table that store job
|
||||
| batching information. These options can be updated to any database
|
||||
| connection and table which has been defined by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'batching' => [
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'job_batches',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Failed Queue Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These options configure the behavior of failed queue job logging so you
|
||||
| can control how and where failed jobs are stored. Laravel ships with
|
||||
| support for storing failed jobs in a simple file or in a database.
|
||||
|
|
||||
| Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => [
|
||||
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
|
||||
'database' => env('DB_CONNECTION', 'sqlite'),
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
|
||||
];
|
83
config/sanctum.php
Normal file
83
config/sanctum.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Stateful Domains
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Requests from the following domains / hosts will receive stateful API
|
||||
| authentication cookies. Typically, these should include your local
|
||||
| and production domains which access your API via a frontend SPA.
|
||||
|
|
||||
*/
|
||||
|
||||
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
|
||||
'%s%s',
|
||||
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
|
||||
Sanctum::currentApplicationUrlWithPort()
|
||||
))),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sanctum Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This array contains the authentication guards that will be checked when
|
||||
| Sanctum is trying to authenticate a request. If none of these guards
|
||||
| are able to authenticate the request, Sanctum will use the bearer
|
||||
| token that's present on an incoming request for authentication.
|
||||
|
|
||||
*/
|
||||
|
||||
'guard' => ['web'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expiration Minutes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value controls the number of minutes until an issued token will be
|
||||
| considered expired. This will override any values set in the token's
|
||||
| "expires_at" attribute, but first-party sessions are not affected.
|
||||
|
|
||||
*/
|
||||
|
||||
'expiration' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Token Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Sanctum can prefix new tokens in order to take advantage of numerous
|
||||
| security scanning initiatives maintained by open source platforms
|
||||
| that notify developers if they commit tokens into repositories.
|
||||
|
|
||||
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
||||
|
|
||||
*/
|
||||
|
||||
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sanctum Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When authenticating your first-party SPA with Sanctum you may need to
|
||||
| customize some of the middleware Sanctum uses while processing the
|
||||
| request. You may change the middleware listed below as required.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
|
||||
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
|
||||
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
|
||||
],
|
||||
|
||||
];
|
38
config/services.php
Normal file
38
config/services.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Third Party Services
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is for storing the credentials for third party services such
|
||||
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||||
| location for this type of information, allowing packages to have
|
||||
| a conventional file to locate the various service credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'postmark' => [
|
||||
'token' => env('POSTMARK_TOKEN'),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'resend' => [
|
||||
'key' => env('RESEND_KEY'),
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'notifications' => [
|
||||
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
|
||||
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
217
config/session.php
Normal file
217
config/session.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Session Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines the default session driver that is utilized for
|
||||
| incoming requests. Laravel supports a variety of storage options to
|
||||
| persist session data. Database storage is a great default choice.
|
||||
|
|
||||
| Supported: "file", "cookie", "database", "apc",
|
||||
| "memcached", "redis", "dynamodb", "array"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('SESSION_DRIVER', 'database'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Lifetime
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the number of minutes that you wish the session
|
||||
| to be allowed to remain idle before it expires. If you want them
|
||||
| to expire immediately when the browser is closed then you may
|
||||
| indicate that via the expire_on_close configuration option.
|
||||
|
|
||||
*/
|
||||
|
||||
'lifetime' => (int) env('SESSION_LIFETIME', 120),
|
||||
|
||||
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to easily specify that all of your session data
|
||||
| should be encrypted before it's stored. All encryption is performed
|
||||
| automatically by Laravel and you may use the session like normal.
|
||||
|
|
||||
*/
|
||||
|
||||
'encrypt' => env('SESSION_ENCRYPT', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session File Location
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing the "file" session driver, the session files are placed
|
||||
| on disk. The default storage location is defined here; however, you
|
||||
| are free to provide another location where they should be stored.
|
||||
|
|
||||
*/
|
||||
|
||||
'files' => storage_path('framework/sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" or "redis" session drivers, you may specify a
|
||||
| connection that should be used to manage these sessions. This should
|
||||
| correspond to a connection in your database configuration options.
|
||||
|
|
||||
*/
|
||||
|
||||
'connection' => env('SESSION_CONNECTION'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" session driver, you may specify the table to
|
||||
| be used to store sessions. Of course, a sensible default is defined
|
||||
| for you; however, you're welcome to change this to another table.
|
||||
|
|
||||
*/
|
||||
|
||||
'table' => env('SESSION_TABLE', 'sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using one of the framework's cache driven session backends, you may
|
||||
| define the cache store which should be used to store the session data
|
||||
| between requests. This must match one of your defined cache stores.
|
||||
|
|
||||
| Affects: "apc", "dynamodb", "memcached", "redis"
|
||||
|
|
||||
*/
|
||||
|
||||
'store' => env('SESSION_STORE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Sweeping Lottery
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Some session drivers must manually sweep their storage location to get
|
||||
| rid of old sessions from storage. Here are the chances that it will
|
||||
| happen on a given request. By default, the odds are 2 out of 100.
|
||||
|
|
||||
*/
|
||||
|
||||
'lottery' => [2, 100],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may change the name of the session cookie that is created by
|
||||
| the framework. Typically, you should not need to change this value
|
||||
| since doing so does not grant a meaningful security improvement.
|
||||
|
|
||||
*/
|
||||
|
||||
'cookie' => env(
|
||||
'SESSION_COOKIE',
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||
),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The session cookie path determines the path for which the cookie will
|
||||
| be regarded as available. Typically, this will be the root path of
|
||||
| your application, but you're free to change this when necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('SESSION_PATH', '/'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the domain and subdomains the session cookie is
|
||||
| available to. By default, the cookie will be available to the root
|
||||
| domain and all subdomains. Typically, this shouldn't be changed.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('SESSION_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTPS Only Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By setting this option to true, session cookies will only be sent back
|
||||
| to the server if the browser has a HTTPS connection. This will keep
|
||||
| the cookie from being sent to you when it can't be done securely.
|
||||
|
|
||||
*/
|
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTP Access Only
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will prevent JavaScript from accessing the
|
||||
| value of the cookie and the cookie will only be accessible through
|
||||
| the HTTP protocol. It's unlikely you should disable this option.
|
||||
|
|
||||
*/
|
||||
|
||||
'http_only' => env('SESSION_HTTP_ONLY', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Same-Site Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines how your cookies behave when cross-site requests
|
||||
| take place, and can be used to mitigate CSRF attacks. By default, we
|
||||
| will set this value to "lax" to permit secure cross-site requests.
|
||||
|
|
||||
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
||||
|
|
||||
| Supported: "lax", "strict", "none", null
|
||||
|
|
||||
*/
|
||||
|
||||
'same_site' => env('SESSION_SAME_SITE', 'lax'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Partitioned Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will tie the cookie to the top-level site for
|
||||
| a cross-site context. Partitioned cookies are accepted by the browser
|
||||
| when flagged "secure" and the Same-Site attribute is set to "none".
|
||||
|
|
||||
*/
|
||||
|
||||
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
|
||||
|
||||
];
|
1
database/.gitignore
vendored
Normal file
1
database/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.sqlite*
|
26
database/factories/TeamFactory.php
Normal file
26
database/factories/TeamFactory.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Team>
|
||||
*/
|
||||
class TeamFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->unique()->company(),
|
||||
'user_id' => User::factory(),
|
||||
'personal_team' => true,
|
||||
];
|
||||
}
|
||||
}
|
72
database/factories/UserFactory.php
Normal file
72
database/factories/UserFactory.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Jetstream\Features;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'two_factor_secret' => null,
|
||||
'two_factor_recovery_codes' => null,
|
||||
'remember_token' => Str::random(10),
|
||||
'profile_photo_path' => null,
|
||||
'current_team_id' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user should have a personal team.
|
||||
*/
|
||||
public function withPersonalTeam(?callable $callback = null): static
|
||||
{
|
||||
if (! Features::hasTeamFeatures()) {
|
||||
return $this->state([]);
|
||||
}
|
||||
|
||||
return $this->has(
|
||||
Team::factory()
|
||||
->state(fn (array $attributes, User $user) => [
|
||||
'name' => $user->name.'\'s Team',
|
||||
'user_id' => $user->id,
|
||||
'personal_team' => true,
|
||||
])
|
||||
->when(is_callable($callback), $callback),
|
||||
'ownedTeams'
|
||||
);
|
||||
}
|
||||
}
|
51
database/migrations/0001_01_01_000000_create_users_table.php
Normal file
51
database/migrations/0001_01_01_000000_create_users_table.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?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('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->foreignId('current_team_id')->nullable();
|
||||
$table->string('profile_photo_path', 2048)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->longText('payload');
|
||||
$table->integer('last_activity')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?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('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user