diff --git a/.env.example b/.env.example
index 82902b4..9767565 100644
--- a/.env.example
+++ b/.env.example
@@ -10,7 +10,7 @@
PROJECT_NAME=jama
# Image version to run (set by build.sh, or use 'latest')
-JAMA_VERSION=0.9.66
+JAMA_VERSION=0.9.67
# App port — the host port Docker maps to the container
PORT=3000
diff --git a/backend/package.json b/backend/package.json
index c07ec8d..e12722d 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "jama-backend",
- "version": "0.9.66",
+ "version": "0.9.67",
"description": "TeamChat backend server",
"main": "src/index.js",
"scripts": {
diff --git a/build.sh b/build.sh
index 5fedb73..b752455 100644
--- a/build.sh
+++ b/build.sh
@@ -13,7 +13,7 @@
# ─────────────────────────────────────────────────────────────
set -euo pipefail
-VERSION="${1:-0.9.66}"
+VERSION="${1:-0.9.67}"
ACTION="${2:-}"
REGISTRY="${REGISTRY:-}"
IMAGE_NAME="jama"
diff --git a/frontend/package.json b/frontend/package.json
index 28c13b3..889e525 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "jama-frontend",
- "version": "0.9.66",
+ "version": "0.9.67",
"private": true,
"scripts": {
"dev": "vite",
diff --git a/frontend/src/components/SchedulePage.jsx b/frontend/src/components/SchedulePage.jsx
index db6313c..3a0c0c0 100644
--- a/frontend/src/components/SchedulePage.jsx
+++ b/frontend/src/components/SchedulePage.jsx
@@ -610,7 +610,7 @@ function BulkImportPanel({ onImported, onCancel }) {
}
// ── Calendar Views ────────────────────────────────────────────────────────────
-function ScheduleView({ events, selectedDate, onSelect, filterKeyword='', filterTypeId='' }) {
+function ScheduleView({ events, selectedDate, onSelect, filterKeyword='', filterTypeId='', isMobile=false }) {
const y=selectedDate.getFullYear(), m=selectedDate.getMonth();
const monthStart=new Date(y,m,1), monthEnd=new Date(y,m+1,0,23,59,59);
const kw=filterKeyword.toLowerCase().trim();
@@ -624,7 +624,15 @@ function ScheduleView({ events, selectedDate, onSelect, filterKeyword='', filter
return true;
});
if(!filtered.length) return
{kw||filterTypeId?'No events match your filters':'No events in'} {!kw&&!filterTypeId&&`${MONTHS[m]} ${y}`}
;
- return <>{filtered.map(e=>{const s=new Date(e.start_at);const col=e.event_type?.colour||'#9ca3af';return(onSelect(e)} style={{display:'flex',alignItems:'center',gap:10,padding:'12px 14px',borderBottom:'1px solid var(--border)',cursor:'pointer'}} onMouseEnter={el=>el.currentTarget.style.background='var(--background)'} onMouseLeave={el=>el.currentTarget.style.background=''}>
{s.getDate()}
{SHORT_MONTHS[s.getMonth()]}, {DAYS[s.getDay()]}
{e.all_day?All day:{fmtTime(e.start_at)} –
{fmtTime(e.end_at)}}
{e.event_type?.name&&
{e.event_type.name}:}
{e.title}{!!e.track_availability&&(
+ return <>{filtered.map(e=>{const s=new Date(e.start_at);const col=e.event_type?.colour||'#9ca3af';
+ // Desktop: original pre-v0.9.64 sizes. Mobile: compact sizes from v0.9.64
+ const rowPad=isMobile?'12px 14px':'14px 20px';
+ const rowGap=isMobile?10:20;
+ const datW=isMobile?36:44; const datFs=isMobile?20:22; const datSFs=isMobile?10:11;
+ const timeW=isMobile?62:100; const timeGap=isMobile?5:8; const timeFs=isMobile?11:13;
+ const dotSz=isMobile?8:10;
+ const typeFs=isMobile?10:11; const titleGap=isMobile?6:8;
+ return(
onSelect(e)} style={{display:'flex',alignItems:'center',gap:rowGap,padding:rowPad,borderBottom:'1px solid var(--border)',cursor:'pointer'}} onMouseEnter={el=>el.currentTarget.style.background='var(--background)'} onMouseLeave={el=>el.currentTarget.style.background=''}>
{s.getDate()}
{SHORT_MONTHS[s.getMonth()]}, {DAYS[s.getDay()]}
{e.all_day?All day:{fmtTime(e.start_at)} –
{fmtTime(e.end_at)}}
{e.event_type?.name&&{e.event_type.name}:}{e.title}{!!e.track_availability&&(
e.my_response ? RESP_ICON[e.my_response](RESP_COLOR[e.my_response]) : BELL_ICON
)}
{e.location&&
{e.location}
}
);})}>;
}
@@ -885,7 +893,14 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
const handleSaved = () => { load(); setPanel('calendar'); setEditingEvent(null); };
const handleDelete = async e => {
if (!confirm(`Delete "${e.title}"?`)) return;
- try { await api.deleteEvent(e.id); toast('Deleted','success'); load(); setDetailEvent(null); } catch(err) { toast(err.message,'error'); }
+ try {
+ await api.deleteEvent(e.id);
+ toast('Deleted','success');
+ setPanel('calendar');
+ setEditingEvent(null);
+ setDetailEvent(null);
+ load(); // reload list so deleted event disappears immediately
+ } catch(err) { toast(err.message,'error'); }
};
if (loading) return
Loading schedule…
;
@@ -969,7 +984,11 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
{/* Mobile title + create */}
{isMobile && (
-
Team Schedule
+ <>
+
Team Schedule
+ {/* User footer trigger on mobile — compact avatar button */}
+
+ >
)}
{!isMobile && (
@@ -1004,7 +1023,7 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
{/* Calendar or panel content */}
- {panel === 'calendar' && view === 'schedule' &&
}
+ {panel === 'calendar' && view === 'schedule' && }
{panel === 'calendar' && view === 'day' && }
{panel === 'calendar' && view === 'week' && }
{panel === 'calendar' && view === 'month' && {setSelDate(d);setView('schedule');}}/>}
diff --git a/frontend/src/components/UserFooter.jsx b/frontend/src/components/UserFooter.jsx
index be917dd..f620fb4 100644
--- a/frontend/src/components/UserFooter.jsx
+++ b/frontend/src/components/UserFooter.jsx
@@ -11,7 +11,7 @@ function useTheme() {
return [dark, setDark];
}
-export default function UserFooter({ onProfile, onHelp, onAbout }) {
+export default function UserFooter({ onProfile, onHelp, onAbout, mobileCompact=false }) {
const { user, logout } = useAuth();
const [showMenu, setShowMenu] = useState(false);
const [dark, setDark] = useTheme();
@@ -32,6 +32,26 @@ export default function UserFooter({ onProfile, onHelp, onAbout }) {
const handleLogout = async () => { await logout(); };
+ if (mobileCompact) return (
+
+
+ {showMenu && (
+
+
{user?.display_name||user?.name}
+ {[['Profile',()=>{setShowMenu(false);onProfile?.();}],['Help',()=>{setShowMenu(false);onHelp?.();}],['About',()=>{setShowMenu(false);onAbout?.();}]].map(([label,action])=>(
+
+ ))}
+
+
+
+
+ )}
+
+ );
+
return (