mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 12:39:39 +02:00
@mana/feedback wird zur Pflege-SSOT für Public-Community-Hub.
- PublicFeedbackItem-Typ: anonymisiertes Item, das nur display_name +
reactions + status führt — kein userId, displayHash, deviceInfo.
- ReactionEmoji ('👍' '❤️' '🚀' '🤔' '🎉') + REACTION_LABELS mit DE-Labels.
- CreateFeedbackInput erweitert um moduleContext + parentId. Reactions
+ score auf Feedback-Type optional gemacht.
- Service-Split:
createFeedbackService — auth-required Submit/React/Manage,
getPublicFeed (auth-enriched mit myReactions)
createPublicFeedbackService — anonymous, SSR-only, getFeed/getItem.
toggleReaction(emoji) statt vote/unvote (legacy-Shims bleiben für
back-compat zu vote → '👍'-Toggle).
- ReactionBar.svelte: Slack-Style emoji-row mit Active-Highlighting für
myReactions, ReadOnly-Mode für Public-SSR. Auto-disabled-Tooltip.
- index.ts re-exportiert die neuen Typen + ReactionBar; FeedbackVote
rausgeschmissen (durch FeedbackReactions im Server-Schema ersetzt).
FeedbackCard + FeedbackPage minimal angepasst, damit svelte-check
clean bleibt — die Legacy-Komponenten bleiben funktional, werden aber
in Phase 3 zu @mana/feedback's neuen Modul-Views ausgemistet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
117 lines
3.2 KiB
TypeScript
117 lines
3.2 KiB
TypeScript
/**
|
|
* Core feedback types — Single source of truth for the @mana/feedback hub.
|
|
*
|
|
* Mana-analytics' Postgres enums (`feedback.feedback_category`,
|
|
* `feedback.feedback_status`) MUST mirror these literal unions exactly.
|
|
* If you add or rename a value here, also write a SQL migration under
|
|
* services/mana-analytics/drizzle/.
|
|
*/
|
|
|
|
export type FeedbackCategory =
|
|
| 'bug'
|
|
| 'feature'
|
|
| 'improvement'
|
|
| 'question'
|
|
| 'praise'
|
|
| 'onboarding-wish'
|
|
| 'other';
|
|
|
|
export type FeedbackStatus =
|
|
| 'submitted'
|
|
| 'under_review'
|
|
| 'planned'
|
|
| 'in_progress'
|
|
| 'completed'
|
|
| 'declined';
|
|
|
|
/**
|
|
* Whitelisted reaction emojis — must mirror REACTION_WEIGHTS in
|
|
* services/mana-analytics/src/services/feedback.ts. Server rejects
|
|
* any emoji not in this list.
|
|
*/
|
|
export const REACTION_EMOJIS = ['👍', '❤️', '🚀', '🤔', '🎉'] as const;
|
|
export type ReactionEmoji = (typeof REACTION_EMOJIS)[number];
|
|
|
|
export const REACTION_LABELS: Record<ReactionEmoji, string> = {
|
|
'👍': 'Will ich auch',
|
|
'❤️': 'Liebe ich',
|
|
'🚀': 'Ship it',
|
|
'🤔': 'Macht mich nachdenklich',
|
|
'🎉': 'Feier',
|
|
};
|
|
|
|
/**
|
|
* Anonymized feedback item as it appears in the public community feed.
|
|
* Never contains userId or other identifying fields — only the
|
|
* persistent display_name pseudonym ("Wachsame Eule #4528").
|
|
*/
|
|
export interface PublicFeedbackItem {
|
|
id: string;
|
|
appId: string;
|
|
title: string | null;
|
|
feedbackText: string;
|
|
category: FeedbackCategory;
|
|
status: FeedbackStatus;
|
|
moduleContext: string | null;
|
|
parentId: string | null;
|
|
displayName: string;
|
|
reactions: Partial<Record<string, number>>;
|
|
score: number;
|
|
adminResponse: string | null;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
/** Auth-only: which emojis the requesting user has reacted with. */
|
|
myReactions?: string[];
|
|
}
|
|
|
|
/**
|
|
* Authenticated, full feedback record (own submissions / admin views).
|
|
* Includes the user-private fields the public feed redacts.
|
|
*/
|
|
export interface Feedback {
|
|
id: string;
|
|
userId: string;
|
|
appId: string;
|
|
title?: string;
|
|
feedbackText: string;
|
|
category: FeedbackCategory;
|
|
status: FeedbackStatus;
|
|
isPublic: boolean;
|
|
adminResponse?: string;
|
|
voteCount: number;
|
|
displayHash?: string;
|
|
displayName?: string;
|
|
moduleContext?: string;
|
|
parentId?: string;
|
|
reactions?: Partial<Record<string, number>>;
|
|
score?: number;
|
|
deviceInfo?: Record<string, unknown>;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
publishedAt?: string;
|
|
completedAt?: string;
|
|
// Legacy / derived for older UI surfaces:
|
|
userHasVoted?: boolean;
|
|
}
|
|
|
|
export const FEEDBACK_CATEGORY_LABELS: Record<FeedbackCategory, string> = {
|
|
bug: 'Bug',
|
|
feature: 'Feature',
|
|
improvement: 'Verbesserung',
|
|
question: 'Frage',
|
|
praise: 'Lob',
|
|
'onboarding-wish': 'Was ich mir wünsche',
|
|
other: 'Sonstiges',
|
|
};
|
|
|
|
export const FEEDBACK_STATUS_CONFIG: Record<
|
|
FeedbackStatus,
|
|
{ label: string; color: string; icon: string }
|
|
> = {
|
|
submitted: { label: 'Eingereicht', color: '#999', icon: 'clock' },
|
|
under_review: { label: 'Wird geprüft', color: '#3498DB', icon: 'eye' },
|
|
planned: { label: 'Geplant', color: '#9B59B6', icon: 'calendar' },
|
|
in_progress: { label: 'In Arbeit', color: '#F39C12', icon: 'loader' },
|
|
completed: { label: 'Umgesetzt', color: '#27AE60', icon: 'check-circle' },
|
|
declined: { label: 'Abgelehnt', color: '#E74C3C', icon: 'x-circle' },
|
|
};
|