Added counts to each category
Counts update on certain events and show or hide various elements Fixed various little ui element issues fixes #6
This commit is contained in:
		@@ -13,6 +13,7 @@
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
// import io from 'socket.io-client'
 | 
			
		||||
import axios from 'axios'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	components: {
 | 
			
		||||
@@ -50,7 +51,6 @@ export default {
 | 
			
		||||
 | 
			
		||||
	},
 | 
			
		||||
	mounted: function(){
 | 
			
		||||
		
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		loggedIn () {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html {
 | 
			
		||||
	scrollbar-width: none;
 | 
			
		||||
	/*scrollbar-width: none;*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
div.ui.basic.segment.no-fluf-segment {
 | 
			
		||||
 
 | 
			
		||||
@@ -192,6 +192,7 @@
 | 
			
		||||
						this.unfolded = false
 | 
			
		||||
						setTimeout( () => {
 | 
			
		||||
							this.visible = false
 | 
			
		||||
							this.$store.dispatch('fetchAndUpdateUserTotals')
 | 
			
		||||
						}, 600)
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
 
 | 
			
		||||
@@ -68,6 +68,7 @@
 | 
			
		||||
						const imageCode = `<img alt="image" src="/api/static/thumb_${location}">`
 | 
			
		||||
 | 
			
		||||
						this.$bus.$emit('new_file_upload', {noteId: this.noteId, imageCode})
 | 
			
		||||
						this.$store.dispatch('fetchAndUpdateUserTotals')
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
				.catch(results => {
 | 
			
		||||
 
 | 
			
		||||
@@ -154,6 +154,7 @@
 | 
			
		||||
			<div class="menu-section" v-if="loggedIn">
 | 
			
		||||
				<router-link exact-active-class="active" class="menu-item menu-button" to="/notes" v-on:click.native="emitReloadEvent()">
 | 
			
		||||
					<i class="file outline icon"></i>Notes
 | 
			
		||||
					<!-- <span v-if="$store.getters.totals">{{ $store.getters.totals['totalNotes'] }}</span> -->
 | 
			
		||||
				</router-link>
 | 
			
		||||
				<div>
 | 
			
		||||
					<!-- <div class="menu-item sub">Show Only <i class="caret down icon"></i></div> -->
 | 
			
		||||
@@ -163,21 +164,10 @@
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="menu-section" v-if="loggedIn">
 | 
			
		||||
				<div v-on:click="updateFastFilters(3)" class="menu-item menu-button">
 | 
			
		||||
					<i class="mail outline icon"></i>Inbox
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="menu-section" v-if="loggedIn">
 | 
			
		||||
				<div v-on:click="updateFastFilters(2)" class="menu-item menu-button">
 | 
			
		||||
					<i class="hdd outline icon"></i>Archived
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="menu-section" v-if="loggedIn">
 | 
			
		||||
			<div class="menu-section" v-if="loggedIn && $store.getters.totals && $store.getters.totals['totalFiles']">
 | 
			
		||||
				<router-link class="menu-item menu-button" exact-active-class="active" to="/attachments">
 | 
			
		||||
					<i class="folder open outline icon"></i>Files
 | 
			
		||||
					<!-- <span>{{ $store.getters.totals['totalFiles'] }}</span> -->
 | 
			
		||||
				</router-link>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
@@ -242,6 +232,8 @@
 | 
			
		||||
			this.mobile = this.$store.getters.getIsUserOnMobile
 | 
			
		||||
			this.collapsed = this.$store.getters.getIsUserOnMobile
 | 
			
		||||
 | 
			
		||||
			// {{ totals['totalNotes'] }}
 | 
			
		||||
 | 
			
		||||
			if(this.mobile){
 | 
			
		||||
				this.menuOpen = false
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@
 | 
			
		||||
				axios.post('/api/note/delete', {'noteId':this.noteId}).then(response => {
 | 
			
		||||
					if(response.data == true){
 | 
			
		||||
						this.$bus.$emit('note_deleted', this.noteId)
 | 
			
		||||
						this.$store.dispatch('fetchAndUpdateUserTotals')
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
			},
 | 
			
		||||
 
 | 
			
		||||
@@ -202,6 +202,7 @@
 | 
			
		||||
				loading: true,
 | 
			
		||||
				loadingMessage: 'Loading Note',
 | 
			
		||||
				currentNoteId: 0,
 | 
			
		||||
				modified: false,
 | 
			
		||||
				noteText: '',
 | 
			
		||||
				rawTextId: 0,
 | 
			
		||||
				shareUsername: null,
 | 
			
		||||
@@ -873,21 +874,16 @@
 | 
			
		||||
						'archived':this.archived,
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					let vm = this
 | 
			
		||||
					//Debounce save to prevent spamming
 | 
			
		||||
					// clearTimeout(this.saveDebounce)
 | 
			
		||||
					// this.saveDebounce = setTimeout(() => {
 | 
			
		||||
						//Only notify user if saving - may help with debugging in the future
 | 
			
		||||
						vm.statusText = 'Saving'
 | 
			
		||||
						axios.post('/api/note/update', postData).then( response => {
 | 
			
		||||
							vm.statusText = 'Saved'
 | 
			
		||||
							vm.updated = Math.round((+new Date)/1000)
 | 
			
		||||
					this.statusText = 'Saving'
 | 
			
		||||
					axios.post('/api/note/update', postData).then( response => {
 | 
			
		||||
						this.statusText = 'Saved'
 | 
			
		||||
						this.updated = Math.round((+new Date)/1000)
 | 
			
		||||
						this.modified = true
 | 
			
		||||
 | 
			
		||||
							//Update last saved note hash
 | 
			
		||||
							vm.lastNoteHash = vm.hashString( currentNoteText )
 | 
			
		||||
							return resolve(true)
 | 
			
		||||
						})
 | 
			
		||||
					// }, 300)
 | 
			
		||||
						//Update last saved note hash
 | 
			
		||||
						this.lastNoteHash = this.hashString( currentNoteText )
 | 
			
		||||
						return resolve(true)
 | 
			
		||||
					})
 | 
			
		||||
				})
 | 
			
		||||
			},
 | 
			
		||||
			checkForUpdatedNote(){
 | 
			
		||||
@@ -949,7 +945,9 @@
 | 
			
		||||
					this.sizeDown = true
 | 
			
		||||
					//This timeout allows animation to play before closing 
 | 
			
		||||
					setTimeout(() => {
 | 
			
		||||
						this.$bus.$emit('close_active_note', {position: this.position, noteId: this.noteid})
 | 
			
		||||
						this.$bus.$emit('close_active_note', {
 | 
			
		||||
							position: this.position, noteId: this.noteid, modified: this.modified
 | 
			
		||||
						})
 | 
			
		||||
						return
 | 
			
		||||
					}, 300)
 | 
			
		||||
				})
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="ui form">
 | 
			
		||||
		<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes and Files" />
 | 
			
		||||
		<div class="ui left icon fluid input">
 | 
			
		||||
			<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes and Files" />
 | 
			
		||||
			<i class="search icon"></i>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,6 @@
 | 
			
		||||
 | 
			
		||||
			if(this.styleObject && this.styleObject.noteBackground){
 | 
			
		||||
				this.bgColor = this.styleObject.noteBackground
 | 
			
		||||
				console.log(this.bgColor)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			
 | 
			
		||||
 
 | 
			
		||||
@@ -3,21 +3,39 @@
 | 
			
		||||
		
 | 
			
		||||
		<div class="ui grid" :class="{ 'mush-it-up':showOneColumn() }" ref="content">
 | 
			
		||||
 | 
			
		||||
			<div v-if="!$store.getters.getIsUserOnMobile" 
 | 
			
		||||
				:class="{ 'sixteen wide column':showOneColumn(), 'twelve wide column':!showOneColumn() }">
 | 
			
		||||
			<div v-if="!$store.getters.getIsUserOnMobile" class="sixteen wide column">
 | 
			
		||||
				<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
 | 
			
		||||
				
 | 
			
		||||
				<div class="ui grid">
 | 
			
		||||
 | 
			
		||||
					<div class="eight wide column">
 | 
			
		||||
						<search-input></search-input>
 | 
			
		||||
					</div>
 | 
			
		||||
					
 | 
			
		||||
					<div class="eight wide column">
 | 
			
		||||
 | 
			
		||||
						<div class="ui basic button" v-on:click="updateFastFilters(3)" v-if="$store.getters.totals && $store.getters.totals['sharedToNotes'] > 0" style="position: relative;">
 | 
			
		||||
							<i class="green mail icon"></i>Inbox
 | 
			
		||||
							<span class="floating ui green label" v-if="$store.getters.totals['unreadNotes'] > 0">
 | 
			
		||||
								{{ $store.getters.totals['unreadNotes'] }}
 | 
			
		||||
							</span>
 | 
			
		||||
						</div>
 | 
			
		||||
 | 
			
		||||
						<div class="ui basic button" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
 | 
			
		||||
							<i class="green archive icon"></i>Archived
 | 
			
		||||
							<!-- <span>{{ $store.getters.totals['archivedNotes'] }}</span> -->
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div class="eight wide column" v-if="showClear">
 | 
			
		||||
						<!-- <fast-filters /> -->
 | 
			
		||||
						<span class="ui fluid green button" 
 | 
			
		||||
							v-if="showClear"
 | 
			
		||||
							
 | 
			
		||||
							@click="reset">
 | 
			
		||||
							<i class="arrow circle left icon"></i>Back to All Notes
 | 
			
		||||
						</span>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
			</div>
 | 
			
		||||
@@ -64,7 +82,7 @@
 | 
			
		||||
					<!-- pinned notes -->
 | 
			
		||||
					<div v-if="containsPinnednotes > 0" class="note-card-section">
 | 
			
		||||
						<!-- ({{containsPinnednotes}}) -->
 | 
			
		||||
						<h4><i class="green pin icon"></i>Pinned <span v-if="!working"></span></h4>
 | 
			
		||||
						<h4><i class="green pin icon"></i>Pinned</h4>
 | 
			
		||||
						<div class="note-card-display-area">
 | 
			
		||||
							<note-title-display-card 
 | 
			
		||||
								v-for="note in notes"
 | 
			
		||||
@@ -80,7 +98,7 @@
 | 
			
		||||
					<!-- normal notes  -->
 | 
			
		||||
					<div v-if="containsNormalNotes > 0" class="note-card-section">
 | 
			
		||||
						<!-- ({{containsNormalNotes}}) -->
 | 
			
		||||
						<h4><i class="green file icon"></i>Notes <span v-if="!working"></span></h4>
 | 
			
		||||
						<h4><i class="green file icon"></i>Notes</h4>
 | 
			
		||||
						<div class="note-card-display-area">
 | 
			
		||||
							<note-title-display-card 
 | 
			
		||||
								v-for="note in notes"
 | 
			
		||||
@@ -194,9 +212,16 @@
 | 
			
		||||
 | 
			
		||||
			this.$parent.loginGateway()
 | 
			
		||||
 | 
			
		||||
			this.$bus.$on('close_active_note', ({position, noteId}) => {
 | 
			
		||||
			//Update totals for app
 | 
			
		||||
			this.$store.dispatch('fetchAndUpdateUserTotals')
 | 
			
		||||
 | 
			
		||||
			this.$bus.$on('close_active_note', ({position, noteId, modified}) => {
 | 
			
		||||
				this.closeNote(position)
 | 
			
		||||
				this.updateSingleNote(noteId)
 | 
			
		||||
				this.$store.dispatch('fetchAndUpdateUserTotals')
 | 
			
		||||
				if(modified){
 | 
			
		||||
					this.updateSingleNote(noteId)
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
			})
 | 
			
		||||
			this.$bus.$on('note_deleted', (noteId) => {
 | 
			
		||||
				//Remove deleted note from set, its deleted
 | 
			
		||||
@@ -265,6 +290,7 @@
 | 
			
		||||
			// this.$bus.$off()
 | 
			
		||||
		},
 | 
			
		||||
		mounted() {
 | 
			
		||||
 | 
			
		||||
			//Loads initial batch and tags
 | 
			
		||||
			this.reset()
 | 
			
		||||
		},
 | 
			
		||||
@@ -634,6 +660,31 @@
 | 
			
		||||
						resolve(data)
 | 
			
		||||
					})
 | 
			
		||||
				})
 | 
			
		||||
			},
 | 
			
		||||
			updateFastFilters(index){
 | 
			
		||||
 | 
			
		||||
				//clear out tags
 | 
			
		||||
				this.searchTags = []
 | 
			
		||||
 | 
			
		||||
				//A little hacky, brings user to notes page then filters on click
 | 
			
		||||
				if(this.$route.name != 'NotesPage'){
 | 
			
		||||
					this.$router.push('/notes')
 | 
			
		||||
					setTimeout( () => {
 | 
			
		||||
						this.updateFastFilters(index)
 | 
			
		||||
					}, 500 )
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				const options = [
 | 
			
		||||
					'withLinks', // 'Only Show Notes with Links'
 | 
			
		||||
					'withTags', // 'Only Show Notes with Tags'
 | 
			
		||||
					'onlyArchived', //'Only Show Archived Notes'
 | 
			
		||||
					'onlyShowSharedNotes', //Only show shared notes
 | 
			
		||||
				]
 | 
			
		||||
 | 
			
		||||
				let filter = {}
 | 
			
		||||
				filter[options[index]] = 1
 | 
			
		||||
 | 
			
		||||
				this.$bus.$emit('update_fast_filters', filter)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ export default new Vuex.Store({
 | 
			
		||||
		isUserOnMobile: false,
 | 
			
		||||
		isNoteSettingsOpen: false, //Little note settings pane
 | 
			
		||||
		socket: null,
 | 
			
		||||
		userTotals: null,
 | 
			
		||||
	},
 | 
			
		||||
	mutations: {
 | 
			
		||||
		setLoginToken(state, userData){
 | 
			
		||||
@@ -88,6 +89,14 @@ export default new Vuex.Store({
 | 
			
		||||
			//Put socket id in axios headers
 | 
			
		||||
			axios.defaults.headers.common['socketId'] = socket
 | 
			
		||||
			state.socket = socket
 | 
			
		||||
		},
 | 
			
		||||
		setUserTotals(state, totalsObject){
 | 
			
		||||
			//Save all the totals for the user
 | 
			
		||||
			state.userTotals = totalsObject
 | 
			
		||||
 | 
			
		||||
			// Object.keys(totalsObject).forEach( key => {
 | 
			
		||||
			// 	console.log(key + ' -- ' + totalsObject[key])
 | 
			
		||||
			// })
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	},
 | 
			
		||||
@@ -114,5 +123,16 @@ export default new Vuex.Store({
 | 
			
		||||
		getSocket: state => {
 | 
			
		||||
			return state.socket
 | 
			
		||||
		},
 | 
			
		||||
		totals: state => {
 | 
			
		||||
			return state.userTotals
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	actions: {
 | 
			
		||||
		fetchAndUpdateUserTotals ({ commit }) {
 | 
			
		||||
			axios.post('/api/user/totals')
 | 
			
		||||
			.then( ({data}) => {
 | 
			
		||||
				commit('setUserTotals', data)
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
@@ -334,6 +334,10 @@ Note.get = (userId, noteId) => {
 | 
			
		||||
			WHERE note.user_id = ? AND note.id = ? LIMIT 1`, [userId,noteId])
 | 
			
		||||
		.then((rows, fields) => {
 | 
			
		||||
 | 
			
		||||
			const created = Math.round((+new Date)/1000)
 | 
			
		||||
 | 
			
		||||
			db.promise().query(`UPDATE note SET opened = ? WHERE (id = ?)`, [created, noteId])
 | 
			
		||||
 | 
			
		||||
			//Return note data
 | 
			
		||||
			resolve(rows[0][0])
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,5 +111,58 @@ User.create = (username, password) => {
 | 
			
		||||
		.catch(console.log)
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Counts notes, pinned notes, archived notes, shared notes, unread notes, total files and types
 | 
			
		||||
User.getCounts = (userId) => {
 | 
			
		||||
	return new Promise((resolve, reject) => {
 | 
			
		||||
 | 
			
		||||
		let countTotals = {}
 | 
			
		||||
 | 
			
		||||
		db.promise().query(
 | 
			
		||||
			`SELECT
 | 
			
		||||
				SUM(pinned = 1 && archived = 0 && share_user_id IS NULL) AS pinnedNotes,
 | 
			
		||||
				SUM(pinned = 0 && archived = 1 && share_user_id IS NULL) AS archivedNotes,
 | 
			
		||||
				SUM(share_user_id IS NULL) AS totalNotes,
 | 
			
		||||
				SUM(share_user_id != ?) AS sharedToNotes,
 | 
			
		||||
				SUM( (share_user_id != ? && opened IS null) || (share_user_id != ? && updated > opened) ) AS unreadNotes
 | 
			
		||||
			FROM note 
 | 
			
		||||
			WHERE user_id = ?`, [userId, userId, userId, userId])
 | 
			
		||||
		.then( (rows, fields) => {
 | 
			
		||||
 | 
			
		||||
			Object.assign(countTotals, rows[0][0]) //combine results
 | 
			
		||||
 | 
			
		||||
			return db.promise().query(
 | 
			
		||||
				`SELECT count(id) AS sharedFromNotes 
 | 
			
		||||
				FROM note WHERE share_user_id = ?`, [userId]
 | 
			
		||||
			)
 | 
			
		||||
		})
 | 
			
		||||
		.then( (rows, fields) => {
 | 
			
		||||
 | 
			
		||||
			Object.assign(countTotals, rows[0][0]) //combine results
 | 
			
		||||
 | 
			
		||||
			return db.promise().query(
 | 
			
		||||
				`SELECT
 | 
			
		||||
					SUM(attachment_type = 1) as linkFiles,
 | 
			
		||||
					SUM(attachment_type != 1) as otherFiles,
 | 
			
		||||
					COUNT(id) as totalFiles
 | 
			
		||||
				FROM attachment WHERE visible = 1
 | 
			
		||||
				AND user_id = ?
 | 
			
		||||
				`, [userId]
 | 
			
		||||
			)
 | 
			
		||||
		}).then( (rows, fields) => {
 | 
			
		||||
 | 
			
		||||
			Object.assign(countTotals, rows[0][0]) //combine results
 | 
			
		||||
 | 
			
		||||
			//Convert everything to an int or 0
 | 
			
		||||
			Object.keys(countTotals).forEach( key => {
 | 
			
		||||
				const count = parseInt(countTotals[key])
 | 
			
		||||
				countTotals[key] = count ? count : 0
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			resolve(countTotals)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -46,4 +46,11 @@ router.post('/login', function (req, res) {
 | 
			
		||||
		})
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// fetch counts of users notes
 | 
			
		||||
router.post('/totals', function (req, res) {
 | 
			
		||||
	User.getCounts(req.headers.userId)
 | 
			
		||||
	.then( countsObject => res.send( countsObject ))
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = router
 | 
			
		||||
		Reference in New Issue
	
	Block a user