Create Plan from Session. Top bar rounded
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Trash2, Calendar, Clock, ChevronDown, ChevronUp, History as HistoryIcon, Dumbbell, Ruler, Timer, Weight, Edit2, Gauge, Pencil, Save } from 'lucide-react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Trash2, Calendar, Clock, ChevronDown, ChevronUp, History as HistoryIcon, Dumbbell, Ruler, Timer, Weight, Edit2, Gauge, Pencil, Save, MoreVertical, ClipboardList } from 'lucide-react';
|
||||
import { TopBar } from './ui/TopBar';
|
||||
import { WorkoutSession, ExerciseType, WorkoutSet, Language } from '../types';
|
||||
import { t } from '../services/i18n';
|
||||
@@ -9,6 +11,7 @@ import { useSession } from '../context/SessionContext';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { getExercises } from '../services/storage';
|
||||
import { Button } from './ui/Button';
|
||||
import { Ripple } from './ui/Ripple';
|
||||
import { Card } from './ui/Card';
|
||||
import { Modal } from './ui/Modal';
|
||||
import { SideSheet } from './ui/SideSheet';
|
||||
@@ -23,9 +26,11 @@ const History: React.FC<HistoryProps> = ({ lang }) => {
|
||||
const { sessions, updateSession, deleteSession } = useSession();
|
||||
const { currentUser } = useAuth();
|
||||
const userId = currentUser?.id || '';
|
||||
const navigate = useNavigate();
|
||||
const [exercises, setExercises] = useState<import('../types').ExerciseDef[]>([]);
|
||||
|
||||
const [editingSession, setEditingSession] = useState<WorkoutSession | null>(null);
|
||||
const [menuState, setMenuState] = useState<{ id: string, x: number, y: number } | null>(null);
|
||||
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
const [deletingSetInfo, setDeletingSetInfo] = useState<{ sessionId: string, setId: string } | null>(null);
|
||||
@@ -221,28 +226,23 @@ const History: React.FC<HistoryProps> = ({ lang }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-1">
|
||||
<div className="relative">
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setEditingSession(JSON.parse(JSON.stringify(session)));
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
setMenuState({
|
||||
id: session.id,
|
||||
x: rect.right + window.scrollX,
|
||||
y: rect.bottom + window.scrollY
|
||||
});
|
||||
}}
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Session Actions"
|
||||
className="text-on-surface-variant hover:text-primary"
|
||||
>
|
||||
<Pencil size={24} />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setDeletingId(session.id);
|
||||
}}
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-on-surface-variant hover:text-error"
|
||||
>
|
||||
<Trash2 size={24} />
|
||||
<MoreVertical size={24} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -328,6 +328,70 @@ const History: React.FC<HistoryProps> = ({ lang }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* MENU PORTAL */}
|
||||
{menuState && typeof document !== 'undefined' && createPortal(
|
||||
<>
|
||||
<div
|
||||
className="fixed inset-0 z-50"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setMenuState(null);
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute bg-surface-container-high rounded-xl shadow-elevation-2 z-50 min-w-[160px] py-1 flex flex-col overflow-hidden animate-menu-enter origin-top-right"
|
||||
style={{
|
||||
top: menuState.y,
|
||||
left: menuState.x,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
const session = sessions.find(s => s.id === menuState.id);
|
||||
if (session) {
|
||||
navigate(`/plans?createFromSessionId=${session.id}`);
|
||||
}
|
||||
setMenuState(null);
|
||||
}}
|
||||
className="w-full relative overflow-hidden text-left px-4 py-3 hover:bg-on-surface/10 text-on-surface flex items-center gap-3 transition-colors text-sm font-medium"
|
||||
>
|
||||
<Ripple />
|
||||
<ClipboardList size={18} />
|
||||
{t('create_plan', lang) || 'Create Plan'}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
const session = sessions.find(s => s.id === menuState.id);
|
||||
if (session) {
|
||||
setEditingSession(JSON.parse(JSON.stringify(session)));
|
||||
}
|
||||
setMenuState(null);
|
||||
}}
|
||||
className="w-full relative overflow-hidden text-left px-4 py-3 hover:bg-on-surface/10 text-on-surface flex items-center gap-3 transition-colors text-sm font-medium"
|
||||
>
|
||||
<Ripple />
|
||||
<Pencil size={18} />
|
||||
{t('edit', lang)}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setDeletingId(menuState.id);
|
||||
setMenuState(null);
|
||||
}}
|
||||
className="w-full relative overflow-hidden text-left px-4 py-3 hover:bg-error-container/10 text-error flex items-center gap-3 transition-colors text-sm font-medium"
|
||||
>
|
||||
<Ripple color="rgba(242, 184, 181, 0.2)" />
|
||||
<Trash2 size={18} />
|
||||
{t('delete', lang)}
|
||||
</button>
|
||||
</div>
|
||||
</>,
|
||||
document.body
|
||||
)}
|
||||
|
||||
{/* DELETE CONFIRMATION MODAL */}
|
||||
<Modal
|
||||
isOpen={!!(deletingId || deletingSetInfo)}
|
||||
|
||||
Reference in New Issue
Block a user