// screens/inbox.jsx — Conversation list
// Localized via window.tr() / window.useLang(). Falls back to EN literals
// when used standalone in the design canvas (no i18n).
//
// Mirrors the real app's two-source inbox: DMs *and* post/reel Comments,
// switched with the segmented control at the top.
const _trI = (k, fb) => (window.tr ? window.tr(k, fb) : fb);
const _useLangI = () => (window.useLang ? window.useLang() : 'en');
// Inbox row. `kind` is 'dm' (default) or 'comment'. Comment rows show a
// small swatch standing in for the post/reel thumbnail + a "commented on"
// subhead so the source is unambiguous at a glance.
function InboxRow({ theme, name, handle, preview, time, unread, drafted, lastFromYou, kind = 'dm', postTint }) {
const t = useT(theme);
const isComment = kind === 'comment';
return (
{/* Leading visual — avatar for DMs, or a tile that pairs the
commenter's avatar with a post thumbnail for comments. */}
{isComment ? (
{/* Subtle pattern to suggest content without faking imagery */}
{/* small avatar tucked in the corner */}
) : (
)}
{name}
{isComment ? _trI('inbox.commentedOn', 'commented on a post') : `@${handle}`}
{drafted && (
{_trI('inbox.row.drafted', 'Drafted ·')}
)}
{lastFromYou && !drafted && {_trI('inbox.row.you', 'You: ')}}
{preview}
{time}
{drafted ? (
{_trI('inbox.row.replyReady', 'Reply ready')}
) : unread ? (
) : (
)}
);
}
// Top-level source switcher: All / DMs / Comments. iOS-style filled pill
// on a tinted track. The whole control sits on one row, full width.
function SourceSegmentedControl({ theme, active = 'all' }) {
const t = useT(theme);
const items = [
{ id: 'all', label: _trI('inbox.source.all', 'All') },
{ id: 'dms', label: _trI('inbox.source.dms', 'DMs') },
{ id: 'comments', label: _trI('inbox.source.comments', 'Comments') },
];
return (
{items.map(it => {
const sel = it.id === active;
return (
{it.label}
);
})}
);
}
function InboxFilters({ theme, active = 'all' }) {
const t = useT(theme);
const items = [
{ id: 'all', label: _trI('inbox.filter.all', 'All'), count: 24 },
{ id: 'ai', label: _trI('inbox.filter.ai', 'AI drafted'), count: 6, sparkle: true },
{ id: 'mine', label: _trI('inbox.filter.mine', 'Needs me'), count: 4 },
{ id: 'closed', label: _trI('inbox.filter.closed', 'Resolved'), count: 132 },
];
return (
{items.map(it => {
const sel = it.id === active;
return (
{it.sparkle && }
{it.label}
{it.count}
);
})}
);
}
// `source` picks which segmented-control tab is active so callers can
// screenshot "Comments" view too. Mixed rows in 'all', filtered otherwise.
function ConversationList({ theme = 'light', source = 'all' }) {
_useLangI(); // subscribe to language changes
const t = useT(theme);
const dms = [
{ kind: 'dm', name: 'Marina Costa', handle: 'marinacostaa', preview: _trI('inbox.preview.marina'), time: '2:18 PM', unread: true, drafted: true },
{ kind: 'dm', name: 'Theo Mendez', handle: 'theo.builds', preview: _trI('inbox.preview.theo'), time: '1:52 PM', unread: true, drafted: true },
{ kind: 'dm', name: 'Priya Raman', handle: 'priya.r', preview: _trI('inbox.preview.priya'), time: '1:14 PM', lastFromYou: true },
{ kind: 'dm', name: 'Júlia Almeida', handle: 'juliaaa', preview: _trI('inbox.preview.julia'), time: '12:40 PM', unread: true },
{ kind: 'dm', name: 'Sam Okafor', handle: 'samo.k', preview: _trI('inbox.preview.sam'), time: '11:22 AM', lastFromYou: true },
{ kind: 'dm', name: 'Noor Ahmadi', handle: 'noor.studio', preview: _trI('inbox.preview.noor'), time: _trI('inbox.time.yesterday') },
];
const comments = [
{ kind: 'comment', name: 'Lila Romero', handle: 'lilaa', preview: _trI('inbox.comment.lila'), time: '2:05 PM', unread: true, drafted: true, postTint: { bg: '#FFE7E2', fg: '#C25540' } },
{ kind: 'comment', name: 'Beto Silva', handle: 'beto.s', preview: _trI('inbox.comment.beto'), time: '1:40 PM', unread: true, postTint: { bg: '#E0E7F2', fg: '#3F5680' } },
{ kind: 'comment', name: 'Ana Vidal', handle: 'anavidall', preview: _trI('inbox.comment.ana'), time: '12:08 PM', drafted: true, postTint: { bg: '#EDE3D2', fg: '#7A5520' } },
{ kind: 'comment', name: 'Rafa Tavares', handle: 'rafatav', preview: _trI('inbox.comment.rafa'), time: _trI('inbox.time.yesterday'), postTint: { bg: '#F1E1E8', fg: '#8B3F66' } },
];
// 'all' interleaves to demonstrate that both sources land in one place.
// Source-specific tabs show only that type.
let rows;
if (source === 'dms') rows = dms;
else if (source === 'comments') rows = comments;
else rows = [
dms[0], comments[0], dms[1], comments[1], dms[2], dms[3], comments[2], dms[4], comments[3], dms[5],
];
return (
{/* Large title header */}
{_trI('inbox.repliesReady', '6 replies ready')}
{_trI('inbox.title', 'Inbox')}
{/* search */}
{_trI('inbox.search', 'Search conversations')}
{/* Source switcher — DMs vs. post/reel Comments. */}
{/* Secondary filters (drafted / needs me / resolved) */}
{rows.map((r, i) => )}
{/* Tab bar */}
);
}
function TabBar({ theme, active }) {
const t = useT(theme);
const tabs = [
{ id: 'inbox', label: _trI('tab.inbox', 'Inbox'), icon: Icons.chat },
{ id: 'approvals', label: _trI('tab.approvals', 'Approvals'), icon: Icons.sparkle },
{ id: 'rules', label: _trI('tab.rules', 'Rules'), icon: Icons.flow },
{ id: 'settings', label: _trI('tab.settings', 'Account'), icon: Icons.settings },
];
return (
{tabs.map(tab => {
const sel = tab.id === active;
const I = tab.icon;
const col = sel ? t.accent : t.secondary;
return (
);
})}
);
}
window.ConversationList = ConversationList;
window.TabBar = TabBar;