Skip to content

Commit

Permalink
Merge branch '_staging' into feat/cicd-overhaul-11-2023
Browse files Browse the repository at this point in the history
  • Loading branch information
TylerHendrickson authored Nov 24, 2023
2 parents c4f1fc6 + 9fdea29 commit a06a211
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 26 deletions.
29 changes: 27 additions & 2 deletions packages/client/src/components/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,32 @@

<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto">
<b-nav-item-dropdown right v-if="loggedInUser && myProfileEnabled" no-caret>
<!-- Using 'button-content' slot -->
<template v-if="myProfileEnabled" #button-content>
<div class="d-inline-flex justify-content-start align-items-center" style="width: 242px">
<UserAvatar size="2.5rem"/>
<div class="ml-2 mr-5 text-black">
<p class="m-0 font-weight-bold">{{ loggedInUser.name }}</p>
<p class="m-0">{{ selectedTeam ? selectedTeam.name : '' }}</p>
</div>
<p class="text-black m-0 ml-auto"><b-icon icon="caret-down-fill" scale="0.8"></b-icon></p>
</div>
</template>
<template v-else #button-content>
<em>{{loggedInUser.email}}</em>
</template>
<b-dropdown-item-button href="#" @click="settingsClicked">Settings</b-dropdown-item-button>
<b-dropdown-item-button href="#" @click="giveFeedback">Give Feedback</b-dropdown-item-button>
<b-dropdown-item-button href="#" @click="trainingGuide">Training Guide</b-dropdown-item-button>
<b-dropdown-item-button href="#" @click="logout">Sign Out</b-dropdown-item-button>
</b-nav-item-dropdown>

<b-nav-text>
<b-nav-text v-if="!myProfileEnabled">
<b-badge>{{selectedTeam ? selectedTeam.name : ''}}</b-badge>
</b-nav-text>

<b-nav-item-dropdown right v-if="loggedInUser">
<b-nav-item-dropdown right v-if="loggedInUser && !myProfileEnabled">
<!-- Using 'button-content' slot -->
<template #button-content>
<em>{{loggedInUser.email}}</em>
Expand Down Expand Up @@ -57,12 +77,14 @@ import { mapGetters } from 'vuex';
import { myProfileEnabled, newTerminologyEnabled, useNewGrantsTable } from '@/helpers/featureFlags';
import ProfileSettingsModal from '@/components/Modals/ProfileSettings.vue';
import AlertBox from '../arpa_reporter/components/AlertBox.vue';
import UserAvatar from './UserAvatar.vue';
export default {
name: 'Layout',
components: {
AlertBox,
ProfileSettingsModal,
UserAvatar,
},
data() {
return {
Expand Down Expand Up @@ -123,4 +145,7 @@ export default {
</script>

<style scoped lang="scss">
.text-black {
color: #000;
}
</style>
13 changes: 12 additions & 1 deletion packages/client/src/components/Modals/EditUser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
@ok="handleOk"
:ok-disabled="$v.formData.$invalid"
>
<div class="text-center my-3">
<UserAvatar editable @changeColor="handleChangeColor" :userName="formData.name"/>
</div>
<b-form>
<b-form-group
:state="!$v.formData.name.$invalid"
Expand All @@ -34,12 +37,17 @@
<script>
import { mapGetters, mapActions } from 'vuex';
import { required, minLength } from 'vuelidate/lib/validators';
import UserAvatar from '../UserAvatar.vue';
export default {
components: {
UserAvatar,
},
data() {
return {
formData: {
name: null,
avatarColor: null,
},
};
},
Expand All @@ -62,15 +70,18 @@ export default {
}),
resetModal() {
this.formData.name = this.loggedInUser.name;
this.formData.avatarColor = this.loggedInUser.avatar_color;
},
handleOk(bvModalEvt) {
// Prevent modal from closing
bvModalEvt.preventDefault();
this.handleSubmit();
},
handleChangeColor(bgColor) {
this.formData.avatarColor = bgColor;
},
async handleSubmit() {
this.formData.id = this.loggedInUser.id;
// Exit when the form isn't valid
if (this.$v.formData.$invalid) {
return;
Expand Down
110 changes: 110 additions & 0 deletions packages/client/src/components/UserAvatar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<template>
<div>
<!-- Default avatar w/o badge: style attribute is bound to computed
property fixedAvatarStyles which is derived from user session data.
-->
<b-avatar v-if="!editable" :text="initials" :size="avatarSize" v-bind:style="fixedAvatarStyles" badge-variant="light">
</b-avatar>

<div v-if="editable">
<!-- Editable avatar:style attribute is bound to editableAvatarStyles
so changes from the color picker will be reflected -->
<b-avatar :text="toInitials(userName)" :size="avatarSize" v-bind:style="editableAvatarStyles" badge-variant="light">
</b-avatar>
<div class="my-4">
<p class="text-left">Avatar color</p>
<div class="color-picker">
<b-button v-for="(color, index) in allColors" :key="index" :style="{ backgroundColor: color }" @click="handleColorSelection(color)"></b-button>
</div>
</div>
</div>
</div>
</template>

<script>
import { mapGetters } from 'vuex';
import { avatarColors } from '@/helpers/constants';
export default {
props: {
size: {
type: String,
default: '5rem',
},
editable: {
type: Boolean,
default: false,
},
userName: {
type: String,
default: '',
},
},
data() {
return {
allColors: Object.keys(avatarColors),
editableAvatarStyles: null,
};
},
computed: {
...mapGetters({
loggedInUser: 'users/loggedInUser',
}),
initials() {
return this.toInitials(this.loggedInUser.name);
},
avatarSize() {
return this.size;
},
fixedAvatarStyles() {
return {
backgroundColor: this.loggedInUser.avatar_color,
color: avatarColors[this.loggedInUser.avatar_color],
};
},
},
created() {
this.editableAvatarStyles = {
backgroundColor: this.loggedInUser.avatar_color,
color: avatarColors[this.loggedInUser.avatar_color],
};
},
methods: {
handleColorSelection(bgColor) {
this.editableAvatarStyles = {
backgroundColor: bgColor,
color: avatarColors[bgColor],
};
this.$emit('changeColor', bgColor); // passes background color to EditUser form
},
toInitials(name) {
if (!name) return '';
const fullNameArr = name.split(' ');
if (fullNameArr.length < 2) return fullNameArr[0][0].toUpperCase();
const firstName = fullNameArr.at(0);
const lastName = fullNameArr.at(-1);
return (firstName[0] + lastName[0]).toUpperCase();
},
},
};
</script>

<style>
.color-picker {
display: grid;
grid-template-columns: repeat(9, 1fr);
justify-items: center;
row-gap: 10px;
}
.color-picker button {
border: none;
border-radius: 5px;
height: 35px;
width: 35px;
}
</style>
22 changes: 22 additions & 0 deletions packages/client/src/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ const billOptions = [
'Social Security Administration',
];

const avatarColors = {
'#44337A': '#FFF',
'#086F83': '#FFF',
'#234E52': '#FFF',
'#702459': '#FFF',
'#602314': '#FFF',
'#BA8C03': '#000',
'#6610F2': '#FFF',
'#0DCAF0': '#000',
'#198754': '#FFF',
'#D63384': '#FFF',
'#FD7E14': '#000',
'#FFC107': '#000',
'#B794F4': '#000',
'#76E4F7': '#000',
'#20C997': '#000',
'#F687B3': '#000',
'#F4B46D': '#000',
'#FCD663': '#000',
};

module.exports = {
billOptions,
avatarColors,
};
4 changes: 2 additions & 2 deletions packages/client/src/store/modules/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ export default {
await dispatch('fetchUsers');
},
async updateUser({ commit }, user) {
const { id, name } = user;
const data = await fetchApi.patch(`/api/organizations/:organizationId/users/${id}`, { name });
const { id, name, avatarColor } = user;
const data = await fetchApi.patch(`/api/organizations/:organizationId/users/${id}`, { name, avatar_color: avatarColor });
commit('SET_LOGGED_IN_USER', data.user);
},
async deleteUser({ dispatch, commit }, userId) {
Expand Down
10 changes: 3 additions & 7 deletions packages/client/src/views/MyProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<section style="margin-top: 4rem;">
<b-row>
<b-col>
<b-avatar :text="initials" size="5rem"></b-avatar>
<UserAvatar />
</b-col>
<b-col cols="7">
<p class="mb-2 h6"><b>{{ name }}</b></p>
Expand Down Expand Up @@ -38,10 +38,12 @@
<script>
import { mapGetters, mapActions } from 'vuex';
import EditUserModal from '@/components/Modals/EditUser.vue';
import UserAvatar from '@/components/UserAvatar.vue';
export default {
components: {
EditUserModal,
UserAvatar,
},
data() {
return {
Expand Down Expand Up @@ -77,12 +79,6 @@ export default {
agency() {
return this.loggedInUser.agency_name;
},
initials() {
const fullNameArr = this.name.split(' ');
const firstName = fullNameArr.at(0);
const lastName = fullNameArr.at(-1);
return (firstName[0] + lastName[0]).toUpperCase();
},
emailPreferences() {
return this.loggedInUser.emailPreferences;
},
Expand Down
9 changes: 9 additions & 0 deletions packages/server/__tests__/api/users.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,15 @@ describe('`/api/users` endpoint', () => {
expect(response.statusText).to.equal('OK');
});

it('updates a user\'s avatar color', async () => {
const response = await fetchApi('/users/4', agencies.own, {
...fetchOptions.nonUSDRAdmin,
method: 'patch',
body: JSON.stringify({ avatar_color: '#44337A' }),
});
expect(response.statusText).to.equal('OK');
});

it('does not update a user\'s email', async () => {
const response = await fetchApi('/users/4', agencies.own, {
...fetchOptions.nonUSDRAdmin,
Expand Down
Loading

0 comments on commit a06a211

Please sign in to comment.