removed old boilerplate, implemented S3 uploading.
This commit is contained in:
parent
d40584de14
commit
c2ec2af33c
29 changed files with 615 additions and 395 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
# laravel-vue-file-share
|
# laravel-vue-file-share
|
||||||
|
|
||||||
Dropbox/Google Drive-esque file sharing application implemented in Laravel, PHP, Inertia, Vue, Headless-UI and Tailwind CSS. Uses Mitt for firing events and passing data.
|
Dropbox/Google Drive-esque file sharing application implemented in Laravel, PHP, Inertia, Vue, Headless-UI and Tailwind CSS. Uses Mitt for firing events and passing data.
|
||||||
|
Uses S3 for storing and retrieving files.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ use App\Http\Requests\SharedFiles;
|
||||||
|
|
||||||
use App\Http\Resources\FileResource;
|
use App\Http\Resources\FileResource;
|
||||||
|
|
||||||
|
use App\Jobs\UploadToS3;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
@ -827,12 +829,16 @@ class FileController extends Controller
|
||||||
// loop over files, make and upload each one
|
// loop over files, make and upload each one
|
||||||
foreach ($files as $userFile) {
|
foreach ($files as $userFile) {
|
||||||
$file = new File();
|
$file = new File();
|
||||||
$file->stored_at = $userFile->store('/files/'.Auth::id());
|
$file->stored_at = $userFile->store('/files/' . Auth::id(), 'local');
|
||||||
$file->is_folder = false;
|
$file->is_folder = false;
|
||||||
$file->name = $userFile->getClientOriginalName();
|
$file->name = $userFile->getClientOriginalName();
|
||||||
$file->mimetype = $userFile->getMimeType();
|
$file->mimetype = $userFile->getMimeType();
|
||||||
$file->size = $userFile->getSize();
|
$file->size = $userFile->getSize();
|
||||||
|
$file->s3 = 0; // file has NOT been uploaded to s3
|
||||||
$parent->appendNode($file);
|
$parent->appendNode($file);
|
||||||
|
|
||||||
|
// upload file to S3
|
||||||
|
UploadToS3::dispatch($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
61
app/Jobs/UploadToS3.php
Normal file
61
app/Jobs/UploadToS3.php
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use App\Models\File;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class UploadToS3 implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct(protected File $file)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
// get file from constructor
|
||||||
|
$file = $this->file;
|
||||||
|
|
||||||
|
// if the file has not been uploaded to S3
|
||||||
|
if (!$file->s3) {
|
||||||
|
$localPath = Storage::disk('local')->path($file->stored_at);
|
||||||
|
Log::debug("File at " . $localPath . " being uploaded to S3");
|
||||||
|
|
||||||
|
// upload file to S3
|
||||||
|
try {
|
||||||
|
// upload to S3 with the "stored_at" path. get file from 'local' disk at the "stored_at" path.
|
||||||
|
$stored = Storage::put($file->stored_at, Storage::disk('local')->get($file->stored_at));
|
||||||
|
// if storing is successful, change DB and output log message
|
||||||
|
if ($stored) {
|
||||||
|
Log::debug("File uploaded to S3");
|
||||||
|
$file->s3 = 1;
|
||||||
|
$file->save();
|
||||||
|
}
|
||||||
|
// else file storing on S3 was not successful.
|
||||||
|
else {
|
||||||
|
Log::error("File upload to S3 was unsuccessful");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (\Exception $exception) {
|
||||||
|
Log::error($exception->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -88,7 +88,7 @@ class File extends Model
|
||||||
else $model->path = '';
|
else $model->path = '';
|
||||||
|
|
||||||
// append current file or folder name to path name
|
// append current file or folder name to path name
|
||||||
$model->path = $model->path . Str::slug($model->name);
|
$model->path = $model->path . $model->name;
|
||||||
});
|
});
|
||||||
|
|
||||||
// define delete function
|
// define delete function
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
"laravel/framework": "^10.10",
|
"laravel/framework": "^10.10",
|
||||||
"laravel/sanctum": "^3.2",
|
"laravel/sanctum": "^3.2",
|
||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
|
"league/flysystem-aws-s3-v3": "^3.0",
|
||||||
|
"psr/http-message": "^1.0",
|
||||||
"tightenco/ziggy": "^1.0"
|
"tightenco/ziggy": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|
|
||||||
327
composer.lock
generated
327
composer.lock
generated
|
|
@ -4,8 +4,157 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "6befa31489c527cc8174c05d5165886a",
|
"content-hash": "edbfbe62b4cb8f6882359a6168f6d6e6",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "aws/aws-crt-php",
|
||||||
|
"version": "v1.2.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/awslabs/aws-crt-php.git",
|
||||||
|
"reference": "2f1dc7b7eda080498be96a4a6d683a41583030e9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/2f1dc7b7eda080498be96a4a6d683a41583030e9",
|
||||||
|
"reference": "2f1dc7b7eda080498be96a4a6d683a41583030e9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35||^5.6.3||^9.5",
|
||||||
|
"yoast/phpunit-polyfills": "^1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "AWS SDK Common Runtime Team",
|
||||||
|
"email": "aws-sdk-common-runtime@amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS Common Runtime for PHP",
|
||||||
|
"homepage": "https://github.com/awslabs/aws-crt-php",
|
||||||
|
"keywords": [
|
||||||
|
"amazon",
|
||||||
|
"aws",
|
||||||
|
"crt",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/awslabs/aws-crt-php/issues",
|
||||||
|
"source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.2"
|
||||||
|
},
|
||||||
|
"time": "2023-07-20T16:49:55+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aws/aws-sdk-php",
|
||||||
|
"version": "3.283.7",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
|
"reference": "54cbb4253c6add698ec429bfb6ff2168c2fd7092"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/54cbb4253c6add698ec429bfb6ff2168c2fd7092",
|
||||||
|
"reference": "54cbb4253c6add698ec429bfb6ff2168c2fd7092",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"aws/aws-crt-php": "^1.0.4",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"guzzlehttp/guzzle": "^6.5.8 || ^7.4.5",
|
||||||
|
"guzzlehttp/promises": "^1.4.0 || ^2.0",
|
||||||
|
"guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
|
||||||
|
"mtdowling/jmespath.php": "^2.6",
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"psr/http-message": "^1.0 || ^2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"andrewsville/php-token-reflection": "^1.4",
|
||||||
|
"aws/aws-php-sns-message-validator": "~1.0",
|
||||||
|
"behat/behat": "~3.0",
|
||||||
|
"composer/composer": "^1.10.22",
|
||||||
|
"dms/phpunit-arraysubset-asserts": "^0.4.0",
|
||||||
|
"doctrine/cache": "~1.4",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-pcntl": "*",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"nette/neon": "^2.3",
|
||||||
|
"paragonie/random_compat": ">= 2",
|
||||||
|
"phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5",
|
||||||
|
"psr/cache": "^1.0",
|
||||||
|
"psr/simple-cache": "^1.0",
|
||||||
|
"sebastian/comparator": "^1.2.3 || ^4.0",
|
||||||
|
"yoast/phpunit-polyfills": "^1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
|
||||||
|
"doctrine/cache": "To use the DoctrineCacheAdapter",
|
||||||
|
"ext-curl": "To send requests using cURL",
|
||||||
|
"ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
|
||||||
|
"ext-sockets": "To use client-side monitoring"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Aws\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Amazon Web Services",
|
||||||
|
"homepage": "http://aws.amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
|
||||||
|
"homepage": "http://aws.amazon.com/sdkforphp",
|
||||||
|
"keywords": [
|
||||||
|
"amazon",
|
||||||
|
"aws",
|
||||||
|
"cloud",
|
||||||
|
"dynamodb",
|
||||||
|
"ec2",
|
||||||
|
"glacier",
|
||||||
|
"s3",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||||
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.283.7"
|
||||||
|
},
|
||||||
|
"time": "2023-10-18T20:16:37+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
|
|
@ -1815,16 +1964,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/flysystem",
|
"name": "league/flysystem",
|
||||||
"version": "3.16.0",
|
"version": "3.17.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/flysystem.git",
|
"url": "https://github.com/thephpleague/flysystem.git",
|
||||||
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729"
|
"reference": "bd4c9b26849d82364119c68429541f1631fba94b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729",
|
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/bd4c9b26849d82364119c68429541f1631fba94b",
|
||||||
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729",
|
"reference": "bd4c9b26849d82364119c68429541f1631fba94b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -1842,8 +1991,8 @@
|
||||||
"symfony/http-client": "<5.2"
|
"symfony/http-client": "<5.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"async-aws/s3": "^1.5",
|
"async-aws/s3": "^1.5 || ^2.0",
|
||||||
"async-aws/simple-s3": "^1.1",
|
"async-aws/simple-s3": "^1.1 || ^2.0",
|
||||||
"aws/aws-sdk-php": "^3.220.0",
|
"aws/aws-sdk-php": "^3.220.0",
|
||||||
"composer/semver": "^3.0",
|
"composer/semver": "^3.0",
|
||||||
"ext-fileinfo": "*",
|
"ext-fileinfo": "*",
|
||||||
|
|
@ -1889,7 +2038,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/thephpleague/flysystem/issues",
|
"issues": "https://github.com/thephpleague/flysystem/issues",
|
||||||
"source": "https://github.com/thephpleague/flysystem/tree/3.16.0"
|
"source": "https://github.com/thephpleague/flysystem/tree/3.17.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -1901,7 +2050,73 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-07T19:22:17+00:00"
|
"time": "2023-10-05T20:15:05+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "league/flysystem-aws-s3-v3",
|
||||||
|
"version": "3.16.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
|
||||||
|
"reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c",
|
||||||
|
"reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"aws/aws-sdk-php": "^3.220.0",
|
||||||
|
"league/flysystem": "^3.10.0",
|
||||||
|
"league/mime-type-detection": "^1.0.0",
|
||||||
|
"php": "^8.0.2"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"guzzlehttp/guzzle": "<7.0",
|
||||||
|
"guzzlehttp/ringphp": "<1.1.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\Flysystem\\AwsS3V3\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frank de Jonge",
|
||||||
|
"email": "info@frankdejonge.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS S3 filesystem adapter for Flysystem.",
|
||||||
|
"keywords": [
|
||||||
|
"Flysystem",
|
||||||
|
"aws",
|
||||||
|
"file",
|
||||||
|
"files",
|
||||||
|
"filesystem",
|
||||||
|
"s3",
|
||||||
|
"storage"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues",
|
||||||
|
"source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.16.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://ecologi.com/frankdejonge",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/frankdejonge",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-08-30T10:14:57+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/flysystem-local",
|
"name": "league/flysystem-local",
|
||||||
|
|
@ -1965,16 +2180,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "league/mime-type-detection",
|
"name": "league/mime-type-detection",
|
||||||
"version": "1.13.0",
|
"version": "1.14.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/mime-type-detection.git",
|
"url": "https://github.com/thephpleague/mime-type-detection.git",
|
||||||
"reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96"
|
"reference": "b6a5854368533df0295c5761a0253656a2e52d9e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/a6dfb1194a2946fcdc1f38219445234f65b35c96",
|
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/b6a5854368533df0295c5761a0253656a2e52d9e",
|
||||||
"reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96",
|
"reference": "b6a5854368533df0295c5761a0253656a2e52d9e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -2005,7 +2220,7 @@
|
||||||
"description": "Mime-type detection for Flysystem",
|
"description": "Mime-type detection for Flysystem",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
|
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
|
||||||
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.13.0"
|
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.14.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -2017,7 +2232,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-05T12:09:49+00:00"
|
"time": "2023-10-17T14:13:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "monolog/monolog",
|
"name": "monolog/monolog",
|
||||||
|
|
@ -2120,6 +2335,72 @@
|
||||||
],
|
],
|
||||||
"time": "2023-06-21T08:46:11+00:00"
|
"time": "2023-06-21T08:46:11+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "mtdowling/jmespath.php",
|
||||||
|
"version": "2.7.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jmespath/jmespath.php.git",
|
||||||
|
"reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/bbb69a935c2cbb0c03d7f481a238027430f6440b",
|
||||||
|
"reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"symfony/polyfill-mbstring": "^1.17"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/xdebug-handler": "^3.0.3",
|
||||||
|
"phpunit/phpunit": "^8.5.33"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/jp.php"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.7-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/JmesPath.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"JmesPath\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Michael Dowling",
|
||||||
|
"email": "mtdowling@gmail.com",
|
||||||
|
"homepage": "https://github.com/mtdowling"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Declaratively specify how to extract elements from a JSON document",
|
||||||
|
"keywords": [
|
||||||
|
"json",
|
||||||
|
"jsonpath"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/jmespath/jmespath.php/issues",
|
||||||
|
"source": "https://github.com/jmespath/jmespath.php/tree/2.7.0"
|
||||||
|
},
|
||||||
|
"time": "2023-08-25T10:54:48+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "nesbot/carbon",
|
"name": "nesbot/carbon",
|
||||||
"version": "2.71.0",
|
"version": "2.71.0",
|
||||||
|
|
@ -2851,16 +3132,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/http-message",
|
"name": "psr/http-message",
|
||||||
"version": "2.0",
|
"version": "1.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/http-message.git",
|
"url": "https://github.com/php-fig/http-message.git",
|
||||||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
|
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
||||||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -2869,7 +3150,7 @@
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.0.x-dev"
|
"dev-master": "1.1.x-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|
@ -2884,7 +3165,7 @@
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "PHP-FIG",
|
"name": "PHP-FIG",
|
||||||
"homepage": "https://www.php-fig.org/"
|
"homepage": "http://www.php-fig.org/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Common interface for HTTP messages",
|
"description": "Common interface for HTTP messages",
|
||||||
|
|
@ -2898,9 +3179,9 @@
|
||||||
"response"
|
"response"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/php-fig/http-message/tree/2.0"
|
"source": "https://github.com/php-fig/http-message/tree/1.1"
|
||||||
},
|
},
|
||||||
"time": "2023-04-04T09:54:51+00:00"
|
"time": "2023-04-04T09:50:52+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/log",
|
"name": "psr/log",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('files', function (Blueprint $table) {
|
||||||
|
// adds 's3' boolean column to files table to signify if it was uploaded to s3
|
||||||
|
$table->boolean('s3')->default(0)->after('stored_at');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('files', function (Blueprint $table) {
|
||||||
|
// reverse everything done above
|
||||||
|
$table->dropColumn('s3');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,43 +1,43 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
import { computed, onMounted, onUnmounted, ref } from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
align: {
|
align: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'right',
|
default: "right",
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '48',
|
default: "48",
|
||||||
},
|
},
|
||||||
contentClasses: {
|
contentClasses: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'py-1 bg-white dark:bg-gray-700',
|
default: "py-1 bg-gray-700",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const closeOnEscape = (e) => {
|
const closeOnEscape = (e) => {
|
||||||
if (open.value && e.key === 'Escape') {
|
if (open.value && e.key === "Escape") {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => document.addEventListener('keydown', closeOnEscape));
|
onMounted(() => document.addEventListener("keydown", closeOnEscape));
|
||||||
onUnmounted(() => document.removeEventListener('keydown', closeOnEscape));
|
onUnmounted(() => document.removeEventListener("keydown", closeOnEscape));
|
||||||
|
|
||||||
const widthClass = computed(() => {
|
const widthClass = computed(() => {
|
||||||
return {
|
return {
|
||||||
48: 'w-48',
|
48: "w-48",
|
||||||
}[props.width.toString()];
|
}[props.width.toString()];
|
||||||
});
|
});
|
||||||
|
|
||||||
const alignmentClasses = computed(() => {
|
const alignmentClasses = computed(() => {
|
||||||
if (props.align === 'left') {
|
if (props.align === "left") {
|
||||||
return 'origin-top-left left-0';
|
return "origin-top-left left-0";
|
||||||
} else if (props.align === 'right') {
|
} else if (props.align === "right") {
|
||||||
return 'origin-top-right right-0';
|
return "origin-top-right right-0";
|
||||||
} else {
|
} else {
|
||||||
return 'origin-top';
|
return "origin-top";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -51,7 +51,11 @@ const open = ref(false);
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Full Screen Dropdown Overlay -->
|
<!-- Full Screen Dropdown Overlay -->
|
||||||
<div v-show="open" class="fixed inset-0 z-40" @click="open = false"></div>
|
<div
|
||||||
|
v-show="open"
|
||||||
|
class="fixed inset-0 z-40"
|
||||||
|
@click="open = false"
|
||||||
|
></div>
|
||||||
|
|
||||||
<Transition
|
<Transition
|
||||||
enter-active-class="transition ease-out duration-200"
|
enter-active-class="transition ease-out duration-200"
|
||||||
|
|
@ -68,7 +72,10 @@ const open = ref(false);
|
||||||
style="display: none"
|
style="display: none"
|
||||||
@click="open = false"
|
@click="open = false"
|
||||||
>
|
>
|
||||||
<div class="rounded-md ring-1 ring-black ring-opacity-5" :class="contentClasses">
|
<div
|
||||||
|
class="rounded-md ring-1 ring-black ring-opacity-5"
|
||||||
|
:class="contentClasses"
|
||||||
|
>
|
||||||
<slot name="content" />
|
<slot name="content" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Link } from '@inertiajs/vue3';
|
import { Link } from "@inertiajs/vue3";
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
href: {
|
href: {
|
||||||
|
|
@ -12,7 +12,7 @@ defineProps({
|
||||||
<template>
|
<template>
|
||||||
<Link
|
<Link
|
||||||
:href="href"
|
:href="href"
|
||||||
class="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-none focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out"
|
class="block w-full px-4 py-2 text-left text-sm leading-5 text-gray-300 hover:bg-gray-800 focus:outline-none focus:bg-gray-800 transition duration-150 ease-in-out"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ defineProps({
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-show="message">
|
<div v-show="message">
|
||||||
<p class="text-sm text-red-600 dark:text-red-400">
|
<p class="text-sm text-red-400">
|
||||||
{{ message }}
|
{{ message }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ defineProps({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<label class="block font-medium text-gray-700 dark:text-gray-300">
|
<label class="block font-medium text-gray-300">
|
||||||
<span v-if="value">{{ value }}</span>
|
<span v-if="value">{{ value }}</span>
|
||||||
<span v-else><slot /></span>
|
<span v-else><slot /></span>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ const props = defineProps({
|
||||||
|
|
||||||
const classes = computed(() =>
|
const classes = computed(() =>
|
||||||
props.active
|
props.active
|
||||||
? "flex items-center p-3 mb-1 bg-sky-600 rounded font-medium leading-5 text-slate-900 dark:text-gray-100 transition duration-150 ease-in-out hover:ring-sky-500"
|
? "flex items-center p-3 mb-1 bg-sky-600 rounded font-medium leading-5 text-gray-100 transition duration-150 ease-in-out hover:ring-sky-500"
|
||||||
: "flex items-center p-3 mb-1 rounded font-medium leading-5 text-gray-500 border border-zinc-900 dark:text-gray-400 hover:text-gray-700 dark:hover:text-zinc-100 hover:border-sky-500 hover:ring-sky-500 dark:hover:border-sky-600 hover:ring-sky-500 dark:hover:ring-sky-600 transition duration-150 ease-in-out"
|
: "flex items-center p-3 mb-1 rounded font-medium leading-5 text-gray-500 border border-zinc-900 text-gray-400 hover:text-zinc-100 hover:ring-sky-500 hover:border-sky-600 hover:ring-sky-600 transition duration-150 ease-in-out"
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ const props = defineProps({
|
||||||
|
|
||||||
const classes = computed(
|
const classes = computed(
|
||||||
() =>
|
() =>
|
||||||
"border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-gray-600 dark:text-zinc-100 hover:border-sky-500 dark:hover:border-sky-600 hover:ring-sky-500 dark:hover:ring-sky-600 transition duration-150 ease-in-out"
|
"border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-zinc-100 hover:border-sky-600 hover:ring-sky-600 transition duration-150 ease-in-out"
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ defineExpose({ focus: () => input.value.focus() });
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<input
|
<input
|
||||||
class="border-gray-300 dark:border-gray-700 dark:bg-zinc-900 dark:text-gray-300 focus:border-sky-500 dark:focus:border-sky-600 hover:border-sky-500 dark:hover:border-sky-600 rounded-md"
|
class="border-gray-700 bg-zinc-900 text-gray-300 focus:border-sky-600 hover:border-sky-600 rounded-md"
|
||||||
:value="modelValue"
|
:value="modelValue"
|
||||||
@input="$emit('update:modelValue', $event.target.value)"
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
ref="input"
|
ref="input"
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,14 @@ const plusClass = computed(() =>
|
||||||
leave-to-class="transform scale-95 opacity-0"
|
leave-to-class="transform scale-95 opacity-0"
|
||||||
>
|
>
|
||||||
<MenuItems
|
<MenuItems
|
||||||
class="border border-gray-300 dark:border-gray-700 absolute left-0 mt-2 w-56 divide-y divide-gray-700 rounded-md bg-zinc-900 focus:outline-none z-50"
|
class="border border-gray-700 absolute left-0 mt-2 w-56 divide-y divide-gray-700 rounded-md bg-zinc-900 focus:outline-none z-50"
|
||||||
>
|
>
|
||||||
<div class="px-1 py-1">
|
<div class="px-1 py-1">
|
||||||
<MenuItem v-slot="{ active }"
|
<MenuItem v-slot="{ active }"
|
||||||
><a
|
><a
|
||||||
href="#"
|
href="#"
|
||||||
@click.prevent="toggleNewFolderModal(true)"
|
@click.prevent="toggleNewFolderModal(true)"
|
||||||
class="block w-full items-center rounded-md py-2 border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-gray-600 dark:text-zinc-100 hover:border-sky-500 dark:hover:border-sky-600 hover:ring-sky-500 dark:hover:ring-sky-600 transition duration-150 ease-in-out"
|
class="block w-full items-center rounded-md py-2 border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-zinc-100 hover:border-sky-600 hover:ring-sky-600 transition duration-150 ease-in-out"
|
||||||
>New Folder</a
|
>New Folder</a
|
||||||
></MenuItem
|
></MenuItem
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const upload = (event) => {
|
||||||
<MenuItem v-slot="{ active }">
|
<MenuItem v-slot="{ active }">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="block w-full items-center rounded-md py-2 border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-gray-600 dark:text-zinc-100 hover:border-sky-500 dark:hover:border-sky-600 hover:ring-sky-500 dark:hover:ring-sky-600transition duration-150 ease-in-out relative"
|
class="block w-full items-center rounded-md py-2 border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-zinc-100 hover:border-sky-600 hover:ring-sky-600 transition duration-150 ease-in-out relative"
|
||||||
>Upload Files
|
>Upload Files
|
||||||
<input
|
<input
|
||||||
@change="upload"
|
@change="upload"
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const upload = (event) => {
|
||||||
<MenuItem v-slot="{ active }"
|
<MenuItem v-slot="{ active }"
|
||||||
><a
|
><a
|
||||||
href="#"
|
href="#"
|
||||||
class="block w-full items-center rounded-md py-2 border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-gray-600 dark:text-zinc-100 hover:border-sky-500 dark:hover:border-sky-600 hover:ring-sky-500 dark:hover:ring-sky-600transition duration-150 ease-in-out relative"
|
class="block w-full items-center rounded-md py-2 border border-zinc-900 block w-full pl-3 pr-4 py-2 text-left text-base font-medium text-zinc-100 hover:border-sky-600 hover:ring-sky-600 transition duration-150 ease-in-out relative"
|
||||||
>
|
>
|
||||||
Upload Folder
|
Upload Folder
|
||||||
<input
|
<input
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@ import ResponsiveNavLink from "../ResponsiveNavLink.vue";
|
||||||
leave-to-class="transform scale-95 opacity-0"
|
leave-to-class="transform scale-95 opacity-0"
|
||||||
>
|
>
|
||||||
<MenuItems
|
<MenuItems
|
||||||
class="border border-gray-300 dark:border-gray-700 absolute right-0 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-zinc-900 focus:outline-none"
|
class="border border-gray-700 absolute right-0 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-zinc-900 focus:outline-none"
|
||||||
>
|
>
|
||||||
<div class="px-1 py-1">
|
<div class="px-1 py-1">
|
||||||
<MenuItem v-slot="{ active }">
|
<MenuItem v-slot="{ active }">
|
||||||
<ResponsiveNavLink
|
<ResponsiveNavLink
|
||||||
:href="route('profile')"
|
:href="route('profile.edit')"
|
||||||
:class="[
|
:class="[
|
||||||
'group flex w-full items-center rounded-md py-2',
|
'group flex w-full items-center rounded-md py-2',
|
||||||
]"
|
]"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,18 @@
|
||||||
<main
|
<main
|
||||||
class="flex flex-col flex-1 px-4 overflow-hidden items-center justify-center"
|
class="flex flex-col flex-1 px-4 overflow-hidden items-center justify-center"
|
||||||
>
|
>
|
||||||
|
<a
|
||||||
|
:href="route('login')"
|
||||||
|
method="get"
|
||||||
|
as="button"
|
||||||
|
type="button"
|
||||||
|
id="logotext"
|
||||||
|
class="text-5xl flex"
|
||||||
|
>
|
||||||
|
<span>DR</span>
|
||||||
|
<span class="text-3xl" id="lightning">⭍</span>
|
||||||
|
<span>VE</span>
|
||||||
|
</a>
|
||||||
<div
|
<div
|
||||||
class="w-full sm:max-w-md mt-6 px-6 py-4 border-sky-600 border rounded overflow-hidden sm:rounded-lg"
|
class="w-full sm:max-w-md mt-6 px-6 py-4 border-sky-600 border rounded overflow-hidden sm:rounded-lg"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,182 +0,0 @@
|
||||||
<div class="min-h-screen bg-gray-100 dark:bg-gray-900">
|
|
||||||
<nav
|
|
||||||
class="bg-white dark:bg-gray-800 border-b border-gray-100 dark:border-gray-700"
|
|
||||||
>
|
|
||||||
<!-- Primary Navigation Menu -->
|
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<div class="flex justify-between h-16">
|
|
||||||
<div class="flex">
|
|
||||||
<!-- Logo -->
|
|
||||||
<div class="shrink-0 flex items-center">
|
|
||||||
<Link :href="route('dashboard')">
|
|
||||||
<ApplicationLogo
|
|
||||||
class="block h-9 w-auto fill-current text-gray-800 dark:text-gray-200"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Navigation Links -->
|
|
||||||
<div
|
|
||||||
class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex"
|
|
||||||
>
|
|
||||||
<NavLink
|
|
||||||
:href="route('dashboard')"
|
|
||||||
:active="route().current('dashboard')"
|
|
||||||
>
|
|
||||||
Dashboard
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hidden sm:flex sm:items-center sm:ml-6">
|
|
||||||
<!-- Settings Dropdown -->
|
|
||||||
<div class="ml-3 relative">
|
|
||||||
<Dropdown align="right" width="48">
|
|
||||||
<template #trigger>
|
|
||||||
<span class="inline-flex rounded-md">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="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-none transition ease-in-out duration-150"
|
|
||||||
>
|
|
||||||
{{ $page.props.auth.user.name }}
|
|
||||||
|
|
||||||
<svg
|
|
||||||
class="ml-2 -mr-0.5 h-4 w-4"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #content>
|
|
||||||
<DropdownLink
|
|
||||||
:href="route('profile.edit')"
|
|
||||||
>
|
|
||||||
Profile
|
|
||||||
</DropdownLink>
|
|
||||||
<DropdownLink
|
|
||||||
:href="route('logout')"
|
|
||||||
method="post"
|
|
||||||
as="button"
|
|
||||||
>
|
|
||||||
Log Out
|
|
||||||
</DropdownLink>
|
|
||||||
</template>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Hamburger -->
|
|
||||||
<div class="-mr-2 flex items-center sm:hidden">
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
showingNavigationDropdown =
|
|
||||||
!showingNavigationDropdown
|
|
||||||
"
|
|
||||||
class="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-none focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-500 dark:focus:text-gray-400 transition duration-150 ease-in-out"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="h-6 w-6"
|
|
||||||
stroke="currentColor"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
:class="{
|
|
||||||
hidden: showingNavigationDropdown,
|
|
||||||
'inline-flex':
|
|
||||||
!showingNavigationDropdown,
|
|
||||||
}"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M4 6h16M4 12h16M4 18h16"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
:class="{
|
|
||||||
hidden: !showingNavigationDropdown,
|
|
||||||
'inline-flex':
|
|
||||||
showingNavigationDropdown,
|
|
||||||
}"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M6 18L18 6M6 6l12 12"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Responsive Navigation Menu -->
|
|
||||||
<div
|
|
||||||
:class="{
|
|
||||||
block: showingNavigationDropdown,
|
|
||||||
hidden: !showingNavigationDropdown,
|
|
||||||
}"
|
|
||||||
class="sm:hidden"
|
|
||||||
>
|
|
||||||
<div class="pt-2 pb-3 space-y-1">
|
|
||||||
<ResponsiveNavLink
|
|
||||||
:href="route('dashboard')"
|
|
||||||
:active="route().current('dashboard')"
|
|
||||||
>
|
|
||||||
Dashboard
|
|
||||||
</ResponsiveNavLink>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Responsive Settings Options -->
|
|
||||||
<div
|
|
||||||
class="pt-4 pb-1 border-t border-gray-200 dark:border-gray-600"
|
|
||||||
>
|
|
||||||
<div class="px-4">
|
|
||||||
<div
|
|
||||||
class="font-medium text-base text-gray-800 dark:text-gray-200"
|
|
||||||
>
|
|
||||||
{{ $page.props.auth.user.name }}
|
|
||||||
</div>
|
|
||||||
<div class="font-medium text-sm text-gray-500">
|
|
||||||
{{ $page.props.auth.user.email }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-3 space-y-1">
|
|
||||||
<ResponsiveNavLink :href="route('profile.edit')">
|
|
||||||
Profile
|
|
||||||
</ResponsiveNavLink>
|
|
||||||
<ResponsiveNavLink
|
|
||||||
:href="route('logout')"
|
|
||||||
method="post"
|
|
||||||
as="button"
|
|
||||||
>
|
|
||||||
Log Out
|
|
||||||
</ResponsiveNavLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- Page Heading -->
|
|
||||||
<header
|
|
||||||
class="bg-white dark:bg-gray-800 shadow"
|
|
||||||
v-if="$slots.header"
|
|
||||||
>
|
|
||||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
|
||||||
<slot name="header" />
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- Page Content -->
|
|
||||||
<main>
|
|
||||||
<slot />
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import GuestLayout from '@/Layouts/GuestLayout.vue';
|
|
||||||
import InputError from '@/Components/InputError.vue';
|
|
||||||
import InputLabel from '@/Components/InputLabel.vue';
|
|
||||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
|
||||||
import TextInput from '@/Components/TextInput.vue';
|
|
||||||
import { Head, useForm } from '@inertiajs/vue3';
|
|
||||||
|
|
||||||
const form = useForm({
|
|
||||||
password: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
const submit = () => {
|
|
||||||
form.post(route('password.confirm'), {
|
|
||||||
onFinish: () => form.reset(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<GuestLayout>
|
|
||||||
<Head title="Confirm Password" />
|
|
||||||
|
|
||||||
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
|
|
||||||
This is a secure area of the application. Please confirm your password before continuing.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form @submit.prevent="submit">
|
|
||||||
<div>
|
|
||||||
<InputLabel for="password" value="Password" />
|
|
||||||
<TextInput
|
|
||||||
id="password"
|
|
||||||
type="password"
|
|
||||||
class="mt-1 block w-full"
|
|
||||||
v-model="form.password"
|
|
||||||
required
|
|
||||||
autocomplete="current-password"
|
|
||||||
autofocus
|
|
||||||
/>
|
|
||||||
<InputError class="mt-2" :message="form.errors.password" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex justify-end mt-4">
|
|
||||||
<PrimaryButton class="ml-4" :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
|
|
||||||
Confirm
|
|
||||||
</PrimaryButton>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</GuestLayout>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import GuestLayout from '@/Layouts/GuestLayout.vue';
|
import GuestLayout from "@/Layouts/GuestLayout.vue";
|
||||||
import InputError from '@/Components/InputError.vue';
|
import InputError from "@/Components/InputError.vue";
|
||||||
import InputLabel from '@/Components/InputLabel.vue';
|
import InputLabel from "@/Components/InputLabel.vue";
|
||||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
import TextInput from "@/Components/TextInput.vue";
|
||||||
import TextInput from '@/Components/TextInput.vue';
|
import { Head, useForm } from "@inertiajs/vue3";
|
||||||
import { Head, useForm } from '@inertiajs/vue3';
|
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
status: {
|
status: {
|
||||||
|
|
@ -13,11 +12,11 @@ defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
email: '',
|
email: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
form.post(route('password.email'));
|
form.post(route("password.email"));
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -25,12 +24,13 @@ const submit = () => {
|
||||||
<GuestLayout>
|
<GuestLayout>
|
||||||
<Head title="Forgot Password" />
|
<Head title="Forgot Password" />
|
||||||
|
|
||||||
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
|
<div class="mb-4 text-sm text-gray-400">
|
||||||
Forgot your password? No problem. Just let us know your email address and we will email you a password reset
|
Forgot your password? No problem. Just let us know your email
|
||||||
link that will allow you to choose a new one.
|
address and we will email you a password reset link that will allow
|
||||||
|
you to choose a new one.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="status" class="mb-4 font-medium text-sm text-green-600 dark:text-green-400">
|
<div v-if="status" class="mb-4 font-medium text-sm text-green-400">
|
||||||
{{ status }}
|
{{ status }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -52,9 +52,13 @@ const submit = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end mt-4">
|
<div class="flex items-center justify-end mt-4">
|
||||||
<PrimaryButton :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
|
<button
|
||||||
|
class="px-6 py-3 border-sky-600 border rounded-lg hover:bg-sky-600"
|
||||||
|
:class="{ 'opacity-25': form.processing }"
|
||||||
|
:disabled="form.processing"
|
||||||
|
>
|
||||||
Email Password Reset Link
|
Email Password Reset Link
|
||||||
</PrimaryButton>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</GuestLayout>
|
</GuestLayout>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ const form = useForm({
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
form.post(route("login"), {
|
form.post(route("login"), {
|
||||||
onFinish: () => form.reset("password"),
|
onFinish: () => form.reset("password"),
|
||||||
onSuccess: () => router.visit(route("/files")),
|
onSuccess: () => router.visit(route("/verify-email")),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -73,18 +73,23 @@ const submit = () => {
|
||||||
<div class="block mt-4">
|
<div class="block mt-4">
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
<Checkbox name="remember" v-model:checked="form.remember" />
|
<Checkbox name="remember" v-model:checked="form.remember" />
|
||||||
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400"
|
<span class="ml-2 text-sm text-gray-400">Remember me</span>
|
||||||
>Remember me</span
|
|
||||||
>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-end mt-4 gap-6">
|
<div class="flex items-center justify-end mt-4 gap-6">
|
||||||
<Link
|
<Link
|
||||||
:href="route('register')"
|
:href="route('register')"
|
||||||
class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md"
|
class="underline text-sm text-gray-400 hover:text-gray-100 rounded-md"
|
||||||
>
|
>
|
||||||
Don't have an account?
|
Register
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
:href="route('password.request')"
|
||||||
|
class="underline text-sm text-gray-400 hover:text-gray-100 rounded-md"
|
||||||
|
>
|
||||||
|
Forgot your password?
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,6 @@ const submit = () => {
|
||||||
form.post(route("register"), {
|
form.post(route("register"), {
|
||||||
onFinish: () => form.reset("password", "password_confirmation"),
|
onFinish: () => form.reset("password", "password_confirmation"),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
alert(
|
|
||||||
"Registration successful. Please check your e-mails for login link."
|
|
||||||
);
|
|
||||||
router.visit(route("/login"));
|
router.visit(route("/login"));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -100,7 +97,7 @@ const submit = () => {
|
||||||
<div class="flex items-center justify-end mt-6 gap-6">
|
<div class="flex items-center justify-end mt-6 gap-6">
|
||||||
<Link
|
<Link
|
||||||
:href="route('login')"
|
:href="route('login')"
|
||||||
class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md"
|
class="underline text-sm text-gray-400 hover:text-gray-100 rounded-md"
|
||||||
>
|
>
|
||||||
Already registered?
|
Already registered?
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { computed } from "vue";
|
||||||
import GuestLayout from '@/Layouts/GuestLayout.vue';
|
import GuestLayout from "@/Layouts/GuestLayout.vue";
|
||||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
import { Head, Link, useForm } from "@inertiajs/vue3";
|
||||||
import { Head, Link, useForm } from '@inertiajs/vue3';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
status: {
|
status: {
|
||||||
|
|
@ -13,36 +12,47 @@ const props = defineProps({
|
||||||
const form = useForm({});
|
const form = useForm({});
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
form.post(route('verification.send'));
|
form.post(route("verification.send"));
|
||||||
};
|
};
|
||||||
|
|
||||||
const verificationLinkSent = computed(() => props.status === 'verification-link-sent');
|
const verificationLinkSent = computed(
|
||||||
|
() => props.status === "verification-link-sent"
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<GuestLayout>
|
<GuestLayout>
|
||||||
<Head title="Email Verification" />
|
<Head title="Email Verification" />
|
||||||
|
|
||||||
<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
|
<div class="mb-4 text-sm text-gray-400">
|
||||||
Thanks for signing up! Before getting started, could you verify your email address by clicking on the link
|
Thanks for signing up! Before getting started, could you verify your
|
||||||
we just emailed to you? If you didn't receive the email, we will gladly send you another.
|
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.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-4 font-medium text-sm text-green-600 dark:text-green-400" v-if="verificationLinkSent">
|
<div
|
||||||
A new verification link has been sent to the email address you provided during registration.
|
class="mb-4 font-medium text-sm text-green-400"
|
||||||
|
v-if="verificationLinkSent"
|
||||||
|
>
|
||||||
|
A new verification link has been sent to the email address you
|
||||||
|
provided during registration.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form @submit.prevent="submit">
|
<form @submit.prevent="submit">
|
||||||
<div class="mt-4 flex items-center justify-between">
|
<div class="mt-4 flex items-center justify-between">
|
||||||
<PrimaryButton :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
|
<button
|
||||||
|
class="px-6 py-3 border-sky-600 border rounded-lg hover:bg-sky-600"
|
||||||
|
:class="{ 'opacity-25': form.processing }"
|
||||||
|
:disabled="form.processing"
|
||||||
|
>
|
||||||
Resend Verification Email
|
Resend Verification Email
|
||||||
</PrimaryButton>
|
</button>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
:href="route('logout')"
|
:href="route('logout')"
|
||||||
method="post"
|
method="post"
|
||||||
as="button"
|
as="button"
|
||||||
class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"
|
class="px-6 py-3 border-red-600 border rounded-lg hover:bg-red-600"
|
||||||
>Log Out</Link
|
>Log Out</Link
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
|
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue";
|
||||||
import DeleteUserForm from './Partials/DeleteUserForm.vue';
|
import DeleteUserForm from "./Partials/DeleteUserForm.vue";
|
||||||
import UpdatePasswordForm from './Partials/UpdatePasswordForm.vue';
|
import UpdatePasswordForm from "./Partials/UpdatePasswordForm.vue";
|
||||||
import UpdateProfileInformationForm from './Partials/UpdateProfileInformationForm.vue';
|
import UpdateProfileInformationForm from "./Partials/UpdateProfileInformationForm.vue";
|
||||||
import { Head } from '@inertiajs/vue3';
|
import { Head } from "@inertiajs/vue3";
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
mustVerifyEmail: {
|
mustVerifyEmail: {
|
||||||
|
|
@ -19,13 +19,9 @@ defineProps({
|
||||||
<Head title="Profile" />
|
<Head title="Profile" />
|
||||||
|
|
||||||
<AuthenticatedLayout>
|
<AuthenticatedLayout>
|
||||||
<template #header>
|
<div class="py-12 overflow-auto">
|
||||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">Profile</h2>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="py-12">
|
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
|
<div class="p-4 sm:p-8 border border-sky-600 rounded-lg">
|
||||||
<UpdateProfileInformationForm
|
<UpdateProfileInformationForm
|
||||||
:must-verify-email="mustVerifyEmail"
|
:must-verify-email="mustVerifyEmail"
|
||||||
:status="status"
|
:status="status"
|
||||||
|
|
@ -33,11 +29,11 @@ defineProps({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
|
<div class="p-4 sm:p-8 border border-sky-600 rounded-lg">
|
||||||
<UpdatePasswordForm class="max-w-xl" />
|
<UpdatePasswordForm class="max-w-xl" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
|
<div class="p-4 sm:p-8 border border-sky-600 rounded-lg">
|
||||||
<DeleteUserForm class="max-w-xl" />
|
<DeleteUserForm class="max-w-xl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import DangerButton from '@/Components/DangerButton.vue';
|
import InputError from "@/Components/InputError.vue";
|
||||||
import InputError from '@/Components/InputError.vue';
|
import InputLabel from "@/Components/InputLabel.vue";
|
||||||
import InputLabel from '@/Components/InputLabel.vue';
|
import Modal from "@/Components/Modal.vue";
|
||||||
import Modal from '@/Components/Modal.vue';
|
import TextInput from "@/Components/TextInput.vue";
|
||||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
import { useForm } from "@inertiajs/vue3";
|
||||||
import TextInput from '@/Components/TextInput.vue';
|
import { nextTick, ref } from "vue";
|
||||||
import { useForm } from '@inertiajs/vue3';
|
|
||||||
import { nextTick, ref } from 'vue';
|
|
||||||
|
|
||||||
const confirmingUserDeletion = ref(false);
|
const confirmingUserDeletion = ref(false);
|
||||||
const passwordInput = ref(null);
|
const passwordInput = ref(null);
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
password: '',
|
password: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const confirmUserDeletion = () => {
|
const confirmUserDeletion = () => {
|
||||||
|
|
@ -22,7 +20,7 @@ const confirmUserDeletion = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteUser = () => {
|
const deleteUser = () => {
|
||||||
form.delete(route('profile.destroy'), {
|
form.delete(route("profile.destroy"), {
|
||||||
preserveScroll: true,
|
preserveScroll: true,
|
||||||
onSuccess: () => closeModal(),
|
onSuccess: () => closeModal(),
|
||||||
onError: () => passwordInput.value.focus(),
|
onError: () => passwordInput.value.focus(),
|
||||||
|
|
@ -40,29 +38,40 @@ const closeModal = () => {
|
||||||
<template>
|
<template>
|
||||||
<section class="space-y-6">
|
<section class="space-y-6">
|
||||||
<header>
|
<header>
|
||||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">Delete Account</h2>
|
<h2 class="text-lg font-medium text-gray-100">Delete Account</h2>
|
||||||
|
|
||||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
<p class="mt-1 text-sm text-gray-400">
|
||||||
Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting
|
Once your account is deleted, all of its resources and data will
|
||||||
your account, please download any data or information that you wish to retain.
|
be permanently deleted. Before deleting your account, please
|
||||||
|
download any data or information that you wish to retain.
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<DangerButton @click="confirmUserDeletion">Delete Account</DangerButton>
|
<button
|
||||||
|
class="px-6 py-3 border-red-600 border rounded-lg hover:bg-red-600 hover:border-red-600"
|
||||||
|
@click="confirmUserDeletion"
|
||||||
|
>
|
||||||
|
Delete Account
|
||||||
|
</button>
|
||||||
|
|
||||||
<Modal :show="confirmingUserDeletion" @close="closeModal">
|
<Modal :show="confirmingUserDeletion" @close="closeModal">
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
<h2 class="text-lg font-medium text-gray-100">
|
||||||
Are you sure you want to delete your account?
|
Are you sure you want to delete your account?
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
<p class="mt-1 text-sm text-gray-400">
|
||||||
Once your account is deleted, all of its resources and data will be permanently deleted. Please
|
Once your account is deleted, all of its resources and data
|
||||||
enter your password to confirm you would like to permanently delete your account.
|
will be permanently deleted. Please enter your password to
|
||||||
|
confirm you would like to permanently delete your account.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<InputLabel for="password" value="Password" class="sr-only" />
|
<InputLabel
|
||||||
|
for="password"
|
||||||
|
value="Password"
|
||||||
|
class="sr-only"
|
||||||
|
/>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
id="password"
|
id="password"
|
||||||
|
|
@ -78,16 +87,14 @@ const closeModal = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-6 flex justify-end">
|
<div class="mt-6 flex justify-end">
|
||||||
<SecondaryButton @click="closeModal"> Cancel </SecondaryButton>
|
<button
|
||||||
|
class="px-6 py-3 border-red-600 border rounded-lg hover:bg-red-600 hover:border-red-600"
|
||||||
<DangerButton
|
|
||||||
class="ml-3"
|
|
||||||
:class="{ 'opacity-25': form.processing }"
|
:class="{ 'opacity-25': form.processing }"
|
||||||
:disabled="form.processing"
|
:disabled="form.processing"
|
||||||
@click="deleteUser"
|
@click="deleteUser"
|
||||||
>
|
>
|
||||||
Delete Account
|
Delete Account
|
||||||
</DangerButton>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,30 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import InputError from '@/Components/InputError.vue';
|
import InputError from "@/Components/InputError.vue";
|
||||||
import InputLabel from '@/Components/InputLabel.vue';
|
import InputLabel from "@/Components/InputLabel.vue";
|
||||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
import TextInput from "@/Components/TextInput.vue";
|
||||||
import TextInput from '@/Components/TextInput.vue';
|
import { useForm } from "@inertiajs/vue3";
|
||||||
import { useForm } from '@inertiajs/vue3';
|
import { ref } from "vue";
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
const passwordInput = ref(null);
|
const passwordInput = ref(null);
|
||||||
const currentPasswordInput = ref(null);
|
const currentPasswordInput = ref(null);
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
current_password: '',
|
current_password: "",
|
||||||
password: '',
|
password: "",
|
||||||
password_confirmation: '',
|
password_confirmation: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatePassword = () => {
|
const updatePassword = () => {
|
||||||
form.put(route('password.update'), {
|
form.put(route("password.update"), {
|
||||||
preserveScroll: true,
|
preserveScroll: true,
|
||||||
onSuccess: () => form.reset(),
|
onSuccess: () => form.reset(),
|
||||||
onError: () => {
|
onError: () => {
|
||||||
if (form.errors.password) {
|
if (form.errors.password) {
|
||||||
form.reset('password', 'password_confirmation');
|
form.reset("password", "password_confirmation");
|
||||||
passwordInput.value.focus();
|
passwordInput.value.focus();
|
||||||
}
|
}
|
||||||
if (form.errors.current_password) {
|
if (form.errors.current_password) {
|
||||||
form.reset('current_password');
|
form.reset("current_password");
|
||||||
currentPasswordInput.value.focus();
|
currentPasswordInput.value.focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -36,10 +35,11 @@ const updatePassword = () => {
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<header>
|
<header>
|
||||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">Update Password</h2>
|
<h2 class="text-lg font-medium text-gray-100">Update Password</h2>
|
||||||
|
|
||||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
<p class="mt-1 text-sm text-gray-400">
|
||||||
Ensure your account is using a long, random password to stay secure.
|
Ensure your account is using a long, random password to stay
|
||||||
|
secure.
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -56,7 +56,10 @@ const updatePassword = () => {
|
||||||
autocomplete="current-password"
|
autocomplete="current-password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InputError :message="form.errors.current_password" class="mt-2" />
|
<InputError
|
||||||
|
:message="form.errors.current_password"
|
||||||
|
class="mt-2"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -75,7 +78,10 @@ const updatePassword = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<InputLabel for="password_confirmation" value="Confirm Password" />
|
<InputLabel
|
||||||
|
for="password_confirmation"
|
||||||
|
value="Confirm Password"
|
||||||
|
/>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
id="password_confirmation"
|
id="password_confirmation"
|
||||||
|
|
@ -85,11 +91,19 @@ const updatePassword = () => {
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InputError :message="form.errors.password_confirmation" class="mt-2" />
|
<InputError
|
||||||
|
:message="form.errors.password_confirmation"
|
||||||
|
class="mt-2"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<PrimaryButton :disabled="form.processing">Save</PrimaryButton>
|
<button
|
||||||
|
class="px-6 py-3 border-sky-600 border rounded-lg hover:bg-sky-600"
|
||||||
|
:disabled="form.processing"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
|
||||||
<Transition
|
<Transition
|
||||||
enter-active-class="transition ease-in-out"
|
enter-active-class="transition ease-in-out"
|
||||||
|
|
@ -97,7 +111,12 @@ const updatePassword = () => {
|
||||||
leave-active-class="transition ease-in-out"
|
leave-active-class="transition ease-in-out"
|
||||||
leave-to-class="opacity-0"
|
leave-to-class="opacity-0"
|
||||||
>
|
>
|
||||||
<p v-if="form.recentlySuccessful" class="text-sm text-gray-600 dark:text-gray-400">Saved.</p>
|
<p
|
||||||
|
v-if="form.recentlySuccessful"
|
||||||
|
class="text-sm text-gray-400"
|
||||||
|
>
|
||||||
|
Saved.
|
||||||
|
</p>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import InputError from '@/Components/InputError.vue';
|
import InputError from "@/Components/InputError.vue";
|
||||||
import InputLabel from '@/Components/InputLabel.vue';
|
import InputLabel from "@/Components/InputLabel.vue";
|
||||||
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
import TextInput from "@/Components/TextInput.vue";
|
||||||
import TextInput from '@/Components/TextInput.vue';
|
import { Link, useForm, usePage } from "@inertiajs/vue3";
|
||||||
import { Link, useForm, usePage } from '@inertiajs/vue3';
|
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
mustVerifyEmail: {
|
mustVerifyEmail: {
|
||||||
|
|
@ -25,14 +24,19 @@ const form = useForm({
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<header>
|
<header>
|
||||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">Profile Information</h2>
|
<h2 class="text-lg font-medium text-gray-100">
|
||||||
|
Profile Information
|
||||||
|
</h2>
|
||||||
|
|
||||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
<p class="mt-1 text-sm text-gray-400">
|
||||||
Update your account's profile information and email address.
|
Update your account's profile information and email address.
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<form @submit.prevent="form.patch(route('profile.update'))" class="mt-6 space-y-6">
|
<form
|
||||||
|
@submit.prevent="form.patch(route('profile.update'))"
|
||||||
|
class="mt-6 space-y-6"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<InputLabel for="name" value="Name" />
|
<InputLabel for="name" value="Name" />
|
||||||
|
|
||||||
|
|
@ -65,13 +69,13 @@ const form = useForm({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="mustVerifyEmail && user.email_verified_at === null">
|
<div v-if="mustVerifyEmail && user.email_verified_at === null">
|
||||||
<p class="text-sm mt-2 text-gray-800 dark:text-gray-200">
|
<p class="text-sm mt-2 text-gray-200">
|
||||||
Your email address is unverified.
|
Your email address is unverified.
|
||||||
<Link
|
<Link
|
||||||
:href="route('verification.send')"
|
:href="route('verification.send')"
|
||||||
method="post"
|
method="post"
|
||||||
as="button"
|
as="button"
|
||||||
class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"
|
class="underline text-sm text-gray-400 hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800"
|
||||||
>
|
>
|
||||||
Click here to re-send the verification email.
|
Click here to re-send the verification email.
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -79,14 +83,19 @@ const form = useForm({
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-show="status === 'verification-link-sent'"
|
v-show="status === 'verification-link-sent'"
|
||||||
class="mt-2 font-medium text-sm text-green-600 dark:text-green-400"
|
class="mt-2 font-medium text-sm text-green-400"
|
||||||
>
|
>
|
||||||
A new verification link has been sent to your email address.
|
A new verification link has been sent to your email address.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<PrimaryButton :disabled="form.processing">Save</PrimaryButton>
|
<button
|
||||||
|
class="px-6 py-3 border-sky-600 border rounded-lg hover:bg-sky-600"
|
||||||
|
:disabled="form.processing"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
|
||||||
<Transition
|
<Transition
|
||||||
enter-active-class="transition ease-in-out"
|
enter-active-class="transition ease-in-out"
|
||||||
|
|
@ -94,7 +103,12 @@ const form = useForm({
|
||||||
leave-active-class="transition ease-in-out"
|
leave-active-class="transition ease-in-out"
|
||||||
leave-to-class="opacity-0"
|
leave-to-class="opacity-0"
|
||||||
>
|
>
|
||||||
<p v-if="form.recentlySuccessful" class="text-sm text-gray-600 dark:text-gray-400">Saved.</p>
|
<p
|
||||||
|
v-if="form.recentlySuccessful"
|
||||||
|
class="text-sm text-gray-400"
|
||||||
|
>
|
||||||
|
Saved.
|
||||||
|
</p>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue