Add and fix nominee profile photo uploads

- Run artisan migrate to add column photo in nominee table
- npm run development/watch
This commit is contained in:
Afiq Hamzah
2024-03-23 23:01:43 +08:00
committed by nurafrinaalimi16
parent 8bde7a0544
commit 1d892b064e
8 changed files with 196 additions and 66 deletions
@@ -43,12 +43,19 @@ class AddController extends Controller
]);
}
public function insertNominee ($request)
public function insertNominee ($request)
{
$nominee = $request->all();
$default_image = config('app.cloudinary_enabled') ? config('app.cloudinary_image_default') : config('app.nominee_image');
$nominee['image'] = Util::getImagePath($request, config('app.nominee_directory'), $default_image);
$nominee = $request->except(['photo']);
$nominee['election_id'] = Util::getCurrentElection();
if ($request->hasFile('photo')) {
$imageData = file_get_contents($request->file('photo'));
$nominee['photo'] = $imageData;
}
Nominee::create($nominee);
return response()->json(['message' => 'Photo updated successfully']);
}
}
@@ -41,11 +41,10 @@ class UpdateController extends Controller
]);
}
private function updateNominee ($request, $id)
private function updateNominee ($request, $id)
{
$nominee = Nominee::find($id);
$default_image = $nominee->image;
$nominee->name = $request->name;
$nominee->unit = $request->unit;
$nominee->no_anggota = $request->no_anggota;
@@ -53,11 +52,13 @@ class UpdateController extends Controller
$nominee->partylist_id = $request->partylist_id;
$nominee->motto = $request->motto;
$nominee->description = $request->description;
$nominee->image = Util::getImagePath($request, config('app.nominee_directory'), $default_image);
$nominee->save();
if (!empty($request->image))
Util::deleteImage($default_image);
if ($request->hasFile('photo')) {
$imageData = file_get_contents($request->file('photo'));
$nominee->photo = $imageData;
}
$nominee->save();
}
}
+15 -5
View File
@@ -8,14 +8,24 @@ class Nominee extends Model
{
protected $table = 'nominee';
protected $fillable = [
'name',
'unit',
'no_anggota',
'name',
'unit',
'no_anggota',
'position_id',
'partylist_id',
'election_id',
'image',
'description',
'motto'
'motto',
'photo',
];
public $timestamp = false;
public function getPhotoAttribute($value)
{
if ($value) {
return base64_encode($value);
}
return null;
}
}
@@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddPhotoColumnToNomineeTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('nominee', function (Blueprint $table) {
$table->binary('photo')->nullable();
$table->dropColumn('image');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('nominee', function (Blueprint $table) {
$table->dropColumn('photo');
$table->string('image');
});
}
}
@@ -46,9 +46,12 @@
</select>
</div>
<div id="imagePreview">
<img :src="imageUrl" v-if="imageUrl" alt="Preview">
</div>
<div>
<label for="image">Masukkan Gambar</label>
<input type="file" accept="image/*" @change="uploadImage($event)" id="file-input">
<input name="photo" type="file" accept="image/*" id="file-input" @change="handleImageChange">
</div>
@@ -70,6 +73,7 @@
export default {
data: function () {
return {
imageUrl: '',
loading: false
}
},
@@ -88,6 +92,8 @@ export default {
vm.$router.push({ name: 'Maklumat Calon' });
},
error: function (error) {
alert('Nominee with the same name has already registered');
location.reload();
$.notifyClose();
vm.loading = false;
vm.util.showResult(error, 'error', 'ajax');
@@ -98,30 +104,27 @@ export default {
})
},
uploadImage(event) {
handleImageChange(event) {
const file = event.target.files[0]; // Get the selected file
const imageType = /image.*/; // RegExp to check if the file is an image
const URL = 'http://foobar.com/upload';
// Check if the selected file is an image
if (file && file.type.match(imageType)) {
const reader = new FileReader(); // Create a FileReader object
let data = new FormData();
data.append('name', 'my-picture');
data.append('file', event.target.files[0]);
reader.onload = (e) => {
this.imageUrl = e.target.result; // Set the imageUrl to the data URL of the image
document.getElementById('imagePreview').style.display = 'block'; // Display the div
};
let config = {
header: {
'Content-Type': 'image/png'
}
}
axios.put(
URL,
data,
config
).then(
response => {
console.log('image upload response > ', response)
}
)
}
reader.readAsDataURL(file); // Read the image data as a data URL
} else {
// Clear the file input and hide the div if the selected file is not an image
event.target.value = '';
this.imageUrl = '';
document.getElementById('imagePreview').style.display = 'none';
}
}
},
computed: {
@@ -136,4 +139,19 @@ export default {
}
}
}
</script>
</script>
<style scoped>
#imagePreview {
width: 200px;
height: 200px;
border: 1px solid #ccc;
margin-bottom: 10px;
display: none; /* Initially hide the div */
}
#imagePreview img {
max-width: 100%;
max-height: 100%;
}
</style>
@@ -10,12 +10,8 @@
@submit.prevent="edit()">
<input type="hidden" name="_method" value="PUT"/>
<div class="col-md-4">
<uploader file-name="image" :image-src="data.storageURL+nominee.image"/>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="name">Nama</label>
<input type="text" name="name" class="form-control" :value="nominee.name" required/>
@@ -23,12 +19,12 @@
<div class="form-group">
<label for="student_id">No. Anggota</label>
<input type="text" name="student_id" class="form-control" :value="nominee.student_id" required/>
<input type="text" name="no_anggota" class="form-control" :value="nominee.no_anggota" required/>
</div>
<div class="form-group">
<label for="Unit">Unit</label>
<input type="text" name="unit" class="form-control" :value="nominee.Unit" required/>
<input type="text" name="unit" class="form-control" :value="nominee.unit" required/>
</div>
<div class="form-group">
@@ -57,10 +53,18 @@
</select>
</div>
<div id="imagePreview">
<img :src="imageUrl" v-if="imageUrl" alt="Preview">
</div>
<div>
<label for="image">Masukkan Gambar</label>
<input name="photo" type="file" accept="image/*" id="file-input" @change="handleImageChange">
</div>
<div class="form-group pull-right">
<input type="submit" value="Submit" class="btn btn-info">
<router-link
:to="{name:'Maklumat Calon'}"
<router-link
:to="{name:'Maklumat Calon'}"
class="btn btn-default">
Back
</router-link>
@@ -75,6 +79,7 @@
export default{
data: function () {
return {
imageUrl: '',
loading: false
}
},
@@ -84,7 +89,38 @@ export default{
this.$router.push({name:'Maklumat Calon'});
},
mounted: function () {
if(this.nominee.id) {
this.imageUrl = this.createBase64ImageUrl(this.nominee.photo);
document.getElementById('imagePreview').style.display = 'block';
}
},
methods: {
createBase64ImageUrl: function(base64ImageData) {
return "data:image/png;base64," + base64ImageData;
},
handleImageChange(event) {
const file = event.target.files[0]; // Get the selected file
const imageType = /image.*/; // RegExp to check if the file is an image
// Check if the selected file is an image
if (file && file.type.match(imageType)) {
const reader = new FileReader(); // Create a FileReader object
reader.onload = (e) => {
this.imageUrl = e.target.result; // Set the imageUrl to the data URL of the image
document.getElementById('imagePreview').style.display = 'block'; // Display the div
};
reader.readAsDataURL(file); // Read the image data as a data URL
} else {
// Clear the file input and hide the div if the selected file is not an image
event.target.value = '';
this.imageUrl = '';
document.getElementById('imagePreview').style.display = 'none';
}
},
edit: function () {
if (this.loading) return;
var vm = this;
@@ -94,7 +130,7 @@ export default{
success: function (response) {
$.notifyClose();
vm.loading = false;
if (vm.util.showResult(response, 'success', 'ajax'))
if (vm.util.showResult(response, 'success', 'ajax'))
vm.$router.push({name: 'Maklumat Calon'});
},
error: function (error) {
@@ -122,4 +158,19 @@ export default{
}
}
}
</script>
</script>
<style scoped>
#imagePreview {
width: 200px;
height: 200px;
border: 1px solid #ccc;
margin-bottom: 10px;
display: none; /* Initially hide the div */
}
#imagePreview img {
max-width: 100%;
max-height: 100%;
}
</style>
@@ -2,20 +2,20 @@
<div class="row">
<div class="col-md-3" style="max-width: 250px;">
<ul class="list-group">
<router-link
tag="li"
class="list-group-item"
:to="{name: 'Maklumat Calon'}"
exact
<router-link
tag="li"
class="list-group-item"
:to="{name: 'Maklumat Calon'}"
exact
replace
:class="{'active':position_id==0}">
All Position
</router-link>
<router-link
<router-link
v-for="position in data.positions"
:key="position.id"
tag="li"
class="list-group-item"
tag="li"
class="list-group-item"
:to="{query: {position_id:position.id}}"
exact
replace>
@@ -43,7 +43,7 @@
<tbody>
<tr v-for="nominee in nominees">
<td>
<img :alt="nominee.name" :src="data.storageURL+nominee.image" class="thumbnail" style="height: 60px;width: 60px;">
<img :alt="nominee.name" :src="createBase64ImageUrl(nominee.photo)" class="thumbnail" style="height: 60px;width: 60px;">
</td>
<td>{{ nominee.name}}</td>
<td>{{ nominee.no_anggota}}</td>
@@ -142,7 +142,11 @@ export default{
if (partylists[i].id == id)
return partylists[i]['name'];
return 'No partylists';
}
},
createBase64ImageUrl: function(base64ImageData) {
return "data:image/png;base64," + base64ImageData;
}
},
computed: {
@@ -165,4 +169,4 @@ export default{
}
}
}
</script>
</script>
@@ -51,10 +51,10 @@
</thead>
<tbody>
<tr v-for="(nominee,i) in data.nominees" v-if="nominee.position_id==position.id">
<td><img
<td><img
@click="view(i)"
:src="data.storageURL+nominee.image"
class="thumbnail"
:src="createBase64ImageUrl(nominee.photo)"
class="thumbnail"
style="height: 60px;width: 60px;" />
</td>
<td>{{ nominee.name }}</td>
@@ -124,7 +124,7 @@ export default{
getNominee: function (id) {
let nominees = this.data.nominees;
for (var i in nominees)
for (var i in nominees)
if (nominees[i]['id']==id) return nominees[i].name;
return '';
},
@@ -132,7 +132,12 @@ export default{
view: function (index) {
this.x = this.data.nominees[index];
this.util.showModal('#nominee-information-modal');
}
},
createBase64ImageUrl: function(base64ImageData) {
return "data:image/png;base64," + base64ImageData;
}
},
computed: {