So I do not have a lot of experiencing working on event handlers within the JavaScript module pattern.
There is this implementation that does what it is supposed to do:
//= require templates/modules/dvic_card_gallery
//=require templates/modals/dvic_modal_card_gallery
(function(exports) {
'use strict';
var Grill = exports.Grill,
Whiskers = exports.Whiskers,
$ = exports.$;
// itialize the modal gallery's initial card to the sorcerer
var selectedCardInstantCredit = 'card-sorcerer';
var ModalCardGallery = Grill.ModuleView.extend({
style_classes: ['modal_card_gallery'],
template: Whiskers.modules.dvic_card_gallery,
initialize: function() {
exports.console.log('The Card Gallery module is initialized');
},
events: {
'click .view-full-gallery': 'onClickLink',
'click .sp-thumbnail': 'onClickThumbnail',
'click .sp-forward': 'onClickForwardChevron',
'click .sp-backward': 'onClickBackwardChevron'
},
onClickLink: function(e) {
e.preventDefault();
var modalConfig = {
template: Whiskers.modals.dvic_modal_card_gallery,
name: 'full-gallery',
ctx_additions: this.ctx_additions(),
linkEl: [e.target]
};
if (this.modal === undefined) {
this.modal = new Grill.FullGalleryModalView(modalConfig);
this.modal.show();
} else {
// if the modal has already been created and closed, reopen it
this.modal.show();
}
},
onClickThumbnail: function(e) {
e.preventDefault();
this.$clickedEl = $(e.currentTarget);
// Tells us what card was clicked.
var clickedCard = this.$clickedEl.data("action").trim();
selectedCardInstantCredit = clickedCard;
// Hide all , then show what was clicked.
$(".sp-slides .sp-slide").hide();
$(".sp-slides .sp-slide." + clickedCard).show();
},
onClickForwardChevron: function(e) {
e.preventDefault();
galleryButtonClick(selectedCardInstantCredit, "forward");
},
onClickBackwardChevron: function(e) {
e.preventDefault();
galleryButtonClick(selectedCardInstantCredit, "backward");
},
render: function() {
this.$el.html(this.template.render(this.model));
}
});
//==========================
// Helpers
//==========================
var galleryButtonClick = function (cardName, direction) {
// this array must match the card order in the template
var cardsArray = [
'card-sorcerer',
'card-th',
'card-frozen',
'card-yoda',
'card-pixie',
'card-bb8',
'card-tinker',
'card-spotlight',
'card-pals',
'card-vader'
];
var index = cardsArray.indexOf(cardName);
$('.sp-slides .sp-slide').hide();
// get the card to show
if (direction === 'forward' && index === cardsArray.length -1) {
selectedCardInstantCredit = cardsArray[0];
$('.thumbnail-container').css("left", "150%");
} else if (direction === 'forward') {
selectedCardInstantCredit = cardsArray[index + 1];
} else if (direction === 'backward' && index === 0) {
selectedCardInstantCredit = cardsArray[cardsArray.length - 1];
} else if (direction === 'backward') {
selectedCardInstantCredit = cardsArray[index - 1];
}
$('.sp-slides .sp-slide.' + selectedCardInstantCredit).show();
};
ModalCardGallery.register('dvic_card_gallery', {});
})(this);
but I am trying to console log here:
onClickForwardChevron: function(e) {
e.preventDefault();
exports.console.log('is this working?');
galleryButtonClick(selectedCardInstantCredit, "forward");
},
but I don't get the message logged to console. So I am not sure now how to test this event so I can start adding an implementation I have been wanting to add.
I have also tried by adding an event in the if conditional in the helper section of this file:
if (direction === 'forward' && index === cardsArray.length -1) {
selectedCardInstantCredit = cardsArray[0];
$('.thumbnail-container').css("left", "150%");
This is not working but the idea is to get the thumbnail container as a whole to move left as the user keeps clicking the chevron forward.
Here is the html file:
<button class="sp-backward"></button>
<div class="sp-slides">
<div class="sp-slide card-sorcerer"><div role="img" aria-label="The Sorcerer Mickey card" class="card-image"></div><div class="card-title" aria-hidden="true">Sorcerer Mickey</div></div>
<div class="sp-slide card-th"><div role="img" aria-label="The Diamond Celebration (2015-2016) card" class="card-image"></div><div class="card-title" aria-hidden="true">Diamond Celebration<br/>(2015-2016)</div></div>
<div class="sp-slide card-frozen"><div role="img" aria-label="The Frozen card" class="card-image"></div><div class="card-title" aria-hidden="true">Frozen</div></div>
<div class="sp-slide card-yoda"><div role="img" aria-label="The Yoda card" class="card-image"></div><div class="card-title" aria-hidden="true">Yoda</div></div>
<div class="sp-slide card-pixie"><div role="img" aria-label="The Pixie Dust card" class="card-image"></div><div class="card-title" aria-hidden="true">Pixie Dust</div></div>
<div class="sp-slide card-bb8"><div role="img" aria-label="The BB-8 card" class="card-image"></div><div class="card-title" aria-hidden="true">BB-8</div></div>
<div class="sp-slide card-tinker"><div role="img" aria-label="The Tink card" class="card-image"></div><div class="card-title" aria-hidden="true">Tink</div></div>
<div class="sp-slide card-spotlight"><div role="img" aria-label="The Spotlight card" class="card-image"></div><div class="card-title" aria-hidden="true">Spotlight</div></div>
<div class="sp-slide card-pals"><div role="img" aria-label="The Mickey and Pals card" class="card-image"></div><div class="card-title" aria-hidden="true">Mickey & Pals</div></div>
<div class="sp-slide card-vader"><div role="img" aria-label="The Darth Vader card" class="card-image"></div><div class="card-title" aria-hidden="true">Darth Vader</div></div>
</div>
<button class="sp-forward"/></button>
</div>
<div class="thumbnail-container">
<button class="sp-thumbnail sorcerer ada-el-focus" data-action="card-sorcerer" title="View the Sorcerer Mickey card"></button>
<button class="sp-thumbnail th ada-el-focus" data-action="card-th" title="View the Diamond Celebration card" id="box1"></button>
<button class="sp-thumbnail frozen ada-el-focus" data-action="card-frozen" title="View the Frozen card" id="box2"></button>
<button class="sp-thumbnail yoda ada-el-focus" data-action="card-yoda" title="View the Yoda card" id="box3"></button>
<button class="sp-thumbnail pixie ada-el-focus" data-action="card-pixie" title="View the Pixie Dust card"></button>
<button class="sp-thumbnail bb8 ada-el-focus" data-action="card-bb8" title="View the BB-8 card"></button>
<button class="sp-thumbnail tinker ada-el-focus" data-action="card-tinker" title="View the Tink card"></button>
<button class="sp-thumbnail spotlight ada-el-focus" data-action="card-spotlight" title="View the Spotlight card"></button>
<button class="sp-thumbnail pals ada-el-focus" data-action="card-pals" title="View the Mickey and Pals card"></button>
<button class="sp-thumbnail vader ada-el-focus" data-action="card-vader" title="View the Darth Vader card"></button>
</div>
</div>
Its scope, so in your code you reference both modal views and then ModuleView. This looks like Backbone and I had the same issue. Not sure your level of experience with, but if you have a modal that opens then you want to have both this: var ModalCardGallery = Grill.ModuleView.extend for the module page and then this: var ModalCardGallery = Grill.ModalView.extend for the modal view as some of your events are in module view and others in modal view. Speaking of which, separate those events out as well.
Related
I have a question and problem with how to show edited text in WYSIWYG textarea. It didn't show up :(
I tried with summernote and ckeditor and always the same, it didn't show up and shows an empty textarea.
Idea is to make a "template" editor where the customer can make a template for example proof for his member that they work for him because of bus tickets or something like that. So, I made a Liveware component that shows up list of templates and when users click on a template from the list they will need to get the previously saved template so they can edit/change if needs something to change. But for some reason, I get only empty textarea if I put summernote or ckeditor and I can't find a reason why that happened. The same is in the database had some info or not.
Here is my component template:
<div>
<div class="px-4 py-3 mb-8 bg-white rounded-lg shadow-md dark:bg-gray-800">
<label class="block text-sm">
<span class="text-gray-700 dark:text-white">{{__('site.team_member_document.document_type')}}</span>
<select class="block w-full mt-1 text-sm"
name="team_member_document_type_id" id="team_member_document_type_id"
wire:model="team_member_document_type_id" wire:change="onChangeDocumentType()">
<option value="">{{__('site.team_member_document.select_document_type')}}</option>
#foreach($document_types as $item)
<option value="{{$item['id']}}"
#if(old('team_member_document_type_id')==$item['id']) selected #endif
>{{$item['name']}}</option>
#endforeach
</select>
</label>
<label class="block text-sm" wire:ignore>
<span class="text-gray-700 dark:text-white">{{__('site.team_member_document.template')}}</span>
<textarea name="template" id="template" wire:model.defer="template">{{ $template }}</textarea>
</label>
<label class="block mt-4 text-sm">
<button type="button" wire:click="submitForm()"
class="px-4 py-2 text-sm font-medium">
{{__('site.save')}}
</button>
<a href="{{route('team_member_document.index')}}"
class="px-4 py-2 text-sm font-medium">
{{__('site.cancel')}}
</a>
</label>
</div>
<script>
$(function () {
$('#template').summernote({
placeholder: '',
height: 300,
toolbar: [
['style', ['style']],
['font', ['bold', 'underline', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']],
['insert', ['link']],
['view', ['fullscreen', 'codeview']]
],
callbacks: {
onChange: function (contents, $editable) {
#this.set('template', contents);
}
}
});
})
</script>
and here is Livewire component code:
namespace App\Http\Livewire;
use Livewire\Component;
class TeamMemberDocumentTemplate extends Component
{
public $document_types;
public $team_member_document_type_id;
public $template;
protected array $rules = [
'template' => 'required|min:30',
];
public function mount($document_types)
{
$this->template = '';
$this->document_types = $document_types;
}
public function render()
{
return view('livewire.team-member-document-template');
}
public function onChangeDocumentType()
{
$this->template = $this->document_types->filter(function ($item) {
return ($this->team_member_document_type_id == $item->id);
})->first()->template ?? '';
}
public function submitForm()
{
$this->validate();
$document_type = $this->document_types->filter(function ($item) {
return ($this->team_member_document_type_id == $item->id);
})->first();
$document_type->update([
'template' => $this->template
]);
return redirect()->route('team_member_document.index');
}
}
When adding this part of the code into livewire.team-member-document-template.blade.php all works well:
When adding this part of the code into livewire.team-member-document-template.blade.php all works well:
<script> $(function () { $('#summernote_small').on('summernote.change', function (we, contents, $editable) { #this.set('print_note', contents); }); }) </script>
<b-collapse :id="`news-${news.id}`" visible>
<span v-html="getNewsExcerpt(news.body).newsText"></span>
</b-collapse>
<b-collapse :id="`news-${news.id}`">
<span v-html="news.body" ></span>
</b-collapse>
<a href="javascript:void(0)" v-if="getNewsExcerpt(news.body).isExcerpt" v-b-toggle="`news-${news.id}`">
<span class="is-opened">Show more text</span> <span class="is-closed">Show less text</span>
</a>
<div class="text-center" v-show="moreExists">
<button type="button" class="btn btn-primary btn-sm" v-on:click="loadMore">Load more...</button>
</div>
methods: {
getNewsExcerpt (news) {
let excerpt = (news.length > 100) ? true : false
return {
newsText: news.substring(0,100) + "...",
isExcerpt: excerpt,
}
},
loadMore: async function() {
await axios.get('/news/get?page='+this.nextPage)
.then(response => {
this.moreExists =response.data.meta.current_page < response.data.meta.last_page;
this.nextPage = response.data.meta.current_page + 1;
response.data.data.forEach(data => {
this.allnews.push(data);
});
})
.catch(err => {
console.error(err)
this.showErrorNotification()
})
}
},
<style scoped>
.collapsed > .is-opened,
:not(.collapsed) > .is-closed {
display: none;
}
</style>
When I click on Load more news, if in text is Show more text it changes in Show less text and I didnt click on that Load more it affects the buttons below the text..Can anyone help me? I tried to do on so many ways and nothing helped with this code in Vue.
I have this problem: I have a component with which I create editable fields.
If the field is already populated, everything works fine. I see the database value, I can click on it and change it.
If, on the other hand, in the database that value is empty, it is "hidden" in the view. In this way it is not possible to click on it to insert a value in the editable field.
I tried to get around the obstacle by inserting a: placeholder = "placeholder" but I don't even see that.
How can I do?
This is my visualization file:
<div class="py-0 sm:grid sm:grid-cols-10 sm:gap-4 my-2">
<dt class="text-md leading-6 font-medium text-gray-900 sm:col-span-2 self-center">
{{ $trans('labels.description') }}
</dt>
</div>
<div class="py-1 sm:grid sm:grid-cols-10 sm:gap-4">
<dd class="text-sm leading-5 text-gray-600 sm:mt-0 sm:col-span-10 self-center">
<v-input-text-editable
v-model="task.description"
#input="updateTask()"
:placeholder = "placeholder"
/>
</dd>
</div>
props: {
users: {
type: Array,
default: []
},
description: {
type: String,
default: null
}
},
data() {
return {
task: new Form({
description: this.description
})
}
},
this is my component:
<template>
<div class="block w-full">
<div v-if="!editable" class="cursor-pointer" #click="enableEditMode()">
{{ valueAfterEdit }}
</div>
<div v-else class="mt-1 flex rounded-md shadow-sm" v-click-outside="handleClickOutside">
<div class="relative flex-grow focus-within:z-10">
<input #keyup.enter="commitChanges()" class="form-input block w-full rounded-none rounded-l-md transition ease-in-out duration-150 sm:text-sm sm:leading-5" v-model="valueAfterEdit" ref="input"/>
</div>
<span class="btn-group">
<button #click="discardChanges()" type="button" class="btn btn-white rounded-l-none border-l-0">
<svg class="h-4 w-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z"/>
</svg>
</button>
<button #click="commitChanges()" type="button" class="btn btn-white">
<svg class="h-4 w-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path d="M0 11l2-2 5 5L18 3l2 2L7 18z"/>
</svg>
</button>
</span>
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: null
},
allowEmpty: {
type: Boolean,
default: false
}
},
data() {
return {
editable: false,
valueBeforeEdit: this.value,
valueAfterEdit: this.value
}
},
watch: {
value(val) {
this.valueBeforeEdit = val;
}
},
methods: {
handleClickOutside() {
this.disableEditMode();
this.commitChanges();
},
enableEditMode() {
this.editable = true;
this.$emit('edit-enabled');
this.$nextTick(() => {
this.$refs.input.focus();
});
},
disableEditMode() {
this.editable = false;
this.$emit('edit-disabled');
},
commitChanges() {
if (!this.allowEmpty && this.valueAfterEdit !== '.') {
this.$emit('input', this.valueAfterEdit);
this.disableEditMode();
}
},
discardChanges() {
this.valueAfterEdit = this.valueBeforeEdit;
this.disableEditMode();
}
}
}
</script>
i had implement the click event for the chart and it can filter the data in the table. But now i face the problem of the data does not return all the data in the table when click outside the chart are.How can make it return all the data when click outside the area chart? Thank you. Any help will be appreciated.
<script>
import VueApexCharts from "vue-apexcharts";
import faker from "faker";
export default {
components: {
VueApexCharts,
},
data() {
return {
Lists: [],
selectedData:{},
search1:'',
clicked:'',
clicked1:'',
isLoading1:true,
currentPage: 1,
series: [300, 200, 49, 100,290, 228, 119, 55],
chartOptions: {
colors: ['#7961F9', '#FF9F43', '#196EB0', '#2EAB56','#df87f2','#057FF2', '#14DA6E','#FF5500'],
legend: {
fontSize: "14px",
position: "top",
},
dataLabels: {
enabled: true,
minAngleToShowLabel: 0,
distributed: false,
style: {
colors: ['#111'],
},
background: {
enabled: true,
foreColor: '#fff',
borderWidth: 0,
}
},
chart: {
width: 500,
type: 'pie',
events: {
legendClick: (chartContext, seriesIndex,w, config) => {
this.clicked = w.config.labels[seriesIndex];
console.log(this.clicked);
console.log(seriesIndex);
},
dataPointSelection: (event,chartContext,config) => {
this.clicked1 = config.w.config.labels[config.dataPointIndex];
console.log(this.clicked1);
},
},
},
labels: ['Private', 'Local','Dental', 'Government','Cyber Security', 'Health', 'Foreign','Medical'],
responsive: [
{
breakpoint: 480,
options: {
legend: {
position: "bottom",
fontSize: "12px",
},
},
},
],
},
}
},
created() {
this.getData();
this.getData1();
},
computed:{
filterLists(){
let list = this.Lists;
if(this.search1 !=''){
list = list.filter((tr)=>{
return tr.agency.toUpperCase().includes(this.search1.toUpperCase())
});
}
if (this.clicked !=''&& this.clicked){
list = list.filter((tr)=>{
return tr.projectCategory.toUpperCase().includes(this.clicked.toUpperCase())
});
}
if (this.clicked1 !=''&& this.clicked1){
list = list.filter((tr)=>{
return tr.projectCategory.toUpperCase().includes(this.clicked1.toUpperCase())
});
}
return list;
},
},
methods: {
next(page) {},
getData1() {
this.isLoading1 = true;
for (let i = 0; i < this.randInt(8, 4); i++) {
let index = Math.floor(Math.random() * 2);
let projectCategory = this.rotate([
'Private', 'Local','Dental', 'Government','Cyber Security', 'Health', 'Foreign','Medical'
]);
this.Lists.push({
projectCategory:projectCategory,
project_name: faker.company.catchPhrase(),
agency: faker.company.companyName(),
logo: faker.image.abstract(),
});
}
this.maxPage = 2;
this.isLoading1 = false;
},
next1(page) {
if (page == -2) {
this.currentPage = 1;
} else if (page == -3) {
this.currentPage = this.maxPage;
} else {
if (
this.currentPage + page < 1 ||
this.currentPage + page > this.maxPage
) {
return;
}
this.currentPage += page;
}
this.showLoader("#card-list");
this.Lists = [];
this.isLoading1 = true;
setTimeout(() => {
this.closeLoader("#card-list");
this.getData1();
}, 1500);
},
},
};
</script>
<style>
#card > header{
padding: 1.5rem 2rem;
background-color: #2E3839;
}
#card{
--tw-bg-opacity: 1;
background-color: rgba(249, 250, 251, var(--tw-bg-opacity));
}
.con-img.vs-avatar--con-img img {
object-fit: cover !important;
}
.apexcharts-toolbar {
position:absolute;
margin-right:12px;
}
vs-button.btn:hover{
background-color: rgba(255,255,255,0);
cursor: pointer;
}
</style>
<template>
<div class="mb-base">
<div class="vx-row mb-base">
<div class="vx-col 2/3 w-full mb-base">
<vs-card
id="card"
class="vs-con-loading__container h-full"
>
<template slot="header">
<div class="flex">
<div>
<img
src=""
alt="Info"
class="h-12 inline-block mr-4 object-scale-down"
/>
</div>
<div class="flex flex-col justify-center w-full text-start">
<h3 class="text-white">Source of Fund</h3>
<span class="text-sm text-white">Based on Total Billed (Yearly)</span>
</div>
<div>
</div>
</div>
</template>
<div class="flex flex-wrap mt-2">
<div class="lg:w-1/3 w-full">
<vue-apex-charts
type="donut"
:options="chartOptions"
:series="series"
width="100%"
class="items-center justify-center flex mt-16 content-center"
/>
</div>
<div class="lg:w-2/3 w-full lg:pl-6 pl-0 mt-6">
<div class="flex justify-end items-end">
<vx-input-group class="mb-base lg:w-1/2 w-full">
<template slot="append">
<div class="append-text btn-addon">
<vs-button color="#A9A9A9"><i class="fas fa-search"></i></vs-button>
</div>
</template>
<vs-input
v-model="search1"
placeholder="Project Code or name"
/>
</vx-input-group>
</div>
<div id="card-list">
<vs-list v-if="!isLoading1">
<vs-list-item
v-for="(tr, index) in filtertLists"
:key="index"
class="hover:shadow cursor-pointer text-base mb-4"
>
<template slot="title">
<div
class="flex flex-col ml-2 cursor-pointer"
>
<div class="font-bold">{{ tr.project_name }}</div>
<div>{{ tr.agency }}</div>
</div>
</template>
<template slot="avatar">
<vs-avatar :src="tr.logo"></vs-avatar>
</template>
{{ tr.projectCategory }}
</vs-list-item>
<div v-if="!filterLists.length" class="flex">
<div class="items-center justify-center text-lg font-bold">No record...</div>
</div>
</vs-list>
<div v-else class="flex">
<div class="items-center justify-center">Fetching data...</div>
</div>
</div>
<div class="flex justify-end gap-4">
<div class="flex items-center justify-center text-sm">
Page {{ currentPage }} of
{{ maxPage }}
</div>
<div>
<vs-button
type="filled"
color=" rgba(243, 244, 246)"
class="w-10 mr-2 rounded-md bg-gray-400 text-black btn hover:text-black"
#click="next1(-1)"
>
<i class="fas fa-chevron-left"></i>
</vs-button>
<vs-button
type="filled"
color=" rgba(243, 244, 246)"
class="w-10 mr-2 rounded-md bg-gray-400 text-black btn"
#click="next1(1)"
>
<i class="fas fa-chevron-right"></i>
</vs-button>
</div>
</div>
</div>
</div>
</vs-card>
</div>
</div>
</div>
</template>
I am working with laravel vue pie chart. is there any way to filter the data in the table when click the element of pie chart. For example, when clicked the section pie chart, the table will be filter and display the the data in the table under that section..Any help will be appreciated
It is not possible to point directly to a solution as you have given so little detail. I will still try to explain the logic. For this process, you will get an input from the screen working with Vue.js and you will manipulate a data displayed on Vue.js.
So first; you need to know which part of your pie chart clicked on. I assume the pie chart you are using on your project have some events which triggered when you interact with charts. You will listen that event and catch the value of clicked item.
Now you have the value of clicked item and you need to filter your results by that.
To accomplish that you can use Vue.js Computed Properties and Watchers :https://v2.vuejs.org/v2/guide/computed.html
Lets say you have your data on your Vue.js application:
data () {
return {
clickedItem: null,
itemsOnTable: [ ... ]
}
}
You have all your table content in itemsOnTable and selected item's data in clickedItem
You can use computed to filter your data:
data () {
return {
clickedItem: null,
itemsOnTable: [ ... ]
}
},
computed: {
// filter itemsOnTable if clickedItem have any value
filteredItems: function () {
if(this.clickedItem==null) return this.itemsOnTable;
return this.itemsOnTable.filter(item => item.column = this.clickedItem);
}
}
Now in your Vue.js component you can directly use filteredItems for your table elements v-for
<table>
<tr v-for="items in filteredItems">
<td>{{ item.column }}</td>
<!-- other columns -->
</tr>
</table>
This examples explains basics of interactions and computed properties and aims to help you to understand basics.
I'm storing some files (images, video files, word docs etc.) in storage/app/public folder. Within the public folder, I have 3 folders images, resumes, videos.
Everything works on localhost, but after deploying the site to GoDaddy, when a Candidate is viewing his own profile where he can Edit it of course, none of the files from within the storage folder are displaying anymore and I'm getting 403 errors in the console.
Failed to load resource: the server responded with a status of 403 ()
I properly linked the storage folder in my app, so I'm not sure how to fix this.
I'm using Laravel and Vue js for the front end.
Here is my vue file. At the top is where I'm displaying the Profile on the page and below that is my EditModal Form.
ProfileIndex.vue:
<template>
<div class="col-md-12">
<div class="card">
<div class="card-body">
<div v-if="Object.keys(profiles).length > 0">
<b-row>
<b-col>
<h3 class="card-title">My Profile</h3>
</b-col>
<b-col class="text-right" v-for="(profile, index) in profiles" :key="index">
<button class="btn btn-primary btn-sm text-right" v-on:click="editProfile(profile)"><span class="fa fa-edit"></span> Edit</button>
</b-col>
</b-row>
<b-row v-for="(profile, index) in profiles" :key="index">
<b-col md="3" sm="6" class="mb-3"><strong>Job Title</strong><br>
{{profile.job_title}}
</b-col>
<template v-for="(photo, index) in photos" v-if="photo.file === 'null'">
<b-col md="3" sm="6" class="mb-3"><strong>Photo</strong><br>
<img src="/images/placeholder-square.jpg" alt="" class="w-100px" />
</b-col>
</template>
<template v-else>
<b-col md="3" sm="6" v-for="(photo, index) in photos" :key="index" class="mb-3"><strong>Photo</strong><br>
<img :src="`${$store.state.serverPath}/storage/images/${photo.file}`" alt="" class="w-100px" />
</b-col>
</template>
<b-col md="3" sm="6" class="mb-3"><strong>Date of Birth</strong><br>
{{profile.date_of_birth}}
</b-col>
<b-col md="3" sm="6" class="mb-3"><strong>Employment Type</strong><br>
{{profile.employment_type}}
</b-col>
</b-row>
<b-row class="mt-3">
<b-col md="4" sm="6" v-for="(video, index) in video_one" :key="index" class="mb-3"><strong>Video One</strong><br>
<b-embed
type="video"
aspect="16by9"
:src="`${$store.state.serverPath}/storage/videos/${video.file}`"
allowfullscreen
controls
></b-embed>
</b-col>
<b-col md="4" sm="6" v-for="(video, index) in video_two" :key="index" class="mb-3"><strong>Video Two</strong><br>
<b-embed
type="video"
aspect="16by9"
:src="`${$store.state.serverPath}/storage/videos/${video.file}`"
allowfullscreen
controls
></b-embed>
</b-col>
<b-col md="4" sm="6" v-for="(video, index) in video_three" :key="index" class="mb-3"><strong>Video Three</strong><br>
<b-embed
type="video"
aspect="16by9"
:src="`${$store.state.serverPath}/storage/videos/${video.file}`"
allowfullscreen
controls
></b-embed>
</b-col>
</b-row>
<b-row class="mt-3">
<b-col v-for="(resume, index) in resumes" :key="index" class="mb-3"><strong>Resume</strong><br>
{{resume.file}}
</b-col>
</b-row>
<b-row class="mt-3">
<b-col class="mb-3" v-for="(profile, index) in profiles" :key="index"><strong>Experience</strong><br>
{{profile.experience}}
</b-col>
</b-row>
<b-row class="mt-3">
<b-col class="mb-3" v-for="(profile, index) in profiles" :key="index"><strong>Skills</strong><br>
{{profile.skills}}
</b-col>
</b-row>
</div>
<div v-else>
Your profile doesn't exist yet. Please <router-link to="/candidate/profile/create">create profile.</router-link>
</div>
</div>
</div>
<b-modal ref="editProfileModal" id="modal-1" title="Update Profile" hide-footer>
<form v-on:submit.prevent="updateProfile">
<b-row>
<b-col lg="6" md="6" sm="12">
<b-form-group label="Job Title" label-for="job_title">
<b-form-input
v-model="editProfileData.job_title"
id="job_title"
placeholder="Enter job title"
></b-form-input>
<div class="invalid-feedback" v-if="errors.job_title">{{ errors.job_title[0] }}</div>
</b-form-group>
</b-col>
<b-col lg="6" md="6" sm="12">
<span class="mt-4 d-block text-danger"><strong>Important:</strong> this is how employers will find you.</span>
</b-col>
</b-row>
<b-form-group label="Upload Profile Photo (optional)" label-for="photo_id">
<div v-if="editProfileFiles.photo_id.name">
<img src="" ref="newProfilePhotoDisplay" class="w-130" />
</div>
<b-form-file
v-model="editProfileFiles.photo_id"
id="photo_id"
placeholder="Choose a file..."
accept=".jpg, .jpeg, .png"
ref="newProfilePhoto"
></b-form-file>
</b-form-group>
<b-form-group
label="Date of Birth"
label-for="date-of-birth"
>
<b-form-input
type="date"
v-model="editProfileData.date_of_birth"
id="date-of-birth"
>
</b-form-input>
<div class="invalid-feedback" v-if="errors.date_of_birth">{{ errors.date_of_birth[0] }}</div>
</b-form-group>
<b-form-group
label="Employemnt Type"
label-for="employment-type"
>
<b-form-radio-group
id="employment-type"
v-model="editProfileData.employment_type"
:options="options"
name="employment-type"
>
</b-form-radio-group>
<div class="invalid-feedback" v-if="errors.employment_type">{{ errors.employment_type[0] }}</div>
</b-form-group>
<b-form-group label="Resume" label-for="resume_id">
<b-form-file
v-model="editProfileFiles.resume_id"
id="resume_id"
placeholder="Choose a file..."
#change="editAttachResume"
accept=".doc,.docx"
></b-form-file>
<div class="invalid-feedback" v-if="errors.resume_id">{{ errors.resume_id[0] }}</div>
</b-form-group>
<h4 class="mb-3">Please attach a few short videos (30 seconds max) for a better chance of being noticed. (optional)</h4>
<b-form-group label="1. Tell us a little about yourself: (attach video)" label-for="video_one_id">
<b-form-file
v-model="editProfileFiles.video_one_id"
id="video_one_id"
placeholder="Choose a file..."
#change="editAttachVideoOne"
accept=".mp4, .mpeg4"
></b-form-file>
</b-form-group>
<b-form-group label="2. Tell us about your past work experiences: (attach video)" label-for="video_two_id">
<b-form-file
v-model="editProfileFiles.video_two_id"
id="video_two_id"
placeholder="Choose a file..."
#change="editAttachVideoTwo"
accept=".mp4, .mpeg4"
></b-form-file>
</b-form-group>
<b-form-group label="3. What sets you apart?: (attach video)" label-for="video_three_id">
<b-form-file
v-model="editProfileFiles.video_three_id"
id="video_three_id"
placeholder="Choose a file..."
#change="editAttachVideoThree"
accept=".mp4, .mpeg4"
></b-form-file>
</b-form-group>
<b-form-group label="Experience" label-for="experience">
<b-form-textarea
id="experience"
v-model="editProfileData.experience"
placeholder="Tell us a little about your experience..."
:rows="10"
:max-rows="12"
>
</b-form-textarea>
<div class="invalid-feedback" v-if="errors.experience">{{ errors.experience[0] }}</div>
</b-form-group>
<b-form-group label="Skills" label-for="skills">
<b-form-textarea
id="skills"
v-model="editProfileData.skills"
placeholder="List your skills..."
:rows="4"
:max-rows="6"
>
</b-form-textarea>
<div class="invalid-feedback" v-if="errors.skills">{{ errors.skills[0] }}</div>
</b-form-group>
<b-row>
<b-col class="text-left">
<b-button v-on:click="hideEditProfileModal()" variant="light">Cancel</b-button>
</b-col>
<b-col class="text-right">
<b-button type="submit" variant="success" class="mr-2"
><i class="mdi mdi-check-circle"></i> Update</b-button
>
</b-col>
</b-row>
</form>
</b-modal>
</div>
</template>
<script>
import * as groupedService from '../../../services/grouped_data_service.js';
import * as profileService from '../../../services/candidate_profile_service.js';
export default {
name: "candidateProfileIndex",
data() {
return {
profiles: [],
profile: [],
video_one: [],
video_two: [],
video_three: [],
resumes: [],
photos: [],
options: [
{ text: "Full Time", value: "Full Time" },
{ text: "Part Time", value: "Part Time" },
],
profileData: {
job_title: '',
photo_id: '',
employment_type: "Full Time",
date_of_birth: "",
experience: "",
skills: "",
resume_id: '',
video_one_id: '',
video_two_id: '',
video_three_id: ''
},
editProfileFiles: {
photo_id: [],
resume_id: [],
video_one_id: [],
video_two_id: [],
video_three_id: []
},
editProfileData: {},
errors: {}
};
},
mounted() {
this.loadGroupedData();
},
methods: {
loadGroupedData: async function() {
try {
const response = await groupedService.loadGroupedData();
this.resumes = response.data.resumes;
this.video_one = response.data.video_one;
this.video_two = response.data.video_two;
this.video_three = response.data.video_three;
this.photos = response.data.photos;
this.profiles = response.data.profiles;
} catch (error) {
this.$toast.error("Some error occurred, please refresh!");
}
},
hideEditProfileModal() {
this.$refs.editProfileModal.hide();
},
showEditProfileModal() {
this.$refs.editProfileModal.show();
},
editProfile(profile) {
this.editProfileData = {...profile};
this.showEditProfileModal();
},
editAttachImage() {
this.editProfileFiles.photo_id = this.$refs.newProfilePhoto.files[0];
console.log(this.editProfileFiles.photo_id);
// let reader = new FileReader();
// reader.addEventListener('load', function() {
// this.$refs.newCategoryImageDisplay.src = reader.result;
// }.bind(this), false);
//
// reader.readAsDataURL(this.categoryData.image);
},
editAttachResume(evt) {
const file = evt.target.files[0];
let reader = new FileReader();
reader.addEventListener('load', function() {
}.bind(this), false);
reader.readAsDataURL(file);
},
editAttachVideoOne(evt) {
const file = evt.target.files[0];
let reader = new FileReader();
if (file['size'] < 10485760) {
reader.addEventListener('load', function() {
}.bind(this), false);
reader.readAsDataURL(file);
} else {
this.$toast.error('File exceeds 10 MB limit. Please try again.');
}
},
editAttachVideoTwo(evt) {
const file = evt.target.files[0];
let reader = new FileReader();
if (file['size'] < 10485760) {
reader.addEventListener('load', function() {
}.bind(this), false);
reader.readAsDataURL(file);
} else {
this.$toast.error('File exceeds 10 MB limit. Please try again.');
}
},
editAttachVideoThree(evt) {
const file = evt.target.files[0];
let reader = new FileReader();
if (file['size'] < 10485760) {
reader.addEventListener('load', function() {
}.bind(this), false);
reader.readAsDataURL(file);
} else {
this.$toast.error('File exceeds 10 MB limit. Please try again.');
}
},
updateProfile: async function() {
try {
const formData = new FormData();
formData.append('job_title', this.editProfileData.job_title);
formData.append('photo_id', this.editProfileFiles.photo_id);
formData.append('employment_type', this.editProfileData.employment_type);
formData.append('date_of_birth', this.editProfileData.date_of_birth);
formData.append('experience', this.editProfileData.experience);
formData.append('skills', this.editProfileData.skills);
formData.append('resume_id', this.editProfileFiles.resume_id);
formData.append('video_one_id', this.editProfileFiles.video_one_id);
formData.append('video_two_id', this.editProfileFiles.video_two_id);
formData.append('video_three_id', this.editProfileFiles.video_three_id);
const response = await profileService.updateProfile(this.editProfileData.id, formData);
Object.keys(this.profiles).map(profile => {
if (profile.id == response.data.id) {
for (let key in response.data) {
profile[key] = response.data[key];
}
}
});
this.loadGroupedData();
this.hideEditProfileModal();
this.$toast.success("Profile Updated Successfully!");
} catch (error) {
this.$toast.error(error.response.data.message);
}
},
}
}
</script>