diff --git a/.env.example b/.env.example
index 8f9c02d..76c1f3f 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.68
+JAMA_VERSION=0.9.69
# App port — the host port Docker maps to the container
PORT=3000
diff --git a/backend/package.json b/backend/package.json
index aa1eb60..c10deb3 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "jama-backend",
- "version": "0.9.68",
+ "version": "0.9.69",
"description": "TeamChat backend server",
"main": "src/index.js",
"scripts": {
diff --git a/build.sh b/build.sh
index 81fb7e8..4f45087 100644
--- a/build.sh
+++ b/build.sh
@@ -13,7 +13,7 @@
# ─────────────────────────────────────────────────────────────
set -euo pipefail
-VERSION="${1:-0.9.68}"
+VERSION="${1:-0.9.69}"
ACTION="${2:-}"
REGISTRY="${REGISTRY:-}"
IMAGE_NAME="jama"
diff --git a/frontend/package.json b/frontend/package.json
index c3e5c8d..6dc3089 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "jama-frontend",
- "version": "0.9.68",
+ "version": "0.9.69",
"private": true,
"scripts": {
"dev": "vite",
diff --git a/frontend/src/components/MobileEventForm.jsx b/frontend/src/components/MobileEventForm.jsx
index 6bfcb2e..2a7a83c 100644
--- a/frontend/src/components/MobileEventForm.jsx
+++ b/frontend/src/components/MobileEventForm.jsx
@@ -189,6 +189,11 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
const def = selectedDate ? selectedDate.toISOString().slice(0,10) : new Date().toISOString().slice(0,10);
const [title, setTitle] = useState(event?.title||'');
const [typeId, setTypeId] = useState(event?.event_type_id ? String(event.event_type_id) : '');
+ const [localTypes, setLocalTypes] = useState(eventTypes);
+ const [showAddType, setShowAddType] = useState(false);
+ const [newTypeName, setNewTypeName] = useState('');
+ const [newTypeColour, setNewTypeColour] = useState('#6366f1');
+ const [savingType, setSavingType] = useState(false);
const [sd, setSd] = useState(event ? toDateIn(event.start_at) : def);
const [st, setSt] = useState(event ? toTimeIn(event.start_at) : '09:00');
const [ed, setEd] = useState(event ? toDateIn(event.end_at) : def);
@@ -208,21 +213,34 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
const [showRecurrence, setShowRecurrence] = useState(false);
const [showGroups, setShowGroups] = useState(false);
- // Auto-set typeId to default event type
+ // Sync and initialise typeId
useEffect(() => {
+ setLocalTypes(eventTypes);
if(!event && typeId==='' && eventTypes.length>0) {
const def = eventTypes.find(t=>t.is_default) || eventTypes[0];
if(def) setTypeId(String(def.id));
}
}, [eventTypes]);
+ const createEventType = async () => {
+ if(!newTypeName.trim()) return;
+ setSavingType(true);
+ try {
+ const r = await api.createEventType({ name: newTypeName.trim(), colour: newTypeColour });
+ setLocalTypes(prev => [...prev, r.eventType]);
+ setTypeId(String(r.eventType.id));
+ setNewTypeName(''); setShowAddType(false);
+ } catch(e) { toast(e.message, 'error'); }
+ finally { setSavingType(false); }
+ };
+
// When start date changes, match end date
useEffect(() => { if(!event) setEd(sd); }, [sd]);
// When type or start time changes, auto-set end time
useEffect(() => {
if(!sd||!st) return;
- const typ = eventTypes.find(t=>t.id===Number(typeId));
+ const typ = localTypes.find(t=>t.id===Number(typeId));
const dur = typ?.default_duration_hrs||1;
const start = buildISO(sd,st);
if(start && !event) { setEd(toDateIn(addHours(start,dur))); setEt(toTimeIn(addHours(start,dur))); }
@@ -262,8 +280,28 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
{/* Event Type */}