Skip to content

Commit f85f64f

Browse files
author
ahmadhussnain
committed
CategoriesCreate vue component has been updated
1 parent b1ff0b1 commit f85f64f

File tree

3 files changed

+187
-30
lines changed

3 files changed

+187
-30
lines changed

app/Http/Controllers/Api/CategoryController.php

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@
55
use App\Http\Controllers\Controller;
66
use App\Http\Requests\StoreCategoryRequest;
77
use App\Http\Resources\CategoryResource;
8+
use App\Http\Traits\URLScheme;
89
use App\Models\Category;
910
use Exception;
11+
use Illuminate\Support\Facades\Storage;
12+
use Illuminate\Support\Facades\URL;
1013
use Symfony\Component\HttpFoundation\Response;
11-
use Illuminate\Http\Request;
12-
use Illuminate\Http\Resources\Json\ResourceResponse;
1314

1415
class CategoryController extends Controller
1516
{
17+
use URLScheme;
18+
1619
public function index()
1720
{
1821
// return Category::orderBy('id')->get(); // Laravel will return as JSON format.
1922
// We only want id, name filed in the response.
2023
// $categories = Category::select('id','name')->get(); This is efficient approach.
2124
// But we are already defined our toArray response
22-
$categories = Category::all();
25+
$categories = Category::orderBy('id')->get();
2326
return CategoryResource::collection($categories); // Now we are returning resource collection
2427
}
2528

@@ -40,8 +43,8 @@ public function show(Category $category)
4043
public function store(StoreCategoryRequest $request)
4144
{
4245
try {
43-
$category = Category::create($request->all());
44-
// 201 means Created Successfully
46+
$data = $this->storeUpdateCategoryPhoto($request);
47+
$category = Category::create($data);
4548
return (new CategoryResource($category))->response()->setStatusCode(201);
4649
} catch (Exception $exception) { // Anything that went wrong
4750
abort(500, 'Could not create category');
@@ -70,4 +73,37 @@ public function destroy(Category $category) {
7073
}
7174

7275

76+
// Method for storing or uploading category name & photo
77+
private function storeUpdateCategoryPhoto(StoreCategoryRequest $request, Category $category = null, bool $deleteOldFile = false): array
78+
{
79+
// Update data
80+
$data = $request->all();
81+
82+
if ($request->hasFile('photo')) {
83+
84+
// If there is a photo(jpg|jpeg|png) inside the request
85+
// then it means we have to delete the old photo from the file system
86+
// and replace with the new one.
87+
if ($deleteOldFile && $category->photo) {
88+
// Returns trailing name component of path
89+
$oldPath = basename($category->photo); // 6546dgfgfdgfg.jpg
90+
Storage::delete('/public/categories/'.$oldPath);
91+
}
92+
93+
$file = $request->file('photo');
94+
/*
95+
// Old way to store images
96+
$filename = 'categories/' . uniqid() . '.' . $file->extension(); // categories/6546dgfgfdgfg.jpg
97+
$file->storePubliclyAs('public', $filename); // Store inside filesystem categories/6546dgfgfdgfg.jpg
98+
*/
99+
100+
// New way
101+
$fileDirectory = '/categories/';
102+
$fileName = uniqid().'.'. $file->extension();
103+
Storage::putFileAs('public'.$fileDirectory, $file, $fileName);
104+
105+
$data['photo'] = URL::to(''.'storage'.$fileDirectory.$fileName, [], $this->isSecureScheme()); // http://lara8api.test/storage/categories/6546dgfgfdgfg.jpg
106+
}
107+
return $data;
108+
}
73109
}
Lines changed: 114 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,126 @@
11
<template>
2-
<div class="container py-5">
3-
<div class="row">
4-
<div class="col-lg-12">
5-
<div class="mb-3">
6-
<label for="name" class="form-label">Name:</label>
7-
<input type="text" v-model="name" name="name" class="form-control" id="name" placeholder="Category Name" autocomplete="off">
8-
<input type="button" class="btn btn-primary mt-3" value="Add Category" @click="createCategory()">
9-
</div>
2+
<div class="container py-5">
3+
<div class="row">
4+
<div class="col-lg-12">
5+
<div class="mb-3">
6+
<form v-on:submit.prevent="submitForm">
7+
<label for="name" class="form-label">Name:</label>
8+
<input
9+
type="text"
10+
v-model="form.name"
11+
name="name"
12+
class="form-control"
13+
id="name"
14+
placeholder="Category Name"
15+
autocomplete="off"
16+
/>
17+
<hr />
18+
<p class="form-label">Photo:</p>
19+
<div class="api">
20+
<div class="api__overlay">
21+
<div class="api-file">
22+
<label class="api-file__label">
23+
<input
24+
type="file"
25+
accept="image/*"
26+
name="photo"
27+
@change="onHandleUpload($event)"
28+
class="api-file__input"
29+
/>
30+
<span class="api-file__btn">
31+
<span class="api-file__text">Upload</span>
32+
</span>
33+
</label>
34+
</div>
35+
</div>
1036
</div>
37+
38+
<hr />
39+
40+
<button
41+
class="btn btn-primary"
42+
type="button"
43+
:disabled="isSubmitted"
44+
@click="submitForm"
45+
>
46+
<span
47+
v-if="isSubmitted"
48+
class="spinner-border spinner-border-sm"
49+
role="status"
50+
aria-hidden="true"
51+
></span>
52+
<span class="visually-hidden">{{
53+
isSubmitted ? 'Loading' : 'Submit'
54+
}}</span>
55+
</button>
56+
</form>
1157
</div>
58+
</div>
1259
</div>
60+
</div>
1361
</template>
1462

1563
<script>
64+
import { onSingleFileUpload, uploadProgress } from '../utils';
65+
1666
export default {
17-
name: 'CategoriesCreate',
18-
data: function (){
19-
return {
20-
name: ''
21-
}
67+
name: 'CategoriesCreate',
68+
data: function () {
69+
return {
70+
isSubmitted: false, // To check whether the form is in the submitted
71+
form: {
72+
name: '',
73+
photo: ''
74+
},
75+
selectedFile: null
76+
};
77+
},
78+
methods: {
79+
onHandleUpload: function (event) {
80+
const file = onSingleFileUpload(event);
81+
if (file) {
82+
this.selectedFile = file;
83+
}
2284
},
23-
methods: {
24-
createCategory: function (){
25-
console.log('Creating Category...');
26-
axios.post('/api/categories', {
27-
name: this.name
28-
}).then( function(response) {
29-
console.log('New Category ID', response.data.data.id);
30-
}).catch(function(err) {
31-
console.log(err);
32-
console.log('Category Route error Promise has been rejected!', err.response.data.errors);
33-
});
85+
submitForm: function () {
86+
const self = this;
87+
88+
// Check if the string is not empty
89+
if (typeof self.form.name === 'string' && self.form.name.length > 0) {
90+
self.isSubmitted = true;
91+
92+
const formData = new FormData();
93+
94+
// Append formData fields
95+
formData.append('name', self.form.name);
96+
if (self.selectedFile) {
97+
formData.append('photo', self.selectedFile);
3498
}
99+
100+
axios
101+
.post(`/api/categories`, formData, {
102+
headers: { 'Content-Type': 'multipart/form-data' },
103+
onUploadProgress: uploadProgress
104+
})
105+
.then(function (response) {
106+
console.log('response', response.data);
107+
self.isSubmitted = false;
108+
self.form.name = '';
109+
self.form.photo = '';
110+
alert('Data is successfully updated');
111+
})
112+
.catch(function (_) {
113+
self.isSubmitted = false;
114+
self.form.name = '';
115+
self.form.photo = '';
116+
alert('Oops! Something went wrong during posting the form. 🥺');
117+
});
118+
} else {
119+
alert(
120+
`Sorry We can't submit the form. The category 'name' is required. 🥺`
121+
);
122+
}
35123
}
36-
}
124+
}
125+
};
37126
</script>

resources/js/utils/index.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export const getFileExtension = function(fileName) {
2+
return fileName.split('.').pop();
3+
};
4+
5+
/**
6+
* This function will take an Vue.js inner event.
7+
*
8+
* @param event
9+
* @returns {*}
10+
*/
11+
export const onSingleFileUpload = function(event) {
12+
const { target } = event;
13+
console.log('Target files', target.files);
14+
if (target.files.length > 0 && target.files.length < 2) {
15+
const extension = getFileExtension(target.files[0]?.name);
16+
17+
// Check client-side if the upload file is image or not
18+
if (extension === 'jpg' || extension === 'png' || extension === 'jpeg') {
19+
return target.files[0];
20+
} else {
21+
alert('Please upload image file instead of this! 🥺');
22+
}
23+
} else {
24+
alert("Sorry currently, we're not supporting multiple files upload! 🥺");
25+
}
26+
};
27+
28+
29+
export const uploadProgress = function(uploadEvent) {
30+
const { loaded, total} = uploadEvent;
31+
console.log(`Uploading status : ${(loaded / total) * 100}%`);
32+
}

0 commit comments

Comments
 (0)