Compare commits
9 Commits
c51eacb261
...
0.12.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 51ab99fc61 | |||
| d52f51d6e1 | |||
| c1760ae376 | |||
| 6d51327e56 | |||
| 96044ae1ed | |||
| f972a41e45 | |||
| 13b01dfba8 | |||
| fd8724db8f | |||
| 8885dbd722 |
@@ -43,7 +43,7 @@ test.describe('US1: Cancel RSVP from Event Detail View', () => {
|
||||
await expect(statusBar).toBeVisible()
|
||||
|
||||
// Cancel button hidden initially
|
||||
await expect(page.getByRole('button', { name: 'Cancel attendance' })).not.toBeVisible()
|
||||
await expect(page.getByRole('button', { name: 'Cancel RSVP' })).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('tapping status bar reveals cancel button', async ({ page, network }) => {
|
||||
@@ -57,7 +57,7 @@ test.describe('US1: Cancel RSVP from Event Detail View', () => {
|
||||
await page.getByRole('button', { name: /You're attending/ }).click()
|
||||
|
||||
// Cancel button appears
|
||||
await expect(page.getByRole('button', { name: 'Cancel attendance' })).toBeVisible()
|
||||
await expect(page.getByRole('button', { name: 'Cancel RSVP' })).toBeVisible()
|
||||
})
|
||||
|
||||
test('confirm cancellation → localStorage cleared, count decremented, bar reset', async ({ page, network }) => {
|
||||
@@ -70,13 +70,13 @@ test.describe('US1: Cancel RSVP from Event Detail View', () => {
|
||||
await page.addInitScript(seedEvents([rsvpSeed()]))
|
||||
await page.goto(`/events/${fullEvent.eventToken}`)
|
||||
|
||||
// Expand → Cancel attendance → Confirm in dialog
|
||||
// Expand → Cancel RSVP → Confirm in dialog
|
||||
await page.getByRole('button', { name: /You're attending/ }).click()
|
||||
await page.locator('.rsvp-bar__cancel').click()
|
||||
|
||||
// Confirm dialog
|
||||
await expect(page.getByText('Your attendance will be permanently cancelled.')).toBeVisible()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel attendance' }).click()
|
||||
await expect(page.getByText('The organizer will no longer see you as attending.')).toBeVisible()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel RSVP' }).click()
|
||||
|
||||
// Bar resets to CTA state
|
||||
await expect(page.getByRole('button', { name: "I'm attending" })).toBeVisible()
|
||||
@@ -108,7 +108,7 @@ test.describe('US1: Cancel RSVP from Event Detail View', () => {
|
||||
// Expand → Cancel → Confirm in dialog
|
||||
await page.getByRole('button', { name: /You're attending/ }).click()
|
||||
await page.locator('.rsvp-bar__cancel').click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel attendance' }).click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel RSVP' }).click()
|
||||
|
||||
// Error message
|
||||
await expect(page.getByText('Could not cancel RSVP. Please try again.')).toBeVisible()
|
||||
@@ -136,7 +136,7 @@ test.describe('US1: Cancel RSVP from Event Detail View', () => {
|
||||
// Cancel first
|
||||
await page.getByRole('button', { name: /You're attending/ }).click()
|
||||
await page.locator('.rsvp-bar__cancel').click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel attendance' }).click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel RSVP' }).click()
|
||||
|
||||
// CTA should be back
|
||||
await expect(page.getByRole('button', { name: "I'm attending" })).toBeVisible()
|
||||
@@ -244,7 +244,7 @@ test.describe('US3: Cancel RSVP with Stale/Invalid Token', () => {
|
||||
// Cancel flow
|
||||
await page.getByRole('button', { name: /You're attending/ }).click()
|
||||
await page.locator('.rsvp-bar__cancel').click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel attendance' }).click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel RSVP' }).click()
|
||||
|
||||
// Treated as success — CTA returns
|
||||
await expect(page.getByRole('button', { name: "I'm attending" })).toBeVisible()
|
||||
|
||||
@@ -139,7 +139,7 @@ test.describe('US5: Visual Distinction for Event Roles', () => {
|
||||
const card = page.locator('.event-card').filter({ hasText: 'Summer BBQ' })
|
||||
const badge = card.locator('.event-card__badge')
|
||||
await expect(badge).toBeVisible()
|
||||
await expect(badge).toHaveText('Organizer')
|
||||
await expect(badge).toHaveText('Organizing')
|
||||
await expect(badge).toHaveClass(/event-card__badge--organizer/)
|
||||
})
|
||||
|
||||
@@ -150,7 +150,7 @@ test.describe('US5: Visual Distinction for Event Roles', () => {
|
||||
const card = page.locator('.event-card').filter({ hasText: 'Team Meeting' })
|
||||
const badge = card.locator('.event-card__badge')
|
||||
await expect(badge).toBeVisible()
|
||||
await expect(badge).toHaveText('Attendee')
|
||||
await expect(badge).toHaveText('Attending')
|
||||
await expect(badge).toHaveClass(/event-card__badge--attendee/)
|
||||
})
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ test.describe('US1: Watch event from detail page', () => {
|
||||
await expect(bookmark).toHaveAttribute('aria-label', 'Stop watching this event')
|
||||
|
||||
// Navigate to event list via back link
|
||||
await page.locator('.detail__back').click()
|
||||
await page.getByLabel('Back to home').click()
|
||||
|
||||
// Event appears with "Watching" label
|
||||
await expect(page.getByText('Summer BBQ')).toBeVisible()
|
||||
@@ -89,7 +89,7 @@ test.describe('US2: Un-watch event from detail page', () => {
|
||||
await expect(bookmark).toHaveAttribute('aria-label', 'Watch this event')
|
||||
|
||||
// Navigate to event list via back link (avoid page.goto re-running addInitScript)
|
||||
await page.locator('.detail__back').click()
|
||||
await page.getByLabel('Back to home').click()
|
||||
|
||||
// Event is gone
|
||||
await expect(page.getByText('Summer BBQ')).not.toBeVisible()
|
||||
@@ -109,8 +109,8 @@ test.describe('US3: Bookmark reflects attending status', () => {
|
||||
await expect(bookmark).not.toBeVisible()
|
||||
|
||||
// Navigate to list via back link
|
||||
await page.locator('.detail__back').click()
|
||||
await expect(page.getByText('Attendee')).toBeVisible()
|
||||
await page.getByLabel('Back to home').click()
|
||||
await expect(page.getByText('Attending')).toBeVisible()
|
||||
await expect(page.getByText('Watching')).not.toBeVisible()
|
||||
})
|
||||
})
|
||||
@@ -129,7 +129,7 @@ test.describe('US4: RSVP cancellation preserves watch status', () => {
|
||||
// Cancel RSVP
|
||||
await page.getByRole('button', { name: /You're attending/ }).click()
|
||||
await page.locator('.rsvp-bar__cancel').click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel attendance' }).click()
|
||||
await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel RSVP' }).click()
|
||||
|
||||
// Bookmark reappears in CTA state, filled because event is still stored
|
||||
const bookmark = page.locator('.rsvp-bar__bookmark-inner')
|
||||
@@ -137,9 +137,9 @@ test.describe('US4: RSVP cancellation preserves watch status', () => {
|
||||
await expect(bookmark).toHaveAttribute('aria-label', 'Stop watching this event')
|
||||
|
||||
// Navigate to list via back link
|
||||
await page.locator('.detail__back').click()
|
||||
await page.getByLabel('Back to home').click()
|
||||
await expect(page.getByText('Watching')).toBeVisible()
|
||||
await expect(page.getByText('Attendee')).not.toBeVisible()
|
||||
await expect(page.getByText('Attending')).not.toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -211,8 +211,8 @@ test.describe('US7: Watcher upgrades to attendee', () => {
|
||||
await expect(bookmark).not.toBeVisible()
|
||||
|
||||
// Navigate to list via back link
|
||||
await page.locator('.detail__back').click()
|
||||
await expect(page.getByText('Attendee')).toBeVisible()
|
||||
await page.getByLabel('Back to home').click()
|
||||
await expect(page.getByText('Attending')).toBeVisible()
|
||||
await expect(page.getByText('Watching')).not.toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<header v-if="route.name !== 'home'" class="app-header">
|
||||
<BackLink />
|
||||
</header>
|
||||
<RouterView />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import { RouterView, useRoute } from 'vue-router'
|
||||
import BackLink from '@/components/BackLink.vue'
|
||||
|
||||
const route = useRoute()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
padding-top: var(--spacing-lg);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
--color-danger-bg-strong: rgba(220, 38, 38, 0.2);
|
||||
--color-danger-border: rgba(220, 38, 38, 0.3);
|
||||
--color-danger-border-strong: rgba(220, 38, 38, 0.4);
|
||||
--color-danger-solid: #d32f2f;
|
||||
--color-danger-solid-hover: #b71c1c;
|
||||
--color-danger-solid-text: #fff;
|
||||
|
||||
/* Glass system */
|
||||
--color-glass: rgba(255, 255, 255, 0.1);
|
||||
@@ -214,7 +217,7 @@ textarea.form-field {
|
||||
|
||||
/* Error message */
|
||||
.field-error {
|
||||
color: #fff;
|
||||
color: var(--color-danger-solid);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
padding-left: 0.25rem;
|
||||
@@ -325,7 +328,8 @@ textarea.form-field {
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.rsvp-form__label {
|
||||
.rsvp-form__label,
|
||||
.cancel-form__label {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-on-gradient);
|
||||
@@ -333,7 +337,7 @@ textarea.form-field {
|
||||
}
|
||||
|
||||
.rsvp-form__field-error {
|
||||
color: #d32f2f;
|
||||
color: var(--color-danger-solid);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
padding-left: 0.25rem;
|
||||
|
||||
28
frontend/src/components/BackLink.vue
Normal file
28
frontend/src/components/BackLink.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<RouterLink to="/" class="back-link" aria-label="Back to home">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="15 18 9 12 15 6" />
|
||||
</svg>
|
||||
<span class="back-link__brand">fete</span>
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterLink } from 'vue-router'
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.back-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.15rem;
|
||||
color: var(--color-text-on-gradient);
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.back-link__brand {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,18 @@
|
||||
<Teleport to="body">
|
||||
<Transition name="sheet">
|
||||
<div v-if="open" class="sheet-backdrop" @click.self="$emit('close')" @keydown.escape="$emit('close')">
|
||||
<div class="sheet" role="dialog" aria-modal="true" :aria-label="label" ref="sheetEl" tabindex="-1">
|
||||
<div
|
||||
class="sheet"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
:aria-label="label"
|
||||
ref="sheetEl"
|
||||
tabindex="-1"
|
||||
:style="dragStyle"
|
||||
@touchstart="onTouchStart"
|
||||
@touchmove="onTouchMove"
|
||||
@touchend="onTouchEnd"
|
||||
>
|
||||
<div class="sheet__handle" aria-hidden="true" />
|
||||
<slot />
|
||||
</div>
|
||||
@@ -12,14 +23,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, nextTick } from 'vue'
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
open: boolean
|
||||
label: string
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
const emit = defineEmits<{
|
||||
close: []
|
||||
}>()
|
||||
|
||||
@@ -39,6 +50,45 @@ watch(
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
/* ── Drag-to-dismiss ── */
|
||||
const DISMISS_THRESHOLD = 100
|
||||
const dragY = ref(0)
|
||||
const dragging = ref(false)
|
||||
let startY = 0
|
||||
|
||||
const dragStyle = computed(() => {
|
||||
if (!dragging.value || dragY.value <= 0) return undefined
|
||||
return {
|
||||
transform: `translateY(${dragY.value}px)`,
|
||||
transition: 'none',
|
||||
}
|
||||
})
|
||||
|
||||
function onTouchStart(e: TouchEvent) {
|
||||
const touch = e.touches[0]
|
||||
if (!touch) return
|
||||
startY = touch.clientY
|
||||
dragging.value = true
|
||||
dragY.value = 0
|
||||
}
|
||||
|
||||
function onTouchMove(e: TouchEvent) {
|
||||
if (!dragging.value) return
|
||||
const touch = e.touches[0]
|
||||
if (!touch) return
|
||||
const delta = touch.clientY - startY
|
||||
if (delta > 0) e.preventDefault()
|
||||
dragY.value = Math.max(0, delta)
|
||||
}
|
||||
|
||||
function onTouchEnd() {
|
||||
if (dragY.value >= DISMISS_THRESHOLD) {
|
||||
emit('close')
|
||||
}
|
||||
dragging.value = false
|
||||
dragY.value = 0
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -139,8 +139,8 @@ watch(
|
||||
}
|
||||
|
||||
.confirm-dialog__btn--confirm {
|
||||
background: #d32f2f;
|
||||
color: #fff;
|
||||
background: var(--color-danger-solid);
|
||||
color: var(--color-danger-solid-text);
|
||||
}
|
||||
|
||||
.confirm-dialog-enter-active,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<span class="event-card__time">{{ displayTime }}</span>
|
||||
</RouterLink>
|
||||
<span v-if="eventRole" class="event-card__badge" :class="`event-card__badge--${eventRole}`">
|
||||
{{ eventRole === 'organizer' ? 'Organizer' : eventRole === 'attendee' ? 'Attendee' : 'Watching' }}
|
||||
{{ eventRole === 'organizer' ? 'Organizing' : eventRole === 'attendee' ? 'Attending' : 'Watching' }}
|
||||
</span>
|
||||
<button
|
||||
class="event-card__delete"
|
||||
@@ -175,7 +175,7 @@ function onTouchEnd() {
|
||||
}
|
||||
|
||||
.event-card__delete:hover {
|
||||
color: #d32f2f;
|
||||
color: var(--color-danger-solid);
|
||||
background: rgba(211, 47, 47, 0.08);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
type="button"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
Cancel attendance
|
||||
Cancel RSVP
|
||||
</button>
|
||||
</Transition>
|
||||
</div>
|
||||
@@ -34,7 +34,7 @@
|
||||
<div v-else class="rsvp-bar__row">
|
||||
<div class="rsvp-bar__cta glow-border glow-border--animated">
|
||||
<button class="rsvp-bar__cta-inner glass-inner" type="button" @click="$emit('open')">
|
||||
I'm attending
|
||||
I'm attending!
|
||||
</button>
|
||||
</div>
|
||||
<div class="rsvp-bar__bookmark glow-border glow-border--animated">
|
||||
|
||||
@@ -55,12 +55,12 @@ describe('EventCard', () => {
|
||||
|
||||
it('renders organizer badge when eventRole is organizer', () => {
|
||||
const wrapper = mountCard({ eventRole: 'organizer' })
|
||||
expect(wrapper.text()).toContain('Organizer')
|
||||
expect(wrapper.text()).toContain('Organizing')
|
||||
})
|
||||
|
||||
it('renders attendee badge when eventRole is attendee', () => {
|
||||
const wrapper = mountCard({ eventRole: 'attendee' })
|
||||
expect(wrapper.text()).toContain('Attendee')
|
||||
expect(wrapper.text()).toContain('Attending')
|
||||
})
|
||||
|
||||
it('renders watcher badge when eventRole is watcher', () => {
|
||||
|
||||
@@ -160,13 +160,13 @@ describe('EventList', () => {
|
||||
const wrapper = mountList()
|
||||
const badge = wrapper.find('.event-card__badge--organizer')
|
||||
expect(badge.exists()).toBe(true)
|
||||
expect(badge.text()).toBe('Organizer')
|
||||
expect(badge.text()).toBe('Organizing')
|
||||
})
|
||||
|
||||
it('assigns attendee role when event has rsvpToken', () => {
|
||||
const wrapper = mountList()
|
||||
const badge = wrapper.find('.event-card__badge--attendee')
|
||||
expect(badge.exists()).toBe(true)
|
||||
expect(badge.text()).toBe('Attendee')
|
||||
expect(badge.text()).toBe('Attending')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ describe('RsvpBar', () => {
|
||||
it('renders CTA button when hasRsvp is false', () => {
|
||||
const wrapper = mount(RsvpBar)
|
||||
expect(wrapper.find('.rsvp-bar__cta').exists()).toBe(true)
|
||||
expect(wrapper.find('.rsvp-bar__cta-inner').text()).toBe("I'm attending")
|
||||
expect(wrapper.find('.rsvp-bar__cta-inner').text()).toBe("I'm attending!")
|
||||
expect(wrapper.find('.rsvp-bar__status').exists()).toBe(false)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<main class="create">
|
||||
<header class="create__header">
|
||||
<RouterLink to="/" class="create__back" aria-label="Back to home">←</RouterLink>
|
||||
<h1 class="create__title">Create</h1>
|
||||
</header>
|
||||
<h1 class="create__title">Great, a Party!</h1>
|
||||
|
||||
<form class="create__form" novalidate @submit.prevent="handleSubmit">
|
||||
<div class="form-group">
|
||||
@@ -76,7 +73,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
import { useEventStorage } from '@/composables/useEventStorage'
|
||||
|
||||
@@ -194,20 +191,7 @@ async function handleSubmit() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-lg);
|
||||
padding-top: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.create__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.create__back {
|
||||
color: var(--color-text-on-gradient);
|
||||
font-size: 1.5rem;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
padding-top: calc(var(--spacing-lg) + 2.5rem);
|
||||
}
|
||||
|
||||
.create__title {
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
alt=""
|
||||
/>
|
||||
<div class="detail__hero-overlay" />
|
||||
<header class="detail__header">
|
||||
<RouterLink to="/" class="detail__back" aria-label="Back to home">←</RouterLink>
|
||||
<span class="detail__brand">fete</span>
|
||||
</header>
|
||||
</div>
|
||||
|
||||
<div class="detail__body">
|
||||
@@ -129,9 +125,9 @@
|
||||
<!-- Cancel confirmation dialog -->
|
||||
<ConfirmDialog
|
||||
:open="confirmCancelOpen"
|
||||
title="Cancel attendance?"
|
||||
message="Your attendance will be permanently cancelled."
|
||||
confirm-label="Cancel attendance"
|
||||
title="Cancel RSVP?"
|
||||
message="The organizer will no longer see you as attending."
|
||||
confirm-label="Cancel RSVP"
|
||||
cancel-label="Keep"
|
||||
@confirm="handleCancelRsvp"
|
||||
@cancel="confirmCancelOpen = false"
|
||||
@@ -168,7 +164,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { api } from '@/api/client'
|
||||
import { useEventStorage } from '@/composables/useEventStorage'
|
||||
import AttendeeList from '@/components/AttendeeList.vue'
|
||||
@@ -437,32 +433,7 @@ onMounted(fetchEvent)
|
||||
var(--color-glass-overlay) 0%,
|
||||
transparent 50%
|
||||
);
|
||||
}
|
||||
|
||||
.detail__header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
padding: var(--spacing-lg) var(--content-padding);
|
||||
padding-top: env(safe-area-inset-top, var(--spacing-lg));
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.detail__back {
|
||||
color: var(--color-text-on-gradient);
|
||||
font-size: 1.5rem;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.detail__brand {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-on-gradient);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.detail__body {
|
||||
@@ -706,15 +677,15 @@ onMounted(fetchEvent)
|
||||
font-family: inherit;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-danger);
|
||||
background: var(--color-danger-bg-strong);
|
||||
border: 1px solid var(--color-danger-border);
|
||||
color: var(--color-danger-solid-text);
|
||||
background: var(--color-danger-solid);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.cancel-form__confirm:hover {
|
||||
background: var(--color-danger-bg-hover);
|
||||
background: var(--color-danger-solid-hover);
|
||||
}
|
||||
|
||||
.cancel-form__confirm:disabled {
|
||||
|
||||
@@ -198,7 +198,7 @@ describe('EventDetailView', () => {
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('.rsvp-bar__cta').exists()).toBe(true)
|
||||
expect(wrapper.find('.rsvp-bar__cta').text()).toBe("I'm attending")
|
||||
expect(wrapper.find('.rsvp-bar__cta').text()).toBe("I'm attending!")
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user