mirror of
				https://github.com/MarcZierle/photo-log-frontend.git
				synced 2025-10-31 09:24:57 +00:00 
			
		
		
		
	add photo picker
This commit is contained in:
		
							parent
							
								
									c97742efd7
								
							
						
					
					
						commit
						e750480fd0
					
				
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/favicon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.9 KiB | 
| @ -4,7 +4,7 @@ | |||||||
|     <meta charset="utf-8"> |     <meta charset="utf-8"> | ||||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge"> |     <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||||
|     <meta name="viewport" content="width=device-width,initial-scale=1.0"> |     <meta name="viewport" content="width=device-width,initial-scale=1.0"> | ||||||
|     <link rel="icon" href="https://www.zierle-training.de/images/152x152/2980389/favicon.png"> |     <link rel="icon" href="favicon.png"> | ||||||
|     <title><%= htmlWebpackPlugin.options.title %></title> |     <title><%= htmlWebpackPlugin.options.title %></title> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|  | |||||||
| @ -13,3 +13,39 @@ const apiClient = axios.create({ | |||||||
| export function getPhotoLogList() { | export function getPhotoLogList() { | ||||||
| 	return apiClient.get('/photologs/') | 	return apiClient.get('/photologs/') | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export function getPhotoLog(id) { | ||||||
|  | 	return apiClient.get('/photolog/'+id+'/') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function addNewPhotoLog(title, date) { | ||||||
|  | 	return apiClient.post('/addphotolog/', { | ||||||
|  | 		title, | ||||||
|  | 		date: date, | ||||||
|  | 		render_date: true, | ||||||
|  | 		start_slide_image: null, | ||||||
|  | 		slides: [] | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function updatePhotoLog({id, title, date, render_date, start_slide_image, slides}) { | ||||||
|  | 	return apiClient.put('/updatephotolog/'+id+'/', { | ||||||
|  | 		title, | ||||||
|  | 		date, | ||||||
|  | 		render_date, | ||||||
|  | 		start_slide_image, | ||||||
|  | 		slides | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function deletePhotoLog(id) { | ||||||
|  | 	return apiClient.delete('/deletephotolog/'+id+'/') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function getPhotoGroups() { | ||||||
|  | 	return apiClient.get('/photogroups/') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function getPhotosByGroup(group_id) { | ||||||
|  | 	return apiClient.get('/photos/?photogroup='+group_id) | ||||||
|  | } | ||||||
							
								
								
									
										157
									
								
								src/components/PhotoSelectModal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/components/PhotoSelectModal.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | |||||||
|  | <!-- eslint-disable vue/no-mutating-props --> | ||||||
|  | <template> | ||||||
|  | 	<n-modal v-model:show="showSelection" :mask-closable=false> | ||||||
|  | 		<n-card | ||||||
|  | 			style="width: 75vw" | ||||||
|  | 			title="Select Photos" | ||||||
|  | 			:bordered="false" | ||||||
|  | 			size="huge" | ||||||
|  | 			role="dialog" | ||||||
|  | 			aria-modal="true" | ||||||
|  | 			> | ||||||
|  | 			<template #header-extra> | ||||||
|  | 				<p v-if="isFinite(max_select) && !or_less"> | ||||||
|  | 					{{num_selected}}/{{max_select}} photo(s) selected | ||||||
|  | 				</p> | ||||||
|  | 				<p v-else-if="isFinite(max_select) && or_less"> | ||||||
|  | 					maximum of {{selecions_left}} photo(s) left | ||||||
|  | 				</p> | ||||||
|  | 				<p v-else> | ||||||
|  | 					{{num_selected}} photo(s) selected | ||||||
|  | 				</p> | ||||||
|  | 			</template> | ||||||
|  | 			<n-scrollbar style="max-height: 80vh;"> | ||||||
|  | 				<n-collapse :default-expanded-names="[first_group_id]"> | ||||||
|  | 					<n-collapse-item v-for="group in sortedPhotoGroups" | ||||||
|  | 						:key="group.id" | ||||||
|  | 						:title="group.name" | ||||||
|  | 						:name="group.id"> | ||||||
|  | 					 | ||||||
|  | 						<n-image-group> | ||||||
|  | 							<n-space> | ||||||
|  | 								<n-image | ||||||
|  | 									v-for="photo in photos[group.id]" | ||||||
|  | 									:key="photo.id" | ||||||
|  | 									width="100" | ||||||
|  | 									:src="photo.cropped_image !== null ? photo.cropped_image : photo.original_image" | ||||||
|  | 									@click="toggle_select_photo(photo.id)" | ||||||
|  | 									:class="{selected: is_photo_selected(photo.id)}" | ||||||
|  | 									preview-disabled /> | ||||||
|  | 							</n-space> | ||||||
|  | 						</n-image-group> | ||||||
|  | 
 | ||||||
|  | 					<template #header-extra>{{group.date}}</template> | ||||||
|  | 					</n-collapse-item> | ||||||
|  | 				</n-collapse> | ||||||
|  | 			</n-scrollbar> | ||||||
|  | 			<template #action> | ||||||
|  | 				<n-space justify="end"> | ||||||
|  | 					<n-button @click="this.$emit('closed')">Cancel</n-button> | ||||||
|  | 					<n-button @click="this.$emit('closed'); this.$emit('selected', this.selection)" type="primary">Select</n-button> | ||||||
|  | 				</n-space> | ||||||
|  | 			</template> | ||||||
|  | 		</n-card> | ||||||
|  | 	</n-modal> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script> | ||||||
|  | import { useMessage } from 'naive-ui' | ||||||
|  | 
 | ||||||
|  | export default { | ||||||
|  | 	name: 'PhotoSelectModal', | ||||||
|  | 	emits: [ 'closed', 'selected' ], | ||||||
|  | 	props: { | ||||||
|  | 		showSelection: { | ||||||
|  | 			type: Boolean, | ||||||
|  | 			required: true, | ||||||
|  | 			default: false | ||||||
|  | 		}, | ||||||
|  | 		max_select: { | ||||||
|  | 			type: Number, | ||||||
|  | 			required: false, | ||||||
|  | 			default: Infinity, | ||||||
|  | 		}, | ||||||
|  | 		or_less: { | ||||||
|  | 			type: Boolean, | ||||||
|  | 			required: false, | ||||||
|  | 			default: true | ||||||
|  | 		}, | ||||||
|  | 		alreadySelected: { | ||||||
|  | 			type: Array, | ||||||
|  | 			required: false, | ||||||
|  | 			default: () => {return []} | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	setup() { | ||||||
|  | 		const message = useMessage() | ||||||
|  | 		return { message } | ||||||
|  | 	}, | ||||||
|  | 	data() { | ||||||
|  | 		return {  | ||||||
|  | 			selection: [], | ||||||
|  | 			photoGroups: [] | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	watch: { | ||||||
|  | 		showSelection: function () { | ||||||
|  | 			if (this.showSelection) { | ||||||
|  | 				this.selection = [...this.alreadySelected] | ||||||
|  | 				this.$store.dispatch('loadPhotoGroups').then(() => { | ||||||
|  | 					this.photoGroups = this.$store.getters.photoGroups | ||||||
|  | 					this.$store.dispatch('loadPhotosInAllGroups') | ||||||
|  | 				}) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	computed: { | ||||||
|  | 		photos() { | ||||||
|  | 			return this.$store.getters.photos | ||||||
|  | 		}, | ||||||
|  | 		num_selected() { | ||||||
|  | 			return this.selection.length | ||||||
|  | 		}, | ||||||
|  | 		selecions_left() { | ||||||
|  | 			return this.max_select - this.num_selected | ||||||
|  | 		}, | ||||||
|  | 		first_group_id() { | ||||||
|  | 			if (this.sortedPhotoGroups.length > 0) | ||||||
|  | 				return this.sortedPhotoGroups[0].id | ||||||
|  | 			return -1 | ||||||
|  | 		}, | ||||||
|  | 		sortedPhotoGroups() { | ||||||
|  | 			return [...this.photoGroups].sort((a,b) => { | ||||||
|  | 				if (a.date === null) return 1 | ||||||
|  | 				if (b.date === null) return -1 | ||||||
|  | 				return a.date > b.date ? -1 : 1 | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	methods: { | ||||||
|  | 		toggle_select_photo(photo_id) { | ||||||
|  | 			if (this.is_photo_selected(photo_id)) { | ||||||
|  | 				const index = this.selection.indexOf(photo_id) | ||||||
|  | 				this.selection.splice(index, 1)	 | ||||||
|  | 			} else { | ||||||
|  | 				if (this.selecions_left > 0) { | ||||||
|  | 					this.selection.push(photo_id) | ||||||
|  | 				} else { | ||||||
|  | 					this.message.error('You can only select ' + this.max_select + ' photo(s)') | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		is_photo_selected(photo_id) { | ||||||
|  | 			return this.selection.includes(photo_id) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style scoped> | ||||||
|  | .n-image { | ||||||
|  | 	cursor: pointer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .selected { | ||||||
|  | 	opacity: 0.5; | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @ -17,9 +17,16 @@ const routes = [ | |||||||
| 		component: LogsList | 		component: LogsList | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		path: '/logs/create', | 		path: '/logs/create/:e?', | ||||||
| 		name: 'CreateLog', | 		name: 'CreateLog', | ||||||
| 		component: CreateLog | 		component: CreateLog, | ||||||
|  | 		props: (route) => { | ||||||
|  | 			const e = Number.parseInt(route.params.e) | ||||||
|  | 			if (Number.isNaN(e)) { | ||||||
|  | 				return '' | ||||||
|  | 			} | ||||||
|  | 			return {e} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,22 +1,142 @@ | |||||||
| import { createStore } from 'vuex' | import { createStore } from 'vuex' | ||||||
| import { getPhotoLogList } from '@/api' | import {  | ||||||
|  | 	getPhotoLogList, | ||||||
|  | 	deletePhotoLog, | ||||||
|  | 	addNewPhotoLog, | ||||||
|  | 	getPhotoLog, | ||||||
|  | 	updatePhotoLog, | ||||||
|  | 	getPhotoGroups, | ||||||
|  | 	getPhotosByGroup | ||||||
|  | } from '@/api' | ||||||
| 
 | 
 | ||||||
| export default createStore({ | export default createStore({ | ||||||
| 	state: { | 	state: { | ||||||
| 		photoLogList: [] | 		photoLogList: [], | ||||||
|  | 		photoLogs: [], | ||||||
|  | 		photoGroups: [], | ||||||
|  | 		photos: [] | ||||||
| 	}, | 	}, | ||||||
| 	mutations: { | 	mutations: { | ||||||
| 		SET_PHOTO_LOG_LIST(state, newPhotoLogList) { | 		SET_PHOTO_LOG_LIST(state, newPhotoLogList) { | ||||||
| 			state.photoLogList = newPhotoLogList | 			state.photoLogList = newPhotoLogList | ||||||
|  | 		}, | ||||||
|  | 		SET_PHOTO_LOG(state, photoLog) { | ||||||
|  | 			let log_index = state.photoLogs.findIndex(log => log.id === photoLog.id) | ||||||
|  | 			if (log_index > -1) { | ||||||
|  | 				state.photoLogs[log_index] = photoLog | ||||||
|  | 			} else { | ||||||
|  | 				state.photoLogs.push(photoLog) | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		REMOVE_PHOTO_LOG(state, id) { | ||||||
|  | 			let log_index = state.photoLogList.findIndex(log => log.id === id) | ||||||
|  | 			state.photoLogList.splice(log_index, 1) | ||||||
|  | 		}, | ||||||
|  | 		SET_PHOTO_GROUPS(state, groups) { | ||||||
|  | 			state.photoGroups = groups | ||||||
|  | 		}, | ||||||
|  | 		SET_PHOTOS_IN_GROUP(state, {group_id, photos}) { | ||||||
|  | 			if (group_id in state.photos) { | ||||||
|  | 				state.photos.group_id = photos | ||||||
|  | 			} else { | ||||||
|  | 				state.photos = {...state.photos, [group_id]: photos} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	actions: { | 	actions: { | ||||||
| 		loadPhotoLogList({commit}) { | 		loadPhotoLogList({commit}) { | ||||||
| 			getPhotoLogList().then((response) => { | 			return new Promise((resolve, reject) => { | ||||||
| 				commit('SET_PHOTO_LOG_LIST', response.data) | 				getPhotoLogList().then((response) => { | ||||||
|  | 					commit('SET_PHOTO_LOG_LIST', response.data) | ||||||
|  | 					resolve() | ||||||
|  | 				}).catch((error) => { | ||||||
|  | 					console.log(error) | ||||||
|  | 					reject() | ||||||
|  | 				}) | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		loadPhotoLog({commit}, id) { | ||||||
|  | 			return new Promise((resolve, reject) => { | ||||||
|  | 				getPhotoLog(id).then((response) => { | ||||||
|  | 					commit('SET_PHOTO_LOG', response.data) | ||||||
|  | 					resolve() | ||||||
|  | 				}).catch((error) => { | ||||||
|  | 					console.log(error) | ||||||
|  | 					reject() | ||||||
|  | 				}) | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		deletePhotoLog({commit}, id) { | ||||||
|  | 			deletePhotoLog(id).then(() => { | ||||||
|  | 				commit('REMOVE_PHOTO_LOG', id) | ||||||
| 			}).catch((error) => { | 			}).catch((error) => { | ||||||
| 				console.log(error) | 				console.log(error) | ||||||
| 			}) | 			}) | ||||||
|  | 		}, | ||||||
|  | 		addNewPhotoLog({dispatch}, {title, date}) { | ||||||
|  | 			return new Promise((resolve, reject) => { | ||||||
|  | 				addNewPhotoLog(title, date).then((response) => { | ||||||
|  | 					dispatch('loadPhotoLogList') | ||||||
|  | 					resolve(response.data.id) | ||||||
|  | 				}).catch((error) => { | ||||||
|  | 					console.log(error) | ||||||
|  | 					reject(error) | ||||||
|  | 				}) | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		updatePhotoLogDetails({commit}, photolog) { | ||||||
|  | 			if (photolog !== null) { | ||||||
|  | 				commit('SET_PHOTO_LOG', photolog) | ||||||
|  | 				return updatePhotoLog(photolog) | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		loadPhotoGroups({commit}) { | ||||||
|  | 			return new Promise((resolve, reject) => { | ||||||
|  | 				getPhotoGroups().then((response) => { | ||||||
|  | 					commit('SET_PHOTO_GROUPS', response.data) | ||||||
|  | 					resolve(response.data) | ||||||
|  | 				}).catch((error) => { | ||||||
|  | 					reject(error) | ||||||
|  | 				}) | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		loadPhotosInGroup({commit}, group_id) { | ||||||
|  | 			return new Promise((resolve, reject) => { | ||||||
|  | 				getPhotosByGroup(group_id).then((response) => { | ||||||
|  | 					commit('SET_PHOTOS_IN_GROUP', {group_id, photos: response.data}) | ||||||
|  | 					resolve(response.data) | ||||||
|  | 				}).catch((error) => { | ||||||
|  | 					reject(error) | ||||||
|  | 				}) | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		loadPhotosInAllGroups({dispatch, getters}) { | ||||||
|  | 			for (const index in getters.photoGroups) { | ||||||
|  | 				const group_id = getters.photoGroups[index].id | ||||||
|  | 				dispatch('loadPhotosInGroup', group_id) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	getters: { | ||||||
|  | 		photoLogById: (state) => (id) =>  { | ||||||
|  | 			let log = state.photoLogList.filter(log => log.id == id) | ||||||
|  | 			if (log.length > 0) { | ||||||
|  | 				return log[0] | ||||||
|  | 			} | ||||||
|  | 			return null | ||||||
|  | 		}, | ||||||
|  | 		photoLogDetailsById: (state) => (id) =>  { | ||||||
|  | 			let log = state.photoLogs.filter(log => log.id == id) | ||||||
|  | 			if (log.length > 0) { | ||||||
|  | 				return log[0] | ||||||
|  | 			} | ||||||
|  | 			return null | ||||||
|  | 		}, | ||||||
|  | 		photoGroups (state) { | ||||||
|  | 			return state.photoGroups | ||||||
|  | 		}, | ||||||
|  | 		photos (state) { | ||||||
|  | 			return state.photos | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	modules: {}, | 	modules: {}, | ||||||
|  | |||||||
| @ -1,14 +1,278 @@ | |||||||
| <template> | <template> | ||||||
| 	<h1>Create Log</h1> | 	<div> | ||||||
|  | 		<n-space justify="space-between"> | ||||||
|  | 			<h1>Create Log</h1> | ||||||
|  | 			<n-button type="primary">Generate</n-button> | ||||||
|  | 		</n-space> | ||||||
|  | 		{{start_slide_image}} | ||||||
|  | 		{{slides}} | ||||||
|  | 
 | ||||||
|  | 		<n-space justify="space-around"> | ||||||
|  | 			<n-input size="large" round placeholder="Photo Log title" v-model:value="title" @change="updateServerData" /> | ||||||
|  | 			<n-date-picker v-model:value="date" type="date" @update:value="updateServerData" /> | ||||||
|  | 		</n-space> | ||||||
|  | 
 | ||||||
|  | 		<n-divider title-placement="center">Slides</n-divider> | ||||||
|  | 
 | ||||||
|  | 		<n-space vertical> | ||||||
|  | 			<n-card | ||||||
|  | 				style="width: 80%;" | ||||||
|  | 				v-for="(slide, index) in editSlides" :key="index" | ||||||
|  | 				:title="'#'+(index+1)" > | ||||||
|  | 
 | ||||||
|  | 				<n-image-group> | ||||||
|  | 					<n-space> | ||||||
|  | 						<n-image | ||||||
|  | 							v-for="(photo_id, photoIndex) in slide" :key="photoIndex" | ||||||
|  | 							width="100" | ||||||
|  | 							:src="getPhotoSrcById(photo_id)" | ||||||
|  | 							/> | ||||||
|  | 						 | ||||||
|  | 						<n-button round dashed type="info" @click="selectPhotosForSlide(index)"> Edit </n-button> | ||||||
|  | 					</n-space> | ||||||
|  | 				</n-image-group> | ||||||
|  | 
 | ||||||
|  | 				 | ||||||
|  | 			</n-card> | ||||||
|  | 		</n-space> | ||||||
|  | 
 | ||||||
|  | 		<PhotoSelectModal | ||||||
|  | 			v-model:showSelection="selectPhotosModal" | ||||||
|  | 			@closed="selectPhotosModal=false" | ||||||
|  | 			@selected="addPhotosToSlide" | ||||||
|  | 			:max_select=max_photos_per_slide :or_less=true | ||||||
|  | 			:already-selected=editSlides[selectedSlide] /> | ||||||
|  | 
 | ||||||
|  | 		<n-modal v-model:show="showCreateModal" :mask-closable=false> | ||||||
|  | 			<n-spin :show="isCreateLoading"> | ||||||
|  | 				<n-card | ||||||
|  | 					style="width: 600px;" | ||||||
|  | 					title="Create a new Photo Log" | ||||||
|  | 					:bordered="false" | ||||||
|  | 					size="huge" | ||||||
|  | 					role="dialog" | ||||||
|  | 					aria-modal="true" | ||||||
|  | 					> | ||||||
|  | 
 | ||||||
|  | 					<n-form-item label="What's the name of the photo log?" path="title"> | ||||||
|  | 						<n-input v-model:value="title" type="text" placeholder="Photo Log title" /> | ||||||
|  | 					</n-form-item> | ||||||
|  | 					<n-form-item label="When did the training take place?" path="date"> | ||||||
|  | 						<n-date-picker v-model:value="date" type="date" clearable /> | ||||||
|  | 					</n-form-item> | ||||||
|  | 
 | ||||||
|  | 					<template #footer> | ||||||
|  | 						<n-space justify="end"> | ||||||
|  | 							<n-button @click="navigateBack">Cancel</n-button> | ||||||
|  | 							<n-button @click="createNewPhotoLog" type="success">Create</n-button> | ||||||
|  | 						</n-space> | ||||||
|  | 					</template> | ||||||
|  | 				 | ||||||
|  | 				</n-card> | ||||||
|  | 			</n-spin> | ||||||
|  | 		</n-modal> | ||||||
|  | 	</div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
| import { useMeta } from 'vue-meta' | import { useMeta } from 'vue-meta' | ||||||
|  | import { useMessage } from 'naive-ui' | ||||||
|  | 
 | ||||||
|  | import PhotoSelectModal from '@/components/PhotoSelectModal' | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
| 	name: 'CreateLog', | 	name: 'CreateLog', | ||||||
|  | 	components: { | ||||||
|  | 		PhotoSelectModal, | ||||||
|  | 	}, | ||||||
|  | 	props: { | ||||||
|  | 		e: { | ||||||
|  | 			type: Number, | ||||||
|  | 			required: false, | ||||||
|  | 			default: -1, | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			id: Number.parseInt(this.e), | ||||||
|  | 			title: '', | ||||||
|  | 			date: null, | ||||||
|  | 			render_date: false, | ||||||
|  | 			start_slide_image: null, | ||||||
|  | 			slides: [], | ||||||
|  | 
 | ||||||
|  | 			selectPhotosModal: false, | ||||||
|  | 			selectedSlide: null, | ||||||
|  | 			max_photos_per_slide: 3, | ||||||
|  | 			 | ||||||
|  | 			isLoadingData: false, | ||||||
|  | 			isCreateLoading: false, | ||||||
|  | 			isSavingServer: false, | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
| 	setup() { | 	setup() { | ||||||
| 		useMeta({ title: 'Create a new Photo Log' }) | 		useMeta({ title: 'Create a new Photo Log' }) | ||||||
|  | 		const message = useMessage() | ||||||
|  | 		return { message } | ||||||
| 	}, | 	}, | ||||||
|  | 	mounted() { | ||||||
|  | 		if (this.isValidId()) { | ||||||
|  | 			this.isLoadingData = true | ||||||
|  | 
 | ||||||
|  | 			this.$store.dispatch('loadPhotoGroups').then(() => { | ||||||
|  | 				this.photoGroups = this.$store.getters.photoGroups | ||||||
|  | 				this.$store.dispatch('loadPhotosInAllGroups') | ||||||
|  | 			}) | ||||||
|  | 
 | ||||||
|  | 			this.findPhotoLog().then(() => { | ||||||
|  | 				this.updateLocalData() | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	computed: { | ||||||
|  | 		editSlides() { | ||||||
|  | 			return [...this.slides, []] | ||||||
|  | 		}, | ||||||
|  | 		photos() { | ||||||
|  | 			return this.$store.getters.photos | ||||||
|  | 		}, | ||||||
|  | 		showCreateModal () { | ||||||
|  | 			return !this.isValidId() | ||||||
|  | 		}, | ||||||
|  | 		dateStr () { | ||||||
|  | 			if (this.date !== null) { | ||||||
|  | 				let date_obj = new Date(this.date) | ||||||
|  | 				let month = Number.parseInt(date_obj.getMonth())+1 | ||||||
|  | 				month = month < 10 ? '0' + month : month | ||||||
|  | 				let day = Number.parseInt(date_obj.getDate()) | ||||||
|  | 				day = day < 10 ? '0' + day : day | ||||||
|  | 				let date_str = date_obj.getFullYear() + '-' + month + '-' + day | ||||||
|  | 				return date_str | ||||||
|  | 			} | ||||||
|  | 			return '1970-01-01' | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	methods: { | ||||||
|  | 		selectPhotosForSlide(slide_index) { | ||||||
|  | 			this.selectedSlide = slide_index | ||||||
|  | 			this.selectPhotosModal = true | ||||||
|  | 		}, | ||||||
|  | 		getPhotoSrcById(photo_id){ | ||||||
|  | 			for (const index in this.photos) { | ||||||
|  | 				let group = this.photos[index] | ||||||
|  | 				let photo = group.filter((photo) => photo.id == photo_id) | ||||||
|  | 				if (photo.length > 0) { | ||||||
|  | 					photo = photo[0] | ||||||
|  | 					return photo.cropped_image !== null ? photo.cropped_image : photo.original_image | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return null | ||||||
|  | 		}, | ||||||
|  | 		addPhotosToSlide(selected_photos) { | ||||||
|  | 			this.slides[this.selectedSlide] = selected_photos | ||||||
|  | 			this.updateServerData() | ||||||
|  | 		}, | ||||||
|  | 		navigateBack() { | ||||||
|  | 			this.$router.go(-1) | ||||||
|  | 		}, | ||||||
|  | 		createNewPhotoLog() { | ||||||
|  | 			if (this.title.length > 0 && this.date !== null) { | ||||||
|  | 				this.isCreateLoading = true | ||||||
|  | 				this.$store.dispatch('addNewPhotoLog', {title:this.title, date:this.dateStr}).then(id => { | ||||||
|  | 					if (id > -1 && id !== null) { | ||||||
|  | 						this.id = id | ||||||
|  | 						this.$router.push({name: 'CreateLog', params: {e: id}}) | ||||||
|  | 					} else { | ||||||
|  | 						this.message.error('Something went wrong. Please try again later.') | ||||||
|  | 					} | ||||||
|  | 				}).finally(() => { | ||||||
|  | 					this.isCreateLoading = false | ||||||
|  | 				}) | ||||||
|  | 			} else { | ||||||
|  | 				if (this.title.length <= 0) | ||||||
|  | 					this.message.error('Please enter a title') | ||||||
|  | 				if (this.date === null) | ||||||
|  | 					this.message.error('Please enter a date') | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		isValidId() { | ||||||
|  | 			return !( | ||||||
|  | 				this.id == null | ||||||
|  | 				|| Number.isNaN(this.id) | ||||||
|  | 				|| this.id <= 0 | ||||||
|  | 				|| this.id === undefined | ||||||
|  | 			) | ||||||
|  | 		}, | ||||||
|  | 		findPhotoLog() { | ||||||
|  | 			return new Promise((resolve, reject) => { | ||||||
|  | 				let found_log = this.$store.getters.photoLogById(this.id) | ||||||
|  | 				if (found_log === null) { | ||||||
|  | 					this.$store.dispatch('loadPhotoLogList').then(() => { | ||||||
|  | 						found_log = this.$store.getters.photoLogById(this.id) | ||||||
|  | 						if (found_log === null) { | ||||||
|  | 							this.message.error('Photo Log could not be found') | ||||||
|  | 							reject() | ||||||
|  | 						} else { | ||||||
|  | 							resolve() | ||||||
|  | 						} | ||||||
|  | 					}).catch(() => { | ||||||
|  | 						reject() | ||||||
|  | 					}) | ||||||
|  | 				} else { | ||||||
|  | 					resolve() | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		updateLocalData() { | ||||||
|  | 			let found_log = null | ||||||
|  | 			this.$store.dispatch('loadPhotoLog', this.id).then(() => { | ||||||
|  | 				found_log = this.$store.getters.photoLogDetailsById(this.id) | ||||||
|  | 				if (found_log !== null) { | ||||||
|  | 					this.title = found_log.title | ||||||
|  | 					this.date = new Date(found_log.date).getTime() | ||||||
|  | 					this.render_date = found_log.render_date | ||||||
|  | 					this.start_slide_image = found_log.start_slide_image | ||||||
|  | 					this.slides = found_log.slides | ||||||
|  | 					this.isLoadingData = false | ||||||
|  | 				} else { | ||||||
|  | 					this.message.error('Photo Log could not be found') | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		updateServerData() { | ||||||
|  | 			this.isSavingServer = true | ||||||
|  | 			this.$store.dispatch('updatePhotoLogDetails', { | ||||||
|  | 				id: this.id, | ||||||
|  | 				title: this.title, | ||||||
|  | 				date: this.dateStr, | ||||||
|  | 				render_date: this.render_date, | ||||||
|  | 				start_slide_image: this.start_slide_image, | ||||||
|  | 				slides: this.slides | ||||||
|  | 			}).then(() => { | ||||||
|  | 				this.message.success('Changes saved') | ||||||
|  | 			}).finally(() => { | ||||||
|  | 				this.isSavingServer = false | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	beforeRouteUpdate (to) { | ||||||
|  | 		this.id = Number.parseInt(to.params.e) | ||||||
|  | 		if (this.isValidId()) { | ||||||
|  | 			this.isLoadingData = true | ||||||
|  | 			this.findPhotoLog().then(()=> { | ||||||
|  | 				this.updateLocalData() | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	// eslint-disable-next-line no-unused-vars | ||||||
|  | 	beforeRouteLeave (to, from) { | ||||||
|  | 		// prevent from leaving with unsaved changes | ||||||
|  | 	} | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
|  | 
 | ||||||
|  | <style scoped> | ||||||
|  | .n-input { | ||||||
|  | 	min-width: 30em; | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @ -9,7 +9,9 @@ | |||||||
| 			</thead> | 			</thead> | ||||||
| 			<tbody> | 			<tbody> | ||||||
| 				<tr v-for="photolog in photoLogList" :key="photolog.id"> | 				<tr v-for="photolog in photoLogList" :key="photolog.id"> | ||||||
| 					<td>{{ photolog.title }}</td> | 					<router-link :to="{name: 'CreateLog', params: {e: photolog.id}}"> | ||||||
|  | 						<td>{{ photolog.title }}</td> | ||||||
|  | 					</router-link> | ||||||
| 					<td>{{ photolog.date }}</td> | 					<td>{{ photolog.date }}</td> | ||||||
| 					<td> | 					<td> | ||||||
| 						<n-button type="error" @click="askDeleteLog(photolog.id)">Delete</n-button> | 						<n-button type="error" @click="askDeleteLog(photolog.id)">Delete</n-button> | ||||||
| @ -72,7 +74,10 @@ export default { | |||||||
| 			this.deleteModalContent = 'Do you want to permanently delete "' + logtitle + '"?' | 			this.deleteModalContent = 'Do you want to permanently delete "' + logtitle + '"?' | ||||||
| 		}, | 		}, | ||||||
| 		deleteLog() { | 		deleteLog() { | ||||||
| 			console.log('delete ' + this.deleteId) | 			if (this.deleteId !== null) { | ||||||
|  | 				this.$store.dispatch('deletePhotoLog', this.deleteId) | ||||||
|  | 				this.deleteId = null | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 MarcZierle
						MarcZierle