mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 09:13:24 +00:00
FIX - refine SkyRide layout and ride details
This commit is contained in:
@@ -2502,7 +2502,7 @@ const defaultLocales: LocaleTree = {
|
||||
home: 'Home',
|
||||
rides: 'Rides',
|
||||
activity: 'Activity',
|
||||
messages: 'Messages',
|
||||
messages: 'Chat',
|
||||
profile: 'Profile',
|
||||
},
|
||||
rides: 'Your Rides',
|
||||
|
||||
@@ -25,7 +25,9 @@ const ride: SkyRideRide = {
|
||||
createdAt: 1_755_000_000,
|
||||
currency: '$',
|
||||
destination,
|
||||
distanceMeters: 5_200,
|
||||
driver: null,
|
||||
durationSeconds: 640,
|
||||
id: 'ride-1',
|
||||
pickup,
|
||||
price: 48,
|
||||
|
||||
@@ -87,7 +87,9 @@ export type SkyRideRide = {
|
||||
createdAt: number
|
||||
currency: string
|
||||
destination: SkyRideLocation
|
||||
distanceMeters: number
|
||||
driver: SkyRideDriver | null
|
||||
durationSeconds: number
|
||||
finalPrice?: number
|
||||
id: string
|
||||
passenger?: SkyRidePassenger
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const source = readFileSync(
|
||||
new URL('./SkyRideApp.vue', import.meta.url),
|
||||
'utf8',
|
||||
)
|
||||
const types = readFileSync(
|
||||
new URL('../../types/skyride.ts', import.meta.url),
|
||||
'utf8',
|
||||
)
|
||||
|
||||
describe('SkyRide app layout', () => {
|
||||
it('shows the server-authoritative ride distance in history', () => {
|
||||
expect(types).toContain('distanceMeters: number')
|
||||
expect(source).toContain('formatRideDistance(ride.distanceMeters)')
|
||||
expect(source).toContain('skyride-history-card__distance')
|
||||
})
|
||||
|
||||
it('aligns rider and activity surfaces to one content width', () => {
|
||||
expect(source).toMatch(
|
||||
/\.skyride-location-list,\s*\.skyride-activity-list\s*\{[^}]*margin-inline:\s*2px !important;/s,
|
||||
)
|
||||
expect(source).toMatch(
|
||||
/\.skyride-home-panel\s*\{[^}]*background:\s*linear-gradient/s,
|
||||
)
|
||||
})
|
||||
|
||||
it('uses a compact swipeable profile editor with equal actions', () => {
|
||||
expect(source).toContain('class="skyride-profile-sheet"')
|
||||
expect(source).toContain('swipe-to-close')
|
||||
expect(source).toContain('@swipeclose="closeProfileEditor"')
|
||||
expect(source).toMatch(
|
||||
/\.skyride-profile-sheet :deep\(\.sky-sheet__panel\)\s*\{[^}]*max-height:\s*78%;/s,
|
||||
)
|
||||
expect(source.match(/<SkyButton\s+block\s+large\s+rounded/g)).toHaveLength(
|
||||
2,
|
||||
)
|
||||
expect(source).toContain('skyride-profile-media-button')
|
||||
})
|
||||
})
|
||||
@@ -229,6 +229,10 @@ function formatQuoteDistance(
|
||||
)
|
||||
}
|
||||
|
||||
function formatRideDistance(distanceMeters: number): string {
|
||||
return formatQuoteDistance(Math.max(0, distanceMeters) / 1000, 'kilometer')
|
||||
}
|
||||
|
||||
function formatDistanceRate(option: SkyRideQuoteOption): string {
|
||||
const unitKey =
|
||||
skyride.quote?.distanceUnit === 'mile' ? 'perMile' : 'perKilometer'
|
||||
@@ -1256,12 +1260,18 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="skyride-history-card__footer">
|
||||
<span>{{
|
||||
ride.driver?.name ??
|
||||
ride.passenger?.name ??
|
||||
phone.t('Apps.skyride.ride')
|
||||
}}</span
|
||||
><strong>{{
|
||||
<div class="skyride-history-card__meta">
|
||||
<span>{{
|
||||
ride.driver?.name ??
|
||||
ride.passenger?.name ??
|
||||
phone.t('Apps.skyride.ride')
|
||||
}}</span>
|
||||
<span class="skyride-history-card__distance">
|
||||
<Route :size="13" aria-hidden="true" />
|
||||
{{ formatRideDistance(ride.distanceMeters) }}
|
||||
</span>
|
||||
</div>
|
||||
<strong>{{
|
||||
formatMoney(ride.finalPrice ?? ride.price, ride.currency)
|
||||
}}</strong>
|
||||
</div>
|
||||
@@ -1497,11 +1507,12 @@ onBeforeUnmount(() => {
|
||||
class="skyride-profile-sheet"
|
||||
:opened="profileEditorOpened"
|
||||
:aria-label="phone.t('Apps.skyride.editProfile')"
|
||||
swipe-to-close
|
||||
@backdropclick="closeProfileEditor"
|
||||
@escape="closeProfileEditor"
|
||||
@swipeclose="closeProfileEditor"
|
||||
>
|
||||
<section class="skyride-profile-editor">
|
||||
<div class="skyride-sheet__handle" aria-hidden="true"></div>
|
||||
<div class="skyride-sheet__title">
|
||||
<div>
|
||||
<span>{{ phone.t('Apps.skyride.profile') }}</span>
|
||||
@@ -1524,10 +1535,18 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<strong>{{ phone.t('Apps.skyride.profilePhoto') }}</strong>
|
||||
<div>
|
||||
<SkyButton outline rounded @click="openProfileMedia('photos')">
|
||||
<SkyButton
|
||||
rounded
|
||||
class="skyride-profile-media-button"
|
||||
@click="openProfileMedia('photos')"
|
||||
>
|
||||
<Images :size="17" /> {{ phone.t('Apps.skyride.gallery') }}
|
||||
</SkyButton>
|
||||
<SkyButton outline rounded @click="openProfileMedia('camera')">
|
||||
<SkyButton
|
||||
rounded
|
||||
class="skyride-profile-media-button"
|
||||
@click="openProfileMedia('camera')"
|
||||
>
|
||||
<Camera :size="17" /> {{ phone.t('Apps.skyride.camera') }}
|
||||
</SkyButton>
|
||||
</div>
|
||||
@@ -1556,6 +1575,7 @@ onBeforeUnmount(() => {
|
||||
<div class="skyride-profile-editor__actions">
|
||||
<SkyButton
|
||||
block
|
||||
large
|
||||
rounded
|
||||
variant="secondary"
|
||||
@click="closeProfileEditor"
|
||||
@@ -1737,6 +1757,7 @@ onBeforeUnmount(() => {
|
||||
.skyride-app {
|
||||
--ride-accent: #f5c518;
|
||||
--ride-accent-strong: #725600;
|
||||
--ride-bg-rgb: 244 244 247;
|
||||
--ride-bg: #f4f4f7;
|
||||
--ride-card: rgba(255, 255, 255, 0.88);
|
||||
--ride-card-strong: #fff;
|
||||
@@ -1744,6 +1765,7 @@ onBeforeUnmount(() => {
|
||||
--ride-text: #171719;
|
||||
--ride-muted: #707078;
|
||||
--ride-map: #07131f;
|
||||
--ride-profile-media-bg: #725600;
|
||||
--sky-bg: var(--ride-bg);
|
||||
--sky-surface: var(--ride-card-strong);
|
||||
--sky-surface-muted: #e6e6eb;
|
||||
@@ -1760,6 +1782,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
.skyride-app--dark {
|
||||
--ride-accent-strong: #f5c518;
|
||||
--ride-bg-rgb: 8 9 11;
|
||||
--ride-bg: #08090b;
|
||||
--ride-card: rgba(29, 30, 33, 0.9);
|
||||
--ride-card-strong: #1c1d20;
|
||||
@@ -1767,6 +1790,7 @@ onBeforeUnmount(() => {
|
||||
--ride-text: #f7f7f8;
|
||||
--ride-muted: #a2a2aa;
|
||||
--ride-map: #050a10;
|
||||
--ride-profile-media-bg: #9b7600;
|
||||
--sky-surface-muted: #2c2c2e;
|
||||
--sky-danger: #ff453a;
|
||||
}
|
||||
@@ -1884,7 +1908,12 @@ onBeforeUnmount(() => {
|
||||
.skyride-home-panel {
|
||||
min-height: 320px;
|
||||
margin-top: 0;
|
||||
background: var(--ride-bg);
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(var(--ride-bg-rgb) / 0) 0,
|
||||
rgb(var(--ride-bg-rgb) / 0.78) 54px,
|
||||
var(--ride-bg) 112px
|
||||
);
|
||||
}
|
||||
|
||||
.skyride-heading,
|
||||
@@ -1950,6 +1979,11 @@ onBeforeUnmount(() => {
|
||||
margin-block: 0 14px;
|
||||
}
|
||||
|
||||
.skyride-location-list,
|
||||
.skyride-activity-list {
|
||||
margin-inline: 2px !important;
|
||||
}
|
||||
|
||||
.skyride-location-list :deep(li),
|
||||
.skyride-service-list :deep(li),
|
||||
.skyride-activity-list :deep(li),
|
||||
@@ -2514,10 +2548,30 @@ onBeforeUnmount(() => {
|
||||
|
||||
.skyride-history-card__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.skyride-history-card__meta {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.skyride-history-card__distance {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.skyride-history-card__distance > svg {
|
||||
flex: 0 0 auto;
|
||||
color: var(--ride-accent-strong);
|
||||
}
|
||||
|
||||
.skyride-message-contact > svg {
|
||||
color: var(--ride-muted);
|
||||
}
|
||||
@@ -2651,6 +2705,7 @@ button.skyride-profile-avatar--editable {
|
||||
font-weight: 600;
|
||||
line-height: 13px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.skyride-tab-pane :deep(> .sky-tab-button .sky-tab-button__icon) {
|
||||
@@ -2675,24 +2730,24 @@ button.skyride-profile-avatar--editable {
|
||||
|
||||
.skyride-profile-editor {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding: calc(var(--sky-safe-area-top) + 8px) 14px
|
||||
calc(var(--sky-safe-area-bottom) + 12px);
|
||||
min-height: 0;
|
||||
padding: 4px 14px calc(var(--sky-safe-area-bottom) + 12px);
|
||||
color: var(--ride-text);
|
||||
background: var(--ride-bg);
|
||||
border-radius: 0;
|
||||
border-radius: 0 0 28px 28px;
|
||||
}
|
||||
|
||||
.skyride-profile-sheet :deep(.sky-overlay-backdrop) {
|
||||
background: var(--ride-bg);
|
||||
background: rgba(0, 0, 0, 0.38);
|
||||
}
|
||||
|
||||
.skyride-profile-sheet :deep(.sky-sheet__panel) {
|
||||
top: 0;
|
||||
max-height: none;
|
||||
top: auto;
|
||||
max-height: 78%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
border-radius: 28px 28px 0 0;
|
||||
background: var(--ride-bg);
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -2724,6 +2779,20 @@ button.skyride-profile-avatar--editable {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.skyride-profile-editor__avatar :deep(.skyride-profile-media-button) {
|
||||
border-color: var(--ride-profile-media-bg);
|
||||
background: var(--ride-profile-media-bg);
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.skyride-profile-editor__avatar
|
||||
:deep(.skyride-profile-media-button:active:not(:disabled)) {
|
||||
border-color: var(--ride-profile-media-bg);
|
||||
background: var(--ride-profile-media-bg);
|
||||
color: #fff !important;
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
|
||||
.skyride-profile-editor__actions {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
@@ -1114,7 +1114,9 @@ let skyRideAvailableRequests = [
|
||||
createdAt: unixTime(-90),
|
||||
currency: '$',
|
||||
destination: skyRideQuickLocations[1],
|
||||
distanceMeters: 4200,
|
||||
driver: null,
|
||||
durationSeconds: 480,
|
||||
id: 'skyride-request-demo',
|
||||
passenger: {
|
||||
avatarUrl:
|
||||
@@ -1136,7 +1138,9 @@ let skyRideHistory = [
|
||||
createdAt: unixTime(-22 * 60 * 60),
|
||||
currency: '$',
|
||||
destination: skyRideQuickLocations[3],
|
||||
distanceMeters: 4800,
|
||||
driver: skyRideDriver,
|
||||
durationSeconds: 620,
|
||||
finalPrice: 31,
|
||||
id: 'skyride-history-1',
|
||||
passenger: skyRidePassenger,
|
||||
@@ -1150,7 +1154,9 @@ let skyRideHistory = [
|
||||
createdAt: unixTime(-3 * 24 * 60 * 60),
|
||||
currency: '$',
|
||||
destination: skyRideQuickLocations[2],
|
||||
distanceMeters: 18700,
|
||||
driver: skyRideDriver,
|
||||
durationSeconds: 1380,
|
||||
finalPrice: 68,
|
||||
id: 'skyride-history-2',
|
||||
passenger: skyRidePassenger,
|
||||
@@ -7411,7 +7417,9 @@ app.post('/api/:endpoint', (request, response) => {
|
||||
createdAt: now,
|
||||
currency: quote.option.currency,
|
||||
destination: quote.destination,
|
||||
distanceMeters: quote.distanceMeters,
|
||||
driver: null,
|
||||
durationSeconds: quote.durationSeconds,
|
||||
id: `skyride-ride-${skyRideSequence++}`,
|
||||
passenger: skyRidePassenger,
|
||||
pickup: quote.pickup,
|
||||
|
||||
@@ -1187,7 +1187,7 @@ Locales["en"] = {
|
||||
cancelled = "This ride is no longer active.",
|
||||
},
|
||||
navigation = "SkyRide navigation",
|
||||
tabs = { home = "Home", rides = "Rides", activity = "Activity", messages = "Messages", profile = "Profile" },
|
||||
tabs = { home = "Home", rides = "Rides", activity = "Activity", messages = "Chat", profile = "Profile" },
|
||||
rides = "Your Rides", ridesBody = "Review completed and cancelled rides.", noRides = "No rides yet",
|
||||
noRidesBody = "Completed and cancelled rides will appear here.", activity = "Activity",
|
||||
activityBody = "Recent trip updates and milestones.", noActivity = "No recent activity",
|
||||
|
||||
Reference in New Issue
Block a user