display user kinds verbatim

This commit is contained in:
Yisroel Baum 2026-08-14 09:54:43 +03:00
parent 2101ab50d2
commit 74feb38300
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
5 changed files with 28 additions and 50 deletions

View file

@ -139,7 +139,7 @@ describe('set scheduling', () => {
cy.get('h1').should('have.text', 'Schedule Bible')
cy.get('#schedule-level option').then(($options) => {
expect([...$options].map((option) => option.textContent?.trim())).to.deep.equal(
['Choose a level', 'Book (2)', 'Portion (2)', 'Chapter_sections-v2 (2)'],
['Choose a level', 'book (2)', 'portion (2)', 'Chapter_sections-v2 (2)'],
)
})
cy.get('#schedule-level').select('3')
@ -155,6 +155,7 @@ describe('set scheduling', () => {
.should('contain.text', 'Genesis / Creation / Chapter 1')
.find('.assignment-kind')
.should('have.text', 'Chapter_sections-v2')
.and('have.css', 'text-transform', 'none')
cy.get('[data-schedule-date="2026-08-11"]')
.should('contain.text', 'Rest day')
.and('not.contain.text', 'Chapter 1')
@ -208,7 +209,10 @@ describe('set scheduling', () => {
cy.wait('@me')
cy.wait('@schedule')
cy.get('h1').should('have.text', 'Bible schedule')
cy.get('.eyebrow').should('have.text', 'Chapter_sections-v2 plan')
cy.get('.eyebrow')
.should('have.text', 'Chapter_sections-v2 plan')
.find('.schedule-kind')
.should('have.css', 'text-transform', 'none')
cy.contains('2 Chapter_sections-v2 assignments across 3 days').should('be.visible')
cy.intercept('GET', '**/api/schedules/74', {
@ -253,7 +257,9 @@ describe('set scheduling', () => {
cy.get('ul[aria-label="Your schedules"]')
.should('contain.text', 'Bible')
.and('contain.text', '2 assignments')
cy.get('.schedule-card__heading p').should('have.text', 'Chapter_sections-v2')
cy.get('.schedule-card__heading p')
.should('have.text', 'Chapter_sections-v2')
.and('have.css', 'text-transform', 'none')
cy.contains('a', 'Bible').should('have.attr', 'href', '/schedules/73')
})
})

View file

@ -87,7 +87,7 @@ defineProps<{
font-size: 0.62rem;
font-weight: 800;
letter-spacing: 0.1em;
text-transform: uppercase;
text-transform: none;
}
@media (max-width: 37.5rem) {

View file

@ -26,12 +26,7 @@ const form = reactive({
const fieldErrors = ref<ScheduleFieldErrors>({})
const levels = computed(() =>
(layout.value?.levels ?? [])
.filter((level) => level.elementCount > 0)
.map((level) => ({
...level,
label: humanizeKind(level.kind),
})),
(layout.value?.levels ?? []).filter((level) => level.elementCount > 0),
)
const scheduleFormSchema = z
@ -111,12 +106,6 @@ async function retry(): Promise<void> {
await setLayoutStore.fetchSetLayout(currentSetId.value)
}
}
function humanizeKind(kind: string): string {
const words = kind.replaceAll(/[_-]+/g, ' ')
return words.charAt(0).toUpperCase() + words.slice(1)
}
</script>
<template>
@ -163,7 +152,7 @@ function humanizeKind(kind: string): string {
>
<option :value="null">Choose a level</option>
<option v-for="level in levels" :key="level.id" :value="level.id">
{{ level.label }} ({{ level.elementCount }})
{{ level.kind }} ({{ level.elementCount }})
</option>
</select>
<p v-if="fieldErrors.levelId" id="schedule-level-error" class="field-error">

View file

@ -15,12 +15,6 @@ onMounted(async () => {
await Promise.all([setsStore.fetchSets(), schedulesStore.fetchSchedules()])
})
function humanizeKind(kind: string): string {
const words = kind.replaceAll(/[_-]+/g, ' ')
return words.charAt(0).toUpperCase() + words.slice(1)
}
function formatDate(value: string): string {
return new Intl.DateTimeFormat('en', {
dateStyle: 'medium',
@ -73,7 +67,7 @@ function formatDate(value: string): string {
>
<article class="schedule-card">
<div class="schedule-card__heading">
<p>{{ humanizeKind(schedule.elementKind) }}</p>
<p class="schedule-card__kind">{{ schedule.elementKind }}</p>
<span>{{ schedule.assignmentCount }} assignments</span>
</div>
<h3>{{ schedule.set.name }}</h3>
@ -310,6 +304,10 @@ h1 {
margin: 0;
}
.schedule-card__kind {
text-transform: none;
}
.schedule-card h3 {
margin: 2rem 0 0;
font-family: Georgia, 'Times New Roman', serif;

View file

@ -39,28 +39,6 @@ function formatDate(value: string): string {
timeZone: 'UTC',
}).format(new Date(`${value}T00:00:00Z`))
}
function humanizeKind(kind: string): string {
const words = kind.replaceAll(/[_-]+/g, ' ')
return words.charAt(0).toUpperCase() + words.slice(1)
}
function pluralKind(kind: string, count: number): string {
if (count === 1) {
return kind
}
if (kind.endsWith('y')) {
return `${kind.slice(0, -1)}ies`
}
if (kind.endsWith('s')) {
return kind
}
return `${kind}s`
}
</script>
<template>
@ -87,11 +65,14 @@ function pluralKind(kind: string, count: number): string {
<template v-else-if="activeSchedule !== null">
<header class="schedule-introduction">
<p class="eyebrow">{{ humanizeKind(activeSchedule.elementKind) }} plan</p>
<p class="eyebrow">
<span class="schedule-kind">{{ activeSchedule.elementKind }}</span> plan
</p>
<h1>{{ activeSchedule.set.name }} schedule</h1>
<p class="schedule-summary">
{{ activeSchedule.assignmentCount }}
{{ pluralKind(activeSchedule.elementKind, activeSchedule.assignmentCount) }} across
{{ activeSchedule.elementKind }}
{{ activeSchedule.assignmentCount === 1 ? 'assignment' : 'assignments' }} across
{{ activeSchedule.days.length }}
{{ activeSchedule.days.length === 1 ? 'day' : 'days' }}
</p>
@ -119,7 +100,7 @@ function pluralKind(kind: string, count: number): string {
<ul v-else class="assignment-list">
<li v-for="assignment in day.assignments" :key="assignment.id">
<span class="assignment-path">{{ assignment.element.path.join(' / ') }}</span>
<span class="assignment-kind">{{ humanizeKind(assignment.element.kind) }}</span>
<span class="assignment-kind">{{ assignment.element.kind }}</span>
</li>
</ul>
</li>
@ -173,6 +154,10 @@ function pluralKind(kind: string, count: number): string {
text-transform: uppercase;
}
.schedule-kind {
text-transform: none;
}
h1 {
margin: 0;
font-family: Georgia, 'Times New Roman', serif;
@ -265,7 +250,7 @@ h1 {
font-size: 0.62rem;
font-weight: 800;
letter-spacing: 0.1em;
text-transform: uppercase;
text-transform: none;
}
.page-state {