Skip to content

Commit

Permalink
feat: add lines engagement configuration interface
Browse files Browse the repository at this point in the history
  • Loading branch information
cailloumajor committed Sep 27, 2023
1 parent 2c8a434 commit fddeda9
Show file tree
Hide file tree
Showing 13 changed files with 716 additions and 5 deletions.
2 changes: 1 addition & 1 deletion quasar.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ module.exports = configure(function (/* ctx */) {
// directives: [],

// Quasar plugins
plugins: ["Loading", "Meta", "SessionStorage"],
plugins: ["Loading", "Meta", "Notify", "SessionStorage"],
},

// animations: 'all', // --- includes all animations
Expand Down
16 changes: 16 additions & 0 deletions src/api-mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,30 @@ export const timelineData = new Uint8Array([
])

const handlers = [
rest.get(`${configApiPath}/common`, (req, res, ctx) =>
res(
ctx.json({
partnerGroups: {
testzone: ["partner1", "partner2", "partner3"],
},
shiftStartTimes: ["05:00:00", "12:00:00", "20:00:00"],
weekStart: {
day: "Tuesday",
shiftIndex: 2,
},
}),
),
),
rest.get(`${configApiPath}/:id`, (req, res, ctx) =>
res(
ctx.json({
title: "Test Title",
targetCycleTime: 12.34,
shiftEngaged: [...Array(21)].map(() => Math.random() < 0.5),
}),
),
),
rest.patch(`${configApiPath}/:id`, (req, res, ctx) => res(ctx.status(200))),
rest.get(`${computeApiPath}/timeline/:id`, (req, res, ctx) =>
res(
ctx.set("Content-Length", timelineData.byteLength.toString()),
Expand Down
29 changes: 29 additions & 0 deletions src/layouts/UserFacingLayout.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<QLayout view="lHh Lpr lFf">
<QHeader elevated>
<QToolbar>
<QToolbarTitle data-cy="layout-title">
{{ title }}
</QToolbarTitle>
</QToolbar>
</QHeader>

<QPageContainer>
<RouterView />
</QPageContainer>
</QLayout>
</template>

<script setup lang="ts">
import { computed } from "vue"
import { useI18n } from "vue-i18n"
import { useUserFacingLayoutStore } from "src/stores/user-facing-layout"
const { t } = useI18n()
const store = useUserFacingLayoutStore()
const title = computed(() =>
[t("digitalFactory"), store.titleExtension].join("\u00a0\u00a0"),
)
</script>
15 changes: 15 additions & 0 deletions src/layouts/__tests__/UserFacingLayout.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useUserFacingLayoutStore } from "src/stores/user-facing-layout"

import UserFacingLayout from "../UserFacingLayout.vue"

describe("UserFacingLayout", () => {
it("gets title extension from the store", () => {
cy.mount(UserFacingLayout)

cy.wrap(useUserFacingLayoutStore()).invoke("$patch", {
titleExtension: "some extension",
})

cy.dataCy("layout-title").should("contain.text", "some extension")
})
})
8 changes: 7 additions & 1 deletion src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@
"runAtCadence": "Running at cadence",
"campaignChange": "Campaign change"
},
"statusDuration": "For {duration} (since {since})"
"statusDuration": "For {duration} (since {since})",
"digitalFactory": "Digital Factory",
"linesEngagement": "Lines Engagement",
"weekDays": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
"checkAll": "Check all",
"uncheckAll": "Uncheck all",
"save": "Save"
}
8 changes: 7 additions & 1 deletion src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@
"runAtCadence": "Marche à cadence",
"campaignChange": "Changement de campagne"
},
"statusDuration": "Depuis {duration} ({since})"
"statusDuration": "Depuis {duration} ({since})",
"digitalFactory": "Usine Numérique",
"linesEngagement": "Engagement des lignes",
"weekDays": ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"],
"checkAll": "Tout cocher",
"uncheckAll": "Tout décocher",
"save": "Enregistrer"
}
227 changes: 227 additions & 0 deletions src/pages/EngagementConfig.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
<template>
<div class="q-ma-lg">
<QBanner
v-if="errorText"
class="error-banner bg-red text-white"
data-cy="error-banner"
>
{{ errorText }}
</QBanner>
<div>
<div class="container">
<div><!-- Do not remove, used to shift headers by one position --></div>
<div
v-for="(header, headerIndex) in headers"
:key="`header-${headerIndex}`"
class="header-cell text-center text-weight-medium q-mt-auto"
data-cy="header-cell"
>
{{ header }}
</div>
<template
v-for="(row, rowIndex) in linesEngagement"
:key="`row-${rowIndex}`"
>
<div
class="row-title q-mr-md q-my-auto text-right text-weight-medium"
data-cy="row-title"
>
{{ row.title }}
</div>
<div
v-for="(shift, shiftIndex) in row.shifts"
:key="`row-${rowIndex}-col-${shiftIndex}`"
:class="{
'bg-blue-1': Math.floor(shiftIndex / 3) % 2 === 0,
'bg-blue-grey-1': Math.floor(shiftIndex / 3) % 2 === 1,
}"
class="shift-cell text-center q-py-sm"
>
<QCheckbox v-model="shift.engaged" data-cy="checkbox" dense />

Check warning on line 40 in src/pages/EngagementConfig.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/EngagementConfig.vue#L40

Added line #L40 was not covered by tests
</div>
</template>
</div>
<div class="row flex-center q-gutter-md q-mt-sm">
<QBtn
color="grey-6"
data-cy="check-all-button"
icon="check_box"
:label="t('checkAll')"
@click="switchAll(true)"
/>
<QBtn
color="grey-6"
data-cy="uncheck-all-button"
icon="check_box_outline_blank"
:label="t('uncheckAll')"
@click="switchAll(false)"
/>
<QBtn
color="primary"
data-cy="save-button"
icon="save"
:disable="disableSubmit"
:label="t('save')"
@click="submit"
/>
</div>
</div>
</div>
</template>

<script setup lang="ts">
import { mande } from "mande"
import { useQuasar } from "quasar"
import { computed, ref } from "vue"
import { useI18n } from "vue-i18n"
import { ZodError } from "zod"
import { configApiPath } from "src/global"
import {
engagementCommonConfigSchema,
engagementPartnerConfigSchema,
} from "src/schemas"
import { useUserFacingLayoutStore } from "src/stores/user-facing-layout"
interface LineEngagement {
id: string
title: string
shifts: {
engaged: boolean
}[]
}
const props = defineProps<{
zone: string
}>()
const $q = useQuasar()
const { t, rt, getLocaleMessage } = useI18n()
const layoutStore = useUserFacingLayoutStore()
console.log(getLocaleMessage("en-US"))
const firstDay = ref("Monday")
const shifts = ref(["0"])
const firstShiftIndex = ref(0)
const headers = computed(() => {
const enWeekDays = getLocaleMessage("en-US").weekDays
const firstDayIndex = enWeekDays
.map((message) => rt(message))
.findIndex((enDay) =>
firstDay.value.toLowerCase().startsWith(enDay.toLowerCase()),
)
return [...Array(21)].map((value, index) => {
const shiftIndex = (index + firstShiftIndex.value) % shifts.value.length
const dayIndex =
(Math.floor(index / shifts.value.length) + firstDayIndex) %
enWeekDays.length
const dayText = shiftIndex === 0 ? t(`weekDays[${dayIndex}]`) + "\n" : ""
return dayText + shifts.value[shiftIndex]
})
})
const linesEngagement = ref<LineEngagement[]>([])
const errorText = ref("")
const disableSubmit = ref(false)
function switchAll(state: boolean) {
for (const row of linesEngagement.value) {
for (const shift of row.shifts) {
shift.engaged = state
}
}
}
function submit() {
disableSubmit.value = true
Promise.all(
linesEngagement.value.map(({ id, shifts }) =>
configApi.patch(id, {
shiftEngaged: shifts.map(({ engaged }) => engaged),
}),
),
)
.then(() => {
setTimeout(() => {
disableSubmit.value = false

Check warning on line 149 in src/pages/EngagementConfig.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/EngagementConfig.vue#L149

Added line #L149 was not covered by tests
}, 2000)
})
.catch((err) => {
$q.notify({
type: "negative",
message: String(err),
onDismiss: () => {
disableSubmit.value = false

Check warning on line 157 in src/pages/EngagementConfig.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/EngagementConfig.vue#L156-L157

Added lines #L156 - L157 were not covered by tests
},
})
})
}
layoutStore.titleExtension = t("linesEngagement")
const configApi = mande(configApiPath)
configApi
.get("/common")
.then((resp) => engagementCommonConfigSchema.parseAsync(resp))
.then((commonConfig) => {
firstDay.value = commonConfig.weekStart.day
shifts.value = commonConfig.shiftStartTimes.map((time) =>
time.replace(/:\d\d$/, ""),
)
firstShiftIndex.value = commonConfig.weekStart.shiftIndex
return Promise.all(
commonConfig.partnerGroups[props.zone].map((partner) =>
configApi
.get(partner)
.then((resp) => engagementPartnerConfigSchema.parseAsync(resp))
.then((config) => ({ id: partner, config })),
),
)
})
.then((partnerConfigs) => {
linesEngagement.value = partnerConfigs.map(
({ id, config: { title, shiftEngaged } }) => ({
id,
title,
shifts: shiftEngaged.map((engaged) => ({ engaged })),
}),
)
})
.catch((err) => {
if (err instanceof ZodError) {
errorText.value = JSON.stringify(err.format(), null, 4)
} else {
errorText.value = String(err)
}
})
</script>

<style lang="scss" scoped>
.container {
display: grid;
grid-template-columns: min-content repeat(21, 1fr);
}
.header-cell {
position: relative;
left: -50%;
white-space: pre-line;
}
.shift-cell {
border-left: 2px solid gray;
}
.row-title {
grid-column-start: 1;
white-space: nowrap;
}
.error-banner {
white-space: pre;
}
</style>
Loading

0 comments on commit fddeda9

Please sign in to comment.