From eecf64c1c60b1a0ad509ca52119ec97bce40395f Mon Sep 17 00:00:00 2001 From: Till JS Date: Mon, 27 Apr 2026 14:14:08 +0200 Subject: [PATCH] feat(community,feedback): +5 reward chip + Phase 3.F legacy-cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UI: - FeedbackQuickModal Success-State + Onboarding-Wish Confirm zeigen +5-Mana-Reward-Chip mit reward-in-Animation. Sofortiger Sichtbarer Reziprozitäts-Loop. Legacy-Cleanup (Phase 3.F): - @mana/feedback dropped: - FeedbackPage.svelte, FeedbackCard.svelte, FeedbackList.svelte, FeedbackForm.svelte, VoteButton.svelte, StatusBadge.svelte (alles Pre-Reactions-Markup, durch Community-Modul ersetzt) - vote/unvote/toggleVote/getPublicFeedback service-shims - VoteResponse, voteCount, userHasVoted Types - mana-web dropped: - lib/modules/feedback/ListView.svelte - routes/(app)/feedback/+page.svelte - app-registry-Eintrag 'feedback' (nur Bug-Reports — Community macht das ohnehin besser via /community) Pre-launch saubere Lösung: keine Backward-Compat-Shims, keine alten Markup-Reste. ReactionBar bleibt der einzige Voting-Surface, /community ist die einzige Feedback-Surface. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../apps/web/src/lib/app-registry/apps.ts | 10 - .../feedback/FeedbackQuickModal.svelte | 43 ++ .../src/lib/modules/feedback/ListView.svelte | 20 - .../src/routes/(app)/feedback/+page.svelte | 10 - .../routes/(app)/onboarding/wish/+page.svelte | 49 ++- packages/feedback/src/FeedbackCard.svelte | 165 -------- packages/feedback/src/FeedbackForm.svelte | 191 --------- packages/feedback/src/FeedbackList.svelte | 58 --- packages/feedback/src/FeedbackPage.svelte | 395 ------------------ packages/feedback/src/StatusBadge.svelte | 31 -- packages/feedback/src/VoteButton.svelte | 91 ---- packages/feedback/src/api.ts | 7 - .../feedback/src/createFeedbackService.ts | 27 -- packages/feedback/src/feedback.ts | 3 - packages/feedback/src/index.ts | 7 - 15 files changed, 90 insertions(+), 1017 deletions(-) delete mode 100644 apps/mana/apps/web/src/lib/modules/feedback/ListView.svelte delete mode 100644 apps/mana/apps/web/src/routes/(app)/feedback/+page.svelte delete mode 100644 packages/feedback/src/FeedbackCard.svelte delete mode 100644 packages/feedback/src/FeedbackForm.svelte delete mode 100644 packages/feedback/src/FeedbackList.svelte delete mode 100644 packages/feedback/src/FeedbackPage.svelte delete mode 100644 packages/feedback/src/StatusBadge.svelte delete mode 100644 packages/feedback/src/VoteButton.svelte diff --git a/apps/mana/apps/web/src/lib/app-registry/apps.ts b/apps/mana/apps/web/src/lib/app-registry/apps.ts index 7aa4fc18a..010b223fd 100644 --- a/apps/mana/apps/web/src/lib/app-registry/apps.ts +++ b/apps/mana/apps/web/src/lib/app-registry/apps.ts @@ -1323,16 +1323,6 @@ registerApp({ }, }); -registerApp({ - id: 'feedback', - name: 'Feedback', - color: '#8B5CF6', - icon: ChatCircleDots, - views: { - list: { load: () => import('$lib/modules/feedback/ListView.svelte') }, - }, -}); - registerApp({ id: 'community', name: 'Community', diff --git a/apps/mana/apps/web/src/lib/components/feedback/FeedbackQuickModal.svelte b/apps/mana/apps/web/src/lib/components/feedback/FeedbackQuickModal.svelte index 9fe31b021..8c5b6cf1e 100644 --- a/apps/mana/apps/web/src/lib/components/feedback/FeedbackQuickModal.svelte +++ b/apps/mana/apps/web/src/lib/components/feedback/FeedbackQuickModal.svelte @@ -105,6 +105,10 @@ Dein Feedback ist eingegangen — sichtbar als {submittedDisplayName}.

+
+ +5 + Mana Credits +
{#if isPublic}

Es taucht in der Community-Page auf, sobald wir es freigeben.

{:else} @@ -261,6 +265,45 @@ margin-top: 0.5rem; } + .reward-chip { + align-self: flex-start; + display: inline-flex; + align-items: baseline; + gap: 0.375rem; + padding: 0.4375rem 0.75rem; + border-radius: 999px; + background: linear-gradient( + 135deg, + hsl(var(--color-primary) / 0.18), + hsl(var(--color-primary) / 0.08) + ); + color: hsl(var(--color-primary)); + border: 1px solid hsl(var(--color-primary) / 0.3); + font-weight: 600; + animation: reward-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1); + } + + .reward-amount { + font-size: 1rem; + font-variant-numeric: tabular-nums; + } + + .reward-label { + font-size: 0.8125rem; + opacity: 0.85; + } + + @keyframes reward-in { + from { + opacity: 0; + transform: translateY(-6px) scale(0.92); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } + } + .context-badge { align-self: flex-start; padding: 0.25rem 0.5rem; diff --git a/apps/mana/apps/web/src/lib/modules/feedback/ListView.svelte b/apps/mana/apps/web/src/lib/modules/feedback/ListView.svelte deleted file mode 100644 index e51eac279..000000000 --- a/apps/mana/apps/web/src/lib/modules/feedback/ListView.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - diff --git a/apps/mana/apps/web/src/routes/(app)/feedback/+page.svelte b/apps/mana/apps/web/src/routes/(app)/feedback/+page.svelte deleted file mode 100644 index 573842145..000000000 --- a/apps/mana/apps/web/src/routes/(app)/feedback/+page.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/apps/mana/apps/web/src/routes/(app)/onboarding/wish/+page.svelte b/apps/mana/apps/web/src/routes/(app)/onboarding/wish/+page.svelte index 5c43f0e96..fa02ca6dc 100644 --- a/apps/mana/apps/web/src/routes/(app)/onboarding/wish/+page.svelte +++ b/apps/mana/apps/web/src/routes/(app)/onboarding/wish/+page.svelte @@ -138,7 +138,11 @@ {#if submittedDisplayName} {/if} @@ -319,11 +323,52 @@ } .preview { - padding: 0.625rem 0.875rem; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 0.875rem; border-radius: 0.625rem; background: hsl(var(--color-primary) / 0.1); color: hsl(var(--color-primary)); font-size: 0.8125rem; text-align: center; } + + .reward-chip { + display: inline-flex; + align-items: baseline; + gap: 0.375rem; + padding: 0.4375rem 0.75rem; + border-radius: 999px; + background: linear-gradient( + 135deg, + hsl(var(--color-primary) / 0.18), + hsl(var(--color-primary) / 0.08) + ); + border: 1px solid hsl(var(--color-primary) / 0.35); + font-weight: 600; + animation: reward-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1); + } + + .reward-amount { + font-size: 1rem; + font-variant-numeric: tabular-nums; + } + + .reward-label { + font-size: 0.8125rem; + opacity: 0.85; + } + + @keyframes reward-in { + from { + opacity: 0; + transform: translateY(-6px) scale(0.92); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } + } diff --git a/packages/feedback/src/FeedbackCard.svelte b/packages/feedback/src/FeedbackCard.svelte deleted file mode 100644 index ee3d75c78..000000000 --- a/packages/feedback/src/FeedbackCard.svelte +++ /dev/null @@ -1,165 +0,0 @@ - - - - - diff --git a/packages/feedback/src/FeedbackForm.svelte b/packages/feedback/src/FeedbackForm.svelte deleted file mode 100644 index 22f337729..000000000 --- a/packages/feedback/src/FeedbackForm.svelte +++ /dev/null @@ -1,191 +0,0 @@ - - - - - diff --git a/packages/feedback/src/FeedbackList.svelte b/packages/feedback/src/FeedbackList.svelte deleted file mode 100644 index 15d1fa93c..000000000 --- a/packages/feedback/src/FeedbackList.svelte +++ /dev/null @@ -1,58 +0,0 @@ - - - - - diff --git a/packages/feedback/src/FeedbackPage.svelte b/packages/feedback/src/FeedbackPage.svelte deleted file mode 100644 index 676719248..000000000 --- a/packages/feedback/src/FeedbackPage.svelte +++ /dev/null @@ -1,395 +0,0 @@ - - - - {pageTitle} - {appName} - - - - - diff --git a/packages/feedback/src/StatusBadge.svelte b/packages/feedback/src/StatusBadge.svelte deleted file mode 100644 index 6d95c6f46..000000000 --- a/packages/feedback/src/StatusBadge.svelte +++ /dev/null @@ -1,31 +0,0 @@ - - - - {config.label} - - - diff --git a/packages/feedback/src/VoteButton.svelte b/packages/feedback/src/VoteButton.svelte deleted file mode 100644 index 433816963..000000000 --- a/packages/feedback/src/VoteButton.svelte +++ /dev/null @@ -1,91 +0,0 @@ - - - - - diff --git a/packages/feedback/src/api.ts b/packages/feedback/src/api.ts index 1691edf39..e978b827a 100644 --- a/packages/feedback/src/api.ts +++ b/packages/feedback/src/api.ts @@ -73,10 +73,3 @@ export interface AdminPatchInput { } export type ReactInput = { emoji: ReactionEmoji }; - -export interface VoteResponse { - success: boolean; - newVoteCount?: number; - userHasVoted?: boolean; - error?: string; -} diff --git a/packages/feedback/src/createFeedbackService.ts b/packages/feedback/src/createFeedbackService.ts index bf18356a2..432464e0b 100644 --- a/packages/feedback/src/createFeedbackService.ts +++ b/packages/feedback/src/createFeedbackService.ts @@ -16,7 +16,6 @@ import type { ReactionResponse, AdminPatchInput, ReactInput, - VoteResponse, } from './api'; import type { FeedbackServiceConfig } from './types'; import type { PublicFeedbackItem, ReactionEmoji } from './feedback'; @@ -148,27 +147,6 @@ export function createFeedbackService(config: FeedbackServiceConfig) { }); } - // ── Legacy (back-compat shims) ───────────────────────────────── - // Older callers still use vote/unvote — translate to 👍-reaction toggles. - - async function vote(feedbackId: string): Promise { - const res = await toggleReaction(feedbackId, '👍'); - return { - success: true, - newVoteCount: res.reactions['👍'] ?? 0, - userHasVoted: res.userHasReacted, - }; - } - const unvote = vote; // toggle, semantically idempotent for legacy callers - async function toggleVote(feedbackId: string): Promise { - return vote(feedbackId); - } - - async function getPublicFeedback(query?: FeedbackQueryParams): Promise { - const items = await getPublicFeed(query); - return { items: items as unknown as FeedbackListResponse['items'] }; - } - return { createFeedback, getPublicFeed, @@ -180,11 +158,6 @@ export function createFeedbackService(config: FeedbackServiceConfig) { deleteFeedback, adminListAll, adminPatch, - // Legacy (deprecated): - getPublicFeedback, - vote, - unvote, - toggleVote, }; } diff --git a/packages/feedback/src/feedback.ts b/packages/feedback/src/feedback.ts index fee300e72..bedcda457 100644 --- a/packages/feedback/src/feedback.ts +++ b/packages/feedback/src/feedback.ts @@ -78,7 +78,6 @@ export interface Feedback { status: FeedbackStatus; isPublic: boolean; adminResponse?: string; - voteCount: number; displayHash?: string; displayName?: string; moduleContext?: string; @@ -90,8 +89,6 @@ export interface Feedback { updatedAt: string; publishedAt?: string; completedAt?: string; - // Legacy / derived for older UI surfaces: - userHasVoted?: boolean; } export const FEEDBACK_CATEGORY_LABELS: Record = { diff --git a/packages/feedback/src/index.ts b/packages/feedback/src/index.ts index a81685d1c..59520dfaa 100644 --- a/packages/feedback/src/index.ts +++ b/packages/feedback/src/index.ts @@ -31,7 +31,6 @@ export { type ReactionResponse, type AdminPatchInput, type ReactInput, - type VoteResponse, } from './api'; // Services @@ -43,10 +42,4 @@ export { export type { FeedbackServiceConfig, PublicFeedbackServiceConfig } from './types'; // UI Components -export { default as FeedbackPage } from './FeedbackPage.svelte'; -export { default as FeedbackForm } from './FeedbackForm.svelte'; -export { default as FeedbackList } from './FeedbackList.svelte'; -export { default as FeedbackCard } from './FeedbackCard.svelte'; -export { default as VoteButton } from './VoteButton.svelte'; export { default as ReactionBar } from './ReactionBar.svelte'; -export { default as StatusBadge } from './StatusBadge.svelte';