Skip to content

Commit

Permalink
Merge pull request #288 from ncosd/dev-1.14.0
Browse files Browse the repository at this point in the history
Release 1.14.0
  • Loading branch information
dherbst authored Jan 24, 2024
2 parents bf4307f + 2acee55 commit f51e517
Show file tree
Hide file tree
Showing 21 changed files with 508 additions and 20 deletions.
2 changes: 1 addition & 1 deletion web/admin/fixtures/auth_export/accounts.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"5WddDr1Teytl9YHQ0Lgf2yP86pft","createdAt":"1681846355208","lastLoginAt":"1681846355208","displayName":"v2","passwordHash":"fakeHash:salt=fakeSaltMaXkJGcoDb58rWtYnrD4:password=password","salt":"fakeSaltMaXkJGcoDb58rWtYnrD4","passwordUpdatedAt":1704985140624,"customAttributes":"{\"volunteer\":true}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","displayName":"v2"}],"validSince":"1704985140","email":"[email protected]","emailVerified":false,"disabled":false},{"localId":"olN7alG8mHwRg6YYgVjlpR9scwq5","createdAt":"1614344510322","lastLoginAt":"1704985153659","displayName":"VolunteerUser","photoUrl":"","passwordHash":"fakeHash:salt=fakeSaltPdNFgJYXTp3KoHpHPeET:password=password","salt":"fakeSaltPdNFgJYXTp3KoHpHPeET","passwordUpdatedAt":1704985140624,"customAttributes":"{\"admin\": true,\"volunteer\":true}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","displayName":"VolunteerUser","photoUrl":""}],"validSince":"1704985140","email":"[email protected]","emailVerified":false,"disabled":false,"lastRefreshAt":"2024-01-11T14:59:13.659Z"},{"localId":"woEHhjSLumylkHLkbJKYdV7bTlNF","createdAt":"1681846322321","lastLoginAt":"1684257041600","displayName":"v1","passwordHash":"fakeHash:salt=fakeSaltMmMYfmogc9thU5bAe1wL:password=password","salt":"fakeSaltMmMYfmogc9thU5bAe1wL","passwordUpdatedAt":1704985140625,"customAttributes":"{\"volunteer\":true}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","displayName":"v1"}],"validSince":"1704985140","email":"[email protected]","emailVerified":false,"disabled":false}]}
{"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"5WddDr1Teytl9YHQ0Lgf2yP86pft","createdAt":"1681846355208","lastLoginAt":"1681846355208","displayName":"v2","passwordHash":"fakeHash:salt=fakeSaltMaXkJGcoDb58rWtYnrD4:password=password","salt":"fakeSaltMaXkJGcoDb58rWtYnrD4","passwordUpdatedAt":1705853986882,"customAttributes":"{\"volunteer\":true}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","displayName":"v2"}],"validSince":"1705853986","email":"[email protected]","emailVerified":false,"disabled":false},{"localId":"olN7alG8mHwRg6YYgVjlpR9scwq5","createdAt":"1614344510322","lastLoginAt":"1704985153659","displayName":"VolunteerUser","photoUrl":"","passwordHash":"fakeHash:salt=fakeSaltPdNFgJYXTp3KoHpHPeET:password=password","salt":"fakeSaltPdNFgJYXTp3KoHpHPeET","passwordUpdatedAt":1705853986882,"customAttributes":"{\"admin\": true,\"volunteer\":true}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","displayName":"VolunteerUser","photoUrl":""}],"validSince":"1705853986","email":"[email protected]","emailVerified":false,"disabled":false},{"localId":"woEHhjSLumylkHLkbJKYdV7bTlNF","createdAt":"1681846322321","lastLoginAt":"1684257041600","displayName":"v1","passwordHash":"fakeHash:salt=fakeSaltMmMYfmogc9thU5bAe1wL:password=password","salt":"fakeSaltMmMYfmogc9thU5bAe1wL","passwordUpdatedAt":1705853986882,"customAttributes":"{\"volunteer\":true}","providerUserInfo":[{"providerId":"password","email":"[email protected]","federatedId":"[email protected]","rawId":"[email protected]","displayName":"v1"}],"validSince":"1705853986","email":"[email protected]","emailVerified":false,"disabled":false}]}
4 changes: 2 additions & 2 deletions web/admin/fixtures/firebase-export-metadata.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"version": "13.0.2",
"version": "13.0.3",
"firestore": {
"version": "1.18.2",
"path": "firestore_export",
"metadata_file": "firestore_export/firestore_export.overall_export_metadata"
},
"auth": {
"version": "13.0.2",
"version": "13.0.3",
"path": "auth_export"
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added web/admin/public/img/delivery/route-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion web/admin/src/components/AppNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ const signOutClick = () => {
<ul class="navbar-nav mb-2 mb-lg-0">
<template v-if="user && user.isAdmin === true">
<li class="nav-item">
<router-link to="/volunteers" class="nav-link">Volunteers</router-link>
<router-link class="nav-link" to="/volunteers">Volunteers</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" to="/schedule">Schedule</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" :to="{ name: 'DeliveryDashboard' }">Delivery</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" :to="{ name: 'LocationsList' }">Locations</router-link>
</li>
Expand Down
26 changes: 26 additions & 0 deletions web/admin/src/components/delivery/DeliveryTabs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup>
import { ref, onBeforeMount } from 'vue'
const props = defineProps({
activeTab: String,
uid: String
})
</script>

<template>
<ul class="nav nav-tabs">
<li class="nav-item">
<router-link :class="['nav-link', { active: props.activeTab === 'Dashboard' }]" aria-current="page" :to="{ name: 'DeliveryDashboard' }">Dashboard</router-link>
</li>
<li class="nav-item">
<router-link :class="['nav-link', { active: props.activeTab === 'Deliveries' }]" :to="{ name: 'DeliveryList' }">Deliveries</router-link>
</li>
<li class="nav-item">
<router-link :class="['nav-link', { active: props.activeTab === 'Routes' }]" :to="{ name: 'DeliveryRoutesList' }">Routes</router-link>
</li>
<li class="nav-item">
<router-link :class="['nav-link', { active: props.activeTab === 'Destinations' }]" :to="{ name: 'DestinationsList' }">Destinations</router-link>
</li>

</ul>
</template>
2 changes: 1 addition & 1 deletion web/admin/src/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export let config = {
version: "1.13.0",
version: "1.14.0",
adminAppNavName: import.meta.env.VITE_ADMIN_APP_NAV_NAME || 'ADMIN_APP_NAV_NAME',
adminAppNavImg: import.meta.env.VITE_ADMIN_APP_NAV_IMG || null,
appNavName: import.meta.env.VITE_APP_NAV_NAME || 'APP_NAV_NAME',
Expand Down
6 changes: 6 additions & 0 deletions web/admin/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,11 @@ fetch('/__/firebase/init.json').then(async response => {
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.directive('focused', {
mounted: (el)=>{
el.focus()
}
})

app.mount('#app')
})
50 changes: 39 additions & 11 deletions web/admin/src/router/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import Login from '@/views/Login.vue'
import NotFound from '@/components/NotFound.vue'
import VolunteerRegistration from '@/views/VolunteerRegistration.vue'
import VolunteersPage from '@/views/VolunteersPage.vue'
import { config } from '@/config'
Expand All @@ -11,33 +8,33 @@ const routes = [
{
path: '/',
name: 'Home',
component: Home,
component: () => import('@/views/Home.vue'),
meta: { requiresLogin: true },
},
{
path: '/login',
name: 'Login',
component: Login,
component: () => import('@/views/Login.vue'),
},
{
path: '/terms',
name: 'Terms',
component: () => import('../views/TermsPage.vue'),
component: () => import('@/views/TermsPage.vue'),
},
{
path: '/privacy-policy',
name: 'Privacy',
component: () => import('../views/PrivacyPage.vue'),
component: () => import('@/views/PrivacyPage.vue'),
},
{
path: '/pending',
name: 'Pending',
component: () => import('../views/Pending.vue'),
component: () => import('@/views/Pending.vue'),
},
{
path: '/forgot-password',
name: 'ForgotPassword',
component: () => import('../views/ForgotPassword.vue'),
component: () => import('@/views/ForgotPassword.vue'),
},
{
path: '/register',
Expand Down Expand Up @@ -151,6 +148,37 @@ const routes = [
component: () => import('@/views/ConfidentialityPage.vue'),
meta: { requiresLogin: true },
},
{
path: '/delivery/dashboard',
name: 'DeliveryDashboard',
component: () => import('@/views/delivery/DeliveryDashboardPage.vue'),
meta: { requiresLogin: true, admin: true },
},
{
path: '/delivery/list',
name: 'DeliveryList',
component: () => import('@/views/delivery/DeliveryListPage.vue'),
meta: { requiresLogin: true, admin: true },
},
{
path: '/delivery/destinations',
name: 'DestinationsList',
component: () => import('@/views/delivery/DestinationsListPage.vue'),
meta: { requiresLogin: true, admin: true },
},
{
path: '/delivery/destination/:id?',
name: 'DestinationPage',
component: () => import('@/views/delivery/DestinationPage.vue'),
props: true,
meta: { requiresLogin: true },
},
{
path: '/delivery/routes',
name: 'DeliveryRoutesList',
component: () => import('@/views/delivery/RouteListPage.vue'),
meta: { requiresLogin: true, admin: true },
},
{
path: '/admin/reports',
name: 'AdminReportPage',
Expand All @@ -160,7 +188,7 @@ const routes = [
{
path: '/contact',
name: 'Contact',
component: () => import('../views/ContactPage.vue'),
component: () => import('@/views/ContactPage.vue'),
},
{
path: '/user-guide',
Expand All @@ -175,7 +203,7 @@ const routes = [
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound,
component: () => import('@/components/NotFound.vue'),
}
]

Expand Down
2 changes: 1 addition & 1 deletion web/admin/src/views/ProfilePage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const acceptTermsError = ref(false)
const save = async ()=>{
await updateDoc(profileRef, profile.value)
if (user.data.displayName != profile.value.displayname) {
if (user.data.displayName != profile.value.displayname && (user.data.uid == userId.value)) {
const auth = getAuth()
updateProfile(auth.currentUser, {
Expand Down
7 changes: 6 additions & 1 deletion web/admin/src/views/ReleaseNotesPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
<template>
<div class="container">
<h1>Release Notes</h1>
<h2 id="1.13.0">January , 2024 - 1.13.0</h2>
<h2 id="1.14.0">January 24, 2024 - 1.14.0</h2>
<ul>
<li><a href="https://github.com/ncosd/food-pantry-app/issues/287">#287</a> Add delivery section for admins.</li>
<li>Fix bug where displayname overwritten when an admin changes the profile for another user.</li>
</ul>
<h2 id="1.13.0">January 20, 2024 - 1.13.0</h2>
<ul>
<li><a href="https://github.com/ncosd/food-pantry-app/issues/275">#275</a> Add sorting the column headers on Locations page.</li>
<li><a href="https://github.com/ncosd/food-pantry-app/issues/281">#281</a> Display and filter if a volunteer wants to be a driver and if they are approved.</li>
Expand Down
138 changes: 138 additions & 0 deletions web/admin/src/views/delivery/DeliveryDashboardPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<script setup>
import { ref, onBeforeMount } from 'vue'
import { useAuthUserStore } from '@/stores/authUser'
import DeliveryTabs from '@/components/delivery/DeliveryTabs.vue'
import { collection, getCountFromServer, getFirestore, doc, addDoc, query, where, setDoc } from 'firebase/firestore'
const user = useAuthUserStore()
const db = getFirestore()
const numTotalDestinations = ref('0')
const numOnHold = ref('0')
const numNoRoute = ref('0')
const numDrivers = ref('0')
const numApprovedDrivers = ref('0')
const numActiveVolunteers = ref('0')
onBeforeMount( async () => {
const destCollection = collection(db, 'deliverydestination')
const numTotalSnap = await getCountFromServer(query(destCollection))
numTotalDestinations.value = numTotalSnap.data().count
const numHoldSnap = await getCountFromServer(query(destCollection, where('onHold', '==', true)))
numOnHold.value = numHoldSnap.data().count
// TODO: calculate numNoRoute
numNoRoute.value = numTotalDestinations.value - numOnHold.value
const numDriversSnap = await getCountFromServer(query(collection(db, 'volunteerprofilestate'),
where('status', '==', 'active'),
where('isDriver', '==', true)))
numDrivers.value = numDriversSnap.data().count
const numApprovedDriversSnap = await getCountFromServer(query(collection(db, 'volunteerprofilestate'),
where('status', '==', 'active'),
where('isDriver', '==', true),
where('isApprovedDriver', '==', true),
))
numApprovedDrivers.value = numApprovedDriversSnap.data().count
const numActiveVolunteersSnap = await getCountFromServer(query(collection(db, 'volunteerprofilestate'),
where('status', '==', 'active')))
numActiveVolunteers.value = numActiveVolunteersSnap.data().count
})
</script>

<template>
<div class="container">
<DeliveryTabs activeTab="Dashboard" ></DeliveryTabs>

<div class="row my-3">
<div class="col-4">
<div class="card h-100">
<div class="card-body">
<div class="row">
<div class="col"><h5 class="card-title">Total Destinations</h5></div>
<div class="col-2"><i class="bi bi-geo-alt fs-3"></i></div>
</div >
<h1 class="text-center">{{ numTotalDestinations }}</h1>
</div>
</div >
</div >

<div class="col-4">
<div class="card h-100">
<div class="card-body">
<div class="row">
<div class="col"><h5 class="card-title">Destinations on hold</h5></div>
<div class="col-2"><i class="bi bi-hourglass-split fs-3"></i></div>
</div >
<h1 class="text-center">{{ numOnHold }}</h1>
</div>
</div >
</div >

<div class="col-4">
<div class="card h-100">
<div class="card-body">
<div class="row">
<div class="col"><h5 class="card-title">Destinations Not on a Route</h5></div>
<div class="col-3">
<i v-if="numNoRoute > 0" class="bi bi-exclamation-diamond text-danger fs-3"></i>
<i v-else class="bi bi-check-circle fs-3"></i>
</div>
</div >
<h1 class="text-center">{{ numNoRoute }}</h1>
</div>
</div >
</div >
</div>

<div class="row my-3">
<div class="col-4">
<div class="card h-100">
<div class="card-body">
<div class="row">
<div class="col"><h5 class="card-title">Drivers</h5></div>
<div class="col-2"><i class="bi bi-car-front fs-3"></i></div>
</div >
<h1 class="text-center">{{ numDrivers }}</h1>
</div>
</div >
</div >

<div class="col-4">
<div class="card h-100">
<div class="card-body">
<div class="row">
<div class="col"><h5 class="card-title">Approved Drivers</h5></div>
<div class="col-2"><i class="bi bi-car-front text-success fs-3"></i></div>
</div >
<h1 class="text-center">{{ numApprovedDrivers }}</h1>
</div>
</div >
</div >

<div class="col-4">
<div class="card h-100">
<div class="card-body">
<div class="row">
<div class="col"><h5 class="card-title">Volunteers</h5></div>
<div class="col-2"><i class="bi bi-person fs-3"></i></div>
</div >
<h1 class="text-center">{{ numActiveVolunteers }}</h1>
</div>
</div >
</div >

</div>


<h2>There are no deliveries scheduled today.</h2>




</div>
</template>
15 changes: 15 additions & 0 deletions web/admin/src/views/delivery/DeliveryListPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup>
import { ref } from 'vue'
import DeliveryTabs from '@/components/delivery/DeliveryTabs.vue'
</script>

<template>
<div class="container">

<DeliveryTabs activeTab="Deliveries" ></DeliveryTabs>



</div>
</template>
Loading

0 comments on commit f51e517

Please sign in to comment.