Extract reusable UI components to reduce DRY violations
- Created StatusBadge component: Standardizes status badge display - Supports tradeStatus prop for trade-specific styling - Supports variant prop for simple badges (success/error/ready) - Eliminates repetitive badge style combinations - Created EmptyState component: Standardizes empty state display - Handles loading and empty states consistently - Supports message, hint, and action props - Used across trades, invites, admin pages - Created ConfirmationButton component: Standardizes confirmation flows - Two-step confirmation pattern (action -> confirm/cancel) - Supports different variants (danger/success/primary) - Handles loading states automatically - Used for cancel, complete, no-show actions - Migrated pages to use new components: - trades/page.tsx: StatusBadge, EmptyState, ConfirmationButton - trades/[id]/page.tsx: StatusBadge - invites/page.tsx: StatusBadge, EmptyState - admin/trades/page.tsx: StatusBadge, EmptyState, ConfirmationButton - admin/invites/page.tsx: StatusBadge Benefits: - Eliminated ~50+ lines of repetitive badge styling code - Consistent UI patterns across all pages - Easier to maintain and update styling - Better type safety All tests passing (32 frontend, 33 e2e)
This commit is contained in:
parent
b86b506d72
commit
1a47b3643f
9 changed files with 309 additions and 425 deletions
50
frontend/app/components/EmptyState.tsx
Normal file
50
frontend/app/components/EmptyState.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { utilityStyles } from "../styles/shared";
|
||||
|
||||
interface EmptyStateProps {
|
||||
/** Message to display when empty */
|
||||
message: string;
|
||||
/** Optional hint/subtitle text */
|
||||
hint?: string;
|
||||
/** Show loading state instead of empty message */
|
||||
isLoading?: boolean;
|
||||
/** Optional action element (e.g., link or button) */
|
||||
action?: React.ReactNode;
|
||||
/** Custom style override */
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standardized empty state component.
|
||||
* Displays a message when there's no data, or a loading state.
|
||||
*/
|
||||
export function EmptyState({ message, hint, isLoading, action, style }: EmptyStateProps) {
|
||||
if (isLoading) {
|
||||
return <div style={{ ...utilityStyles.emptyState, ...style }}>Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ ...utilityStyles.emptyState, ...style }}>
|
||||
<p style={styles.emptyText}>{message}</p>
|
||||
{hint && <p style={styles.emptyHint}>{hint}</p>}
|
||||
{action && <div style={styles.action}>{action}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const styles: Record<string, React.CSSProperties> = {
|
||||
emptyText: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
fontSize: "1rem",
|
||||
margin: 0,
|
||||
},
|
||||
emptyHint: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
color: "rgba(255, 255, 255, 0.4)",
|
||||
fontSize: "0.85rem",
|
||||
marginTop: "0.5rem",
|
||||
},
|
||||
action: {
|
||||
marginTop: "1rem",
|
||||
},
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue