Skip to content

Commit

Permalink
Show other user's lamps in groups (Fixes #49)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexwohlbruck committed May 17, 2022
1 parent db9b772 commit d8eed92
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 55 deletions.
27 changes: 22 additions & 5 deletions client/src/components/Lamp.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
<template lang="pug">
v-card.lamp-card(light)
v-card-text.d-flex.flex-column
v-card-text.d-flex.flex-column.flex-row
.d-flex
.text-h5.font-weight-bold(:style='`color: ${lamp.group.state.colors[0]}`')
| {{ lamp.name }}
div
.text-h5.font-weight-bold(:style='`color: ${state.colors[0]}`')
| {{ lamp.name }}
.text-body-2.font-weight-bold {{ lamp.user.name }}

v-spacer
v-btn(icon color='black' :to="{name: 'lamp-settings', params: {id: lamp._id}}")
v-btn(
v-if='isMyLamp'
icon
color='black'
:to="{name: 'lamp-settings', params: {id: lamp._id}}"
)
v-icon mdi-cog

.d-flex.align-sm-end.justify-space-between.flex-column.flex-sm-row
v-spacer(v-if='!isMyLamp')

lamp-visualizer.mb-4(
:state='lamp.group.state'
:state='state'
:lampId='lamp._id'
:small='!isMyLamp'
)
v-btn.px-8.py-7(
v-if='isMyLamp'
@mousedown='activate'
@touchstart='activate'
@mouseup='deactivate'
Expand All @@ -27,6 +38,7 @@ v-card.lamp-card(light)
| Send pulse

v-color-picker(
v-if='isMyLamp'
v-model='selectedColor'
hide-canvas
hide-inputs
Expand All @@ -53,6 +65,7 @@ type Hsl = {
})
export default class Lamp extends Vue {
@Prop({ default: null }) lamp: any
@Prop({ default: null }) state: any
touching = false
selectedColor: Hsl = {
Expand All @@ -61,6 +74,10 @@ export default class Lamp extends Vue {
l: 0.5,
}
get isMyLamp() {
return this.lamp?.user._id === this.$store.getters.me?._id
}
gradientFromHue(hue: number) {
return gradientFromHue(hue, 'to right')
}
Expand Down
10 changes: 7 additions & 3 deletions client/src/components/LampVisualizer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.lamp-visualizer
//- div(:style='`width: 100px; height: 100px; background: ${state.colors[0]}`')
.lamp
.lamp(:class='{small}')
.section.lid(style='z-index: 3;')
.bottom
.middle
Expand All @@ -22,12 +22,12 @@
import { Component, Vue, Prop } from 'vue-property-decorator'
import { GroupState } from '@/types/Group'
type State = GroupState
@Component
export default class LampVisualizer extends Vue {
@Prop(Object) state!: State
@Prop({ default: false }) small!: boolean
}
</script>

Expand All @@ -46,7 +46,7 @@ $base-height: .2 * $lamp-height;
width: $lamp-width;
height: $lamp-height;
margin-bottom: $lamp-height * .25;
.section {
position: relative;
width: $lamp-width;
Expand Down Expand Up @@ -115,6 +115,10 @@ $base-height: .2 * $lamp-height;
background-color: rgb(207, 109, 43);
}
}
}
.lamp.small {
transform: scale(.5);
margin: -2.6em;
}
</style>
23 changes: 23 additions & 0 deletions client/src/services/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,26 @@ export const getGroup = async (id: string) => {
Store.commit('ADD_GROUP', data)
return data
}

export const getMyGroups = async () => {
const { data } = await axios.get<Group[]>('/groups/me')

console.log(JSON.stringify(data))
console.log(data)

data.forEach(group => {
console.log(group)

// Destructure lamps
group.lamps?.forEach(lamp => {
console.log(lamp)
Store.commit('ADD_LAMP', lamp)
})
delete group.lamps

Store.commit('ADD_GROUP', group)
})

return data

}
16 changes: 13 additions & 3 deletions client/src/store/groups.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Group } from '@/types/Group'
import Vue from 'vue'
import { Group } from '@/types/Group'
import { RootState } from '.'

export interface GroupsState {
all: string[]
Expand Down Expand Up @@ -44,8 +45,17 @@ const mutations = {
}

const getters = {
group: (state: GroupsState) => (id: string) => state.byId[id],
groups: (state: GroupsState) => (ids: string[]) => ids.map(id => state.byId[id]),
group: (state: GroupsState, getters: any, _rootState: RootState, rootGetters: any) => (id: string) => {
const g = state.byId[id]
g.lamps = rootGetters.lampsByGroup(id)
return g
},
groups: (state: GroupsState, getters: any) => (ids: string[]) => ids.map(id => getters.group(id)),
myGroups: (state: GroupsState, getters: any, _rootState: RootState, _rootGetters: any) => {
return getters
.groups(state.all)
// .filter((lamp: Lamp) => lamp.user?._id === rootGetters.me?._id)
}
}

export default {
Expand Down
25 changes: 15 additions & 10 deletions client/src/store/lamps.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Lamp } from '@/types/Lamp'
import Vue from 'vue'
import { Lamp } from '@/types/Lamp'
import { RootState } from '.'
import UsersStore from './users'
import GroupsStore from './groups'
const { mutations: usersMutations, state: usersState } = UsersStore
const { mutations: groupsMutations, state: groupsState } = GroupsStore
// const { mutations: usersMutations, state: usersState } = UsersStore
// const { mutations: groupsMutations, state: groupsState } = GroupsStore

export interface LampsState {
all: string[]
Expand Down Expand Up @@ -33,28 +33,33 @@ const lampsGetters = {
delete lamp.userId
}

if (lamp?.user?._id) {
lamp.user = getters.user(lamp.user._id)
}

return lamp
},

lamps: (_state: LampsState, getters: any) => (ids: string[]) => {
return ids.map((id: string) => getters.lamp(id))
},

myLamps: (state: LampsState, getters: any, _rootState: RootState, rootGetters: any) => {
return getters
.lamps(state.all)
// .filter((lamp: Lamp) => lamp.user?._id === rootGetters.me?._id)
}
lampsByGroup: (state: LampsState, getters: any) => (groupId: string) => {
const lamps = getters.lamps(state.all.filter((id: string) => {
return getters.lamp(id).group === groupId
}))
return lamps
},
}

const mutations = {
ADD_LAMP(state: LampsState, lamp: Lamp) {
if (lamp.user) {
if (lamp.user?._id) {
UsersStore.mutations.ADD_USER(UsersStore.state, lamp.user)
lamp.userId = lamp.user._id
delete lamp.user
}
if (lamp.group) {
if (lamp?.group?._id) {
GroupsStore.mutations.ADD_GROUP(GroupsStore.state, lamp.group)
lamp.groupId = lamp.group._id
delete lamp.group
Expand Down
39 changes: 11 additions & 28 deletions client/src/views/Lamps.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
<template lang="pug">
v-container

.d-flex.flex-column.align-center(v-if='!(myLamps && myLamps.length)' style='padding-top: calc(50vh - 260px)')
.d-flex.flex-column.align-center(v-if='!(myGroups && myGroups.length)' style='padding-top: calc(50vh - 260px)')
p.text-h6 You have no lamps.
v-img.mt-5.mb-10(src='@/assets/undraw_signal_searching.svg' width='300')


.d-flex.flex-column.align-center(v-else)
v-card.lamp-card.mb-4.pa-6.small-container(
v-for='(group, groupId) in groups'
v-for='(group, groupId) in myGroups'
:key='groupId'
:style='`background: ${gradient(group.group.state)}; box-shadow: ${shadow(group.group.state)};`'
:style='`background: ${gradient(group.state)}; box-shadow: ${shadow(group.state)};`'
)
.d-flex.flex-column.mb-4
.text-h6 {{ group.group.groupId }}
.text-h6 {{ group.groupId }}
.text-subtitle-2
| {{ group.lamps.length }} {{ group.lamps.length === 1 ? 'lamp' : 'lamps' }}
| - {{ group.group.accessCode }}
| - {{ group.accessCode }}

.d-flex.flex-column(style='gap: 1.5em;')
lamp(v-for='lamp in group.lamps' :key='lamp._id' :lamp='lamp')
lamp(v-for='lamp in group.lamps' :key='lamp._id' :lamp='lamp' :state='group.state')

.d-flex.justify-center
v-btn.ml-4(
Expand All @@ -34,7 +34,7 @@ v-container

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { getMyLamps } from '@/services/lamp'
import { getMyGroups } from '@/services/group'
import Lamp from '@/components/Lamp.vue'
import { colorShadow, gradientFromHue } from '@/util'
import { hexStringToHsl } from '@/util'
Expand All @@ -46,36 +46,19 @@ import { hexStringToHsl } from '@/util'
})
export default class Lamps extends Vue {
get myLamps() {
return this.$store.getters.myLamps
async mounted() {
await getMyGroups()
}
get groups() {
// Return unqiue groups with their respective lamps in a list
return this.myLamps.reduce((acc: any, lamp: any) => {
if (lamp.group) {
if (!acc[lamp.group._id]) {
acc[lamp.group._id] = {
group: lamp.group,
lamps: [lamp],
}
} else {
acc[lamp.group._id].lamps.push(lamp)
}
}
return acc
}, {})
get myGroups() {
return this.$store.getters.myGroups
}
shadow(state: any) {
const hue = hexStringToHsl(state.colors[0])[0]
return colorShadow(hue)
}
async mounted() {
await getMyLamps()
}
gradient(group: any) {
if (!group?.colors) return 'black'
Expand Down
2 changes: 2 additions & 0 deletions server/models/group.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Schema, model } from 'mongoose'
import { Lamp } from './lamp'

export interface GroupState {
colors: string[]
Expand All @@ -10,6 +11,7 @@ export interface Group {
groupId: string
accessCode: string
state: GroupState
lamps?: Lamp[]
}

const GroupSchema = new Schema<Group>({
Expand Down
5 changes: 2 additions & 3 deletions server/routes/groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { getGroup, listGroups } from '../services/groups'
const router = express.Router()

// Get current user's groups
router.get('/', isAuthenticated, async (req, res) => {
router.get('/me', isAuthenticated, async (req, res) => {
try {
const groups = await listGroups((req.user as User)._id)
const groups = await listGroups((req.user as User)._id, true)
return res.status(200).json(groups)
}
catch (err) {
Expand All @@ -29,5 +29,4 @@ router.get('/:id', isAuthenticated, async (req, res) => {
}
})


export default router
17 changes: 15 additions & 2 deletions server/services/groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,24 @@ import { GroupModel } from '../models/group'
import { convertToDotNotation } from '../helpers'

// List a user's groups
export const listGroups = async (userId: string) => {
export const listGroups = async (userId: string, includeLamps = false) => {
const lamps = await LampModel.find({
user: new Types.ObjectId(userId)
})
const groups = lamps.map((lamp: Lamp) => lamp.group)

// Convert to plain JSON in order to append lamps results
const groups = JSON.parse(JSON.stringify(
lamps.map((lamp: Lamp) => lamp.group)
))

if (includeLamps) {
for (const group of groups) {
group.lamps = await getLamps({
groupId: group._id.toString(),
autopopulate: false,
})
}
}

return groups
}
Expand Down
8 changes: 7 additions & 1 deletion server/services/lamps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ const broadcastToGroup = async (groupId: string, payload: WSPayload) => {
export const getLamps = async (options: {
userId?: string;
groupId?: string;
autopopulate?: boolean;
}) => {
const query: any = {}

if (options) {
if (options.userId) query.user = new Types.ObjectId(options.userId)
if (options.groupId) query.group = new Types.ObjectId(options.groupId)
if (options.autopopulate === undefined) options.autopopulate = true
}

return await LampModel.find(query).sort({ createdAt: -1 })
return await LampModel.find(query, {}, {
autopopulate: options.autopopulate,
})
.populate('user')
.sort({ createdAt: -1 })
}

export const getLamp = async (id: string) => {
Expand Down

0 comments on commit d8eed92

Please sign in to comment.