diff --git a/quasar.conf.js b/quasar.conf.js index 304aaf8b97da9a4ecd16b63da0f3e3b95f37abba..70c88ed16e5d784c02ec62335237aed540a4fd72 100644 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -97,7 +97,7 @@ module.exports = configure(function (/* ctx */) { // directives: [], // Quasar plugins - plugins: [] + plugins: ['Notify'] }, // animations: 'all', // --- includes all animations diff --git a/src/components/Friends.vue b/src/components/Friends.vue index 64dcd74aaa6d8a6b175f6fb81466ef79487e48a2..32ab5cba20e10f50745ee8c68108bfb42bcd4dec 100644 --- a/src/components/Friends.vue +++ b/src/components/Friends.vue @@ -2,7 +2,7 @@ q-toolbar.bg-primary.text-white.shadow-2 q-toolbar-title Contacts q-list(bordered) - q-item.q-my-sm(v-for='(user, key) in users', :key='key', :to='"/chat/" + key', clickable, v-ripple) + q-item.q-my-sm(v-for='(user, key) in friends', :key='key', :to='"/chat/" + key', clickable) q-item-section(avatar) q-avatar(color='primary', text-color='white') | {{ user.name.charAt(0) }} @@ -11,22 +11,62 @@ q-list(bordered) q-item-label(caption, lines='1') @{{ user.username }} q-item-section(side) q-icon(name='chat_bubble', :color='user.online ? "light-green-6" : "blue-grey-5"') +q-item.absolute-bottom.q-mb-xl(v-for='(user, key) in pending', :key='key') + .text-weight-light.text-subtitle1 {{ user }} + q-icon.q-pl-sm.cursor-pointer( + @click='acceptRequest(key)', + name='check_circle_outline', + color='green', + left, + size='1.5rem' + ) + q-icon.cursor-pointer(@click='denyRequest(key)', name='highlight_off', color='red', size='1.5rem') q-toolbar.absolute-bottom.bg-primary.text-white.shadow-2 - q-btn(@click='addFriends()', icon='person_add', flat, dense, label='Add Friends') + q-btn(icon='person_add', flat, dense, label='Add Friends') + q-popup-edit(v-model='usernameInput', :cover='false', v-slot='scope', @keyup.enter='sendRequest()') + q-input(v-model='scope.value', dense, autofocus, counter, @keyup.enter='scope.set') + template(v-slot:prepend) + q-icon(name='person_add', color='primary') </template> <script> -import { mapGetters } from 'vuex' +import { mapState, mapActions } from 'vuex' export default { - methods: { - addFriends() { - console.log('clicked') + data() { + return { + usernameInput: '@' } }, + methods: { + showNotif() { + this.$q.notify({ + message: 'Friend Request Sent', + color: 'pink', + actions: [ + { + label: '✕', + color: 'white' + } + ] + }) + }, + acceptRequest(otherUserId) { + this.firebaseAcceptRequest(otherUserId) + }, + denyRequest(otherUserId) { + this.firebaseRemovePending(otherUserId) + }, + sendRequest() { + this.showNotif() + this.firebaseSendFriendRequest(this.usernameInput.slice(1)) + }, + ...mapActions('firebase', ['firebaseRemovePending', 'firebaseAcceptRequest', 'firebaseSendFriendRequest']) + }, + computed: { - ...mapGetters('firebase', ['users']) + ...mapState('firebase', ['friends', 'pending']) } } </script> diff --git a/src/mixins/mixin-other-user-details.js b/src/mixins/mixin-other-user-details.js index 0184609786f10e8d1909e33759634411803c3970..65d4fc8e71e625fdc61c21cb011640167db7c628 100644 --- a/src/mixins/mixin-other-user-details.js +++ b/src/mixins/mixin-other-user-details.js @@ -1,8 +1,8 @@ export default { computed: { otherUserDetails() { - if (this.$store.state.firebase.users[this.$route.params.otherUserId]) { - return this.$store.state.firebase.users[this.$route.params.otherUserId] + if (this.$store.state.firebase.friends[this.$route.params.otherUserId]) { + return this.$store.state.firebase.friends[this.$route.params.otherUserId] } return {} }, diff --git a/src/pages/UserInfo.vue b/src/pages/UserInfo.vue index cf7bbc565e97dd91289852583e5d6d4bae22fbd7..1826cd91a8465fc985c78d1f01721f8dd33641f9 100644 --- a/src/pages/UserInfo.vue +++ b/src/pages/UserInfo.vue @@ -6,22 +6,33 @@ img( src='https://avataaars.io/?avatarStyle=Circle&topType=Eyepatch&facialHairType=Blank&clotheType=ShirtVNeck&clotheColor=Pink&eyeType=Squint&eyebrowType=AngryNatural&mouthType=Default&skinColor=Light' ) - q-input.q-pb-md(v-model='name', label='Full Name', stack-label, :readonly='isEditing') - q-input.q-pb-md(v-model='username', label='Username', stack-label, :readonly='isEditing') - q-input.q-pb-md(v-model='password', label='Password', stack-label, :readonly='isEditing') - q-input.q-pb-md(v-model='email', label='Email', stack-label, :readonly='isEditing') - q-input.q-pb-md(v-model='phone', label='Phone Number', stack-label, :readonly='isEditing') - q-input.q-pb-lg(v-model='date', mask='date', :rules='["date"]', label='Date of Birth', :readonly='isEditing') + q-input.q-py-md(v-model='localDetails.name', label='Full Name', stack-label, :readonly='isEditing') + q-input.q-pb-md(v-model='localDetails.username', label='Username', stack-label, :readonly='isEditing') + q-input.q-pb-md(v-model='localDetails.email', label='Email', stack-label, :readonly='isEditing') + q-input.q-pb-md(v-model='localDetails.phone', label='Phone Number', stack-label, :readonly='isEditing') + q-input.q-pb-lg( + v-model='localDetails.date', + mask='date', + label='Date of Birth', + :rules='["date"]', + :readonly='isEditing' + ) template(v-slot:append) q-icon.cursor-pointer(name='event') q-menu - q-date(v-model='date', :disable='isEditing') + q-date(v-model='localDetails.date', :disable='isEditing') .text-subtitle1.text-grey-9.q-pb-sm Gender: - q-radio.q-pr-sm.q-ml-md(v-model='gender', val='male', label='Male', color='cyan', :disable='isEditing') - q-radio.q-pr-sm(v-model='gender', val='female', label='Female', color='pink', :disable='isEditing') - q-radio.q-pr-sm(v-model='gender', val='other', label='Other', color='accent', :disable='isEditing') + q-radio.q-pr-sm.q-ml-md( + v-model='localDetails.gender', + val='male', + label='Male', + color='cyan', + :disable='isEditing' + ) + q-radio.q-pr-sm(v-model='localDetails.gender', val='female', label='Female', color='pink', :disable='isEditing') + q-radio.q-pr-sm(v-model='localDetails.gender', val='other', label='Other', color='accent', :disable='isEditing') q-input.q-pb-xl( - v-model='description', + v-model='localDetails.description', label='Description', stack-label='', autogrow='', @@ -29,29 +40,56 @@ ) div q-btn(@click='editing = !editing', color='blue', icon='mode_edit', label='Edit') - q-btn.float-right(icon='save', color='green', label='save') + q-btn.float-right(@click='saveUserDetails()', icon='save', color='green', label='save') </template> <script> +import { mapState, mapMutations, mapActions, mapGetters } from 'vuex' + export default { data() { return { - name: 'Eric Sauce', - username: 'Er1csauce', - password: 'Er1csauce14', - email: 'ek00722@surrey.ac.uk', - phone: '0123456789', - date: '2019/02/01', - gender: 'Male', - description: 'Very hot lad', + localDetails: { + name: null, + username: null, + email: null, + phone: null, + date: '1990/01/01', + gender: null, + description: null + }, editing: false } }, + methods: { + saveUserDetails() { + this.firebaseUpdateUser({ + userId: this.userDetails.userId, + updates: this.localDetails + }) + + this.localDetails['userId'] = this.userDetails.userId + this.setUserDetails(JSON.parse(JSON.stringify(this.localDetails))) + + this.editing = false + }, + ...mapMutations('firebase', ['setUserDetails']), + ...mapActions('firebase', ['firebaseUpdateUser']) + }, + computed: { isEditing() { return this.editing ? false : true - } + }, + ...mapState('firebase', ['userDetails']), + ...mapGetters('firebase', ['userDetailsKeys']) + }, + + mounted() { + this.userDetailsKeys.forEach(key => { + this.localDetails[key] = this.userDetails[key] + }) } } </script> diff --git a/src/static/data-structure.json b/src/static/data-structure.json index 3933ceb971454054e6046d2a35e02881f1946a73..6f524638d086b319ce331ccb4a932f8b6d09b1ad 100644 --- a/src/static/data-structure.json +++ b/src/static/data-structure.json @@ -4,24 +4,40 @@ "name": "Test Name", "username": "testusername", "email": "test@test.com", + "phone": null, + "dob": null, + "gender": null, + "description": null, "online": false }, "Oqk3C1ownieYIm8K0KgFqRXhKs53": { "name": "Scientific Pig", "username": "dontlookitup", "email": "test3@test.com", + "phone": null, + "dob": null, + "gender": null, + "description": null, "online": false }, "l7TY1PJocphLufQb3zN1tfRJYsy1": { "name": "how is this working lmao", "username": "amogus", "email": "test4@test.com", + "phone": null, + "dob": null, + "gender": null, + "description": null, "online": false }, "oVHXZPeYRbQPfKTCmH4LWJtmaeH2": { "name": "Eric Sauce", "username": "theSaucer", "email": "test2@test.com", + "phone": null, + "dob": null, + "gender": null, + "description": null, "online": false } }, @@ -50,5 +66,16 @@ } } } + }, + "friends": { + "9HsxN1tMHNOfmQV3E16LNfcFTdc2": { + "friendList": { + "Oqk3C1ownieYIm8K0KgFqRXhKs53": true, + "l7TY1PJocphLufQb3zN1tfRJYsy1": true + }, + "pending": { + "oVHXZPeYRbQPfKTCmH4LWJtmaeH2": true + } + } } } \ No newline at end of file diff --git a/src/store/firebase.js b/src/store/firebase.js index 69976e6245fe4aff9dbb836267e76772f15c57dd..62927eed76efa5f406afd4c6571da48034e60c34 100644 --- a/src/store/firebase.js +++ b/src/store/firebase.js @@ -4,8 +4,9 @@ let messagesRef const state = { userDetails: {}, - users: {}, - messages: {} + messages: {}, + friends: {}, + pending: {} } const mutations = { @@ -13,12 +14,17 @@ const mutations = { state.userDetails = payload }, - addUser(state, payload) { - state.users[payload.userId] = payload.userDetails + addFriend(state, payload) { + state.friends[payload.userId] = payload.userDetails }, - updateUser(state, payload) { - Object.assign(state.users[payload.userId], payload.userDetails) + addPending(state, payload) { + state.pending[payload.userId] = payload.userDetails + }, + + removePending(state, payload) { + let key = payload + delete state.pending[key] }, addMessage(state, payload) { @@ -81,7 +87,7 @@ const actions = { online: true } }) - dispatch('firebaseGetUsers') + dispatch('firebaseGetFriends', userId) this.$router.push('/') } else if(state.userDetails.userId) { @@ -102,25 +108,65 @@ const actions = { firebaseDb.ref('users/' + payload.userId).update(payload.updates) }, - firebaseGetUsers({ commit }) { - firebaseDb.ref('users').on('child_added', snapshot => { - let userDetails = snapshot.val() - let userId = snapshot.key - commit('addUser', { - userId, - userDetails + firebaseGetFriends({ commit }, payload) { + let userId = payload + + firebaseDb.ref('friends/' + userId + '/friendList').on('child_added', snapshot => { + let otherUserId = snapshot.key + firebaseDb.ref('users').child(otherUserId).once('value', snapshot => { + let userDetails = snapshot.val() + commit('addFriend', { + userId: otherUserId, + userDetails + }) }) }) - firebaseDb.ref('users').on('child_changed', snapshot => { - let userDetails = snapshot.val() - let userId = snapshot.key - commit('updateUser', { - userId, - userDetails + + firebaseDb.ref('friends/' + userId + '/pending').on('child_added', snapshot => { + let otherUserId = snapshot.key + firebaseDb.ref('users').child(otherUserId).once('value', snapshot => { + let userDetails = snapshot.val().username + commit('addPending', { + userId: otherUserId, + userDetails + }) }) }) }, + async firebaseSendFriendRequest({ state }, payload) { + let otherUsername = payload + let requestObject = {} + requestObject[state.userDetails.userId] = true + + const snapshot = await firebaseDb.ref('users').orderByChild('username').equalTo(otherUsername).once('value') + + let otherUserId = Object.keys(snapshot.val())[0] + firebaseDb.ref('friends/' + otherUserId + '/pending').update(requestObject) + }, + + + firebaseRemovePending({ state, commit }, payload) { + let otherUserId = payload + commit('removePending', payload) + firebaseDb.ref('friends/' + state.userDetails.userId + '/pending/' + otherUserId).remove() + }, + + firebaseAcceptRequest({ dispatch }, payload) { + dispatch('firebaseRemovePending', payload) + + let friendId = payload + let friendObject = {} + friendObject[friendId] = true + + firebaseDb.ref('friends/' + state.userDetails.userId + '/friendList').update(friendObject) + + friendObject = {} + friendObject[state.userDetails.userId] = true + + firebaseDb.ref('friends/' + friendId + '/friendList').update(friendObject) + }, + firebaseGetMessages({ state, commit }, otherUserId) { let userId = state.userDetails.userId messagesRef = firebaseDb.ref('chats/' + userId + '/' + otherUserId) @@ -152,14 +198,8 @@ const actions = { } const getters = { - users: state => { - let usersFiltered = {} - Object.keys(state.users).forEach(key => { - if (key !== state.userDetails.userId) { - usersFiltered[key] = state.users[key] - } - }) - return usersFiltered + userDetailsKeys: state => { + return Object.keys(state.userDetails) } }