feat: add theme toggle, shared KanbanCard, keyboard shortcuts
All checks were successful
Deploy / deploy (push) Successful in 11s

Previously unstaged files from prior sessions: ThemeContext,
ThemeToggle, KanbanCard, useKeyboardShortcuts hook, and updated
Header, KanbanBoard, Issues, Tasks, PostProduction, index.css.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
fahed
2026-03-04 12:12:34 +03:00
parent c31e6222d7
commit fa6345f63e
10 changed files with 313 additions and 247 deletions

View File

@@ -5,6 +5,7 @@ import { useAuth } from '../contexts/AuthContext'
import { useLanguage } from '../i18n/LanguageContext'
import { api, PLATFORMS } from '../utils/api'
import KanbanBoard from '../components/KanbanBoard'
import KanbanCard from '../components/KanbanCard'
import PostCard from '../components/PostCard'
import PostDetailPanel from '../components/PostDetailPanel'
import DatePresetPicker from '../components/DatePresetPicker'
@@ -22,7 +23,7 @@ const EMPTY_POST = {
export default function PostProduction() {
const { t, lang } = useLanguage()
const { teamMembers, brands } = useContext(AppContext)
const { teamMembers, brands, getBrandName } = useContext(AppContext)
const { canEditResource } = useAuth()
const toast = useToast()
const [posts, setPosts] = useState([])
@@ -54,12 +55,15 @@ export default function PostProduction() {
}
const handleMovePost = async (postId, newStatus) => {
// Optimistic update — move the card instantly
const prev = posts
setPosts(posts.map(p => p._id === postId ? { ...p, status: newStatus } : p))
try {
await api.patch(`/posts/${postId}`, { status: newStatus })
toast.success(t('posts.statusUpdated'))
loadPosts()
} catch (err) {
console.error('Move failed:', err)
setPosts(prev)
if (err.message?.includes('Cannot publish')) {
setMoveError(t('posts.publishRequired'))
setTimeout(() => setMoveError(''), 5000)
@@ -258,7 +262,32 @@ export default function PostProduction() {
)}
{view === 'kanban' ? (
<KanbanBoard posts={filteredPosts} onPostClick={openEdit} onMovePost={handleMovePost} />
<KanbanBoard
columns={[
{ id: 'draft', label: t('posts.status.draft'), color: 'bg-gray-400' },
{ id: 'in_review', label: t('posts.status.in_review'), color: 'bg-amber-400' },
{ id: 'approved', label: t('posts.status.approved'), color: 'bg-blue-400' },
{ id: 'scheduled', label: t('posts.status.scheduled'), color: 'bg-purple-400' },
{ id: 'published', label: t('posts.status.published'), color: 'bg-emerald-400' },
]}
items={filteredPosts}
getItemId={(p) => p._id}
onMove={(id, status) => handleMovePost(id, status)}
renderCard={(post) => {
const brandName = getBrandName(post.brand_id || post.brandId) || post.brand_name || post.brand
const assignee = post.assignedToName || post.assignedName || post.assigned_name
return (
<KanbanCard
title={post.title}
thumbnail={post.thumbnail_url}
brandName={brandName}
assigneeName={assignee}
date={post.scheduledDate}
onClick={() => openEdit(post)}
/>
)
}}
/>
) : (
<div className="bg-white rounded-xl border border-border overflow-hidden">
{filteredPosts.length === 0 ? (