Tests, UX improvements.

This commit is contained in:
Jennie Robinson Faber 2026-04-05 14:25:29 +01:00
parent 4e6f5d36b8
commit 0ae18f495e
63 changed files with 1384 additions and 2330 deletions

View file

@ -180,6 +180,18 @@
</p>
</div>
<!-- Recent Activity -->
<div v-if="activityEntries.length" class="profile-section">
<div class="section-label">Recent Activity</div>
<div class="activity-list">
<div v-for="entry in activityEntries" :key="entry._id" class="activity-item">
<UIcon :name="getActivity(entry).icon" class="activity-icon" />
<span class="activity-text">{{ getActivity(entry).text }}</span>
<span class="activity-time">{{ formatRelativeDate(entry.timestamp) }}</span>
</div>
</div>
</div>
<!-- Auth Notice -->
<div v-if="!isAuthenticated" class="auth-notice">
<p>Sign in to see full profile details</p>
@ -206,6 +218,8 @@
</template>
<script setup>
import { formatActivity } from '~/utils/activityText'
const route = useRoute();
const { isAuthenticated } = useAuth();
const { openLoginModal } = useLoginModal();
@ -231,6 +245,26 @@ const getInitials = (name) => {
// Fetch member data no await so the component renders immediately (no Suspense)
const { data, pending, error: fetchError } = useFetch(`/api/members/${id}`);
// Fetch public activity
const { data: activityData } = useFetch(`/api/members/${id}/activity`, {
params: { limit: 5 },
default: () => ({ entries: [] })
})
const activityEntries = computed(() => activityData.value?.entries || [])
const getActivity = (entry) => formatActivity(entry)
const formatRelativeDate = (date) => {
const now = new Date()
const d = new Date(date)
const diffInSeconds = Math.floor((now - d) / 1000)
if (diffInSeconds < 60) return 'just now'
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
}
const member = computed(() => data.value?.member || null);
const pageBreadcrumbTitle = useState("pageBreadcrumbTitle", () => "");
@ -467,6 +501,39 @@ useHead({
margin-bottom: 6px;
}
/* ---- ACTIVITY ---- */
.activity-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.activity-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
}
.activity-icon {
width: 14px;
height: 14px;
color: var(--text-faint);
flex-shrink: 0;
}
.activity-text {
color: var(--text-dim);
flex: 1;
min-width: 0;
}
.activity-time {
color: var(--text-faint);
font-size: 11px;
flex-shrink: 0;
}
/* ---- AUTH NOTICE ---- */
.auth-notice {
padding: 20px;