feat: Add planets API and translations (safe incremental)
- Add planet API functions to client.js (fetchPlanets, createPlanet, etc.) - Add updateIsland function for island customization - Add sociowire:create-post event listener in App.jsx - Add planets translations (EN, FR, ES) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c50c61ff36
commit
733296dd59
12
src/App.jsx
12
src/App.jsx
|
|
@ -147,6 +147,18 @@ export default function App() {
|
|||
return () => window.removeEventListener("sw:openPostDetail", handleOpenPostDetail);
|
||||
}, []);
|
||||
|
||||
// Listen for island post creation event
|
||||
useEffect(() => {
|
||||
const handleIslandPost = (e) => {
|
||||
const { island } = e.detail || {};
|
||||
if (island) {
|
||||
window.location.href = `/island/${island}?create=true`;
|
||||
}
|
||||
};
|
||||
window.addEventListener('sociowire:create-post', handleIslandPost);
|
||||
return () => window.removeEventListener('sociowire:create-post', handleIslandPost);
|
||||
}, []);
|
||||
|
||||
// Island Universe handlers
|
||||
const handleOpenUniverse = () => {
|
||||
setShowUniverse(true);
|
||||
|
|
|
|||
|
|
@ -1250,3 +1250,192 @@ export function getCurrentLocation() {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// ISLAND CUSTOMIZATION API
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Update island customization (terrain, colors, size)
|
||||
*/
|
||||
export async function updateIsland(islandId, updates) {
|
||||
if (!islandId) return { ok: false, error: "Missing island ID" };
|
||||
try {
|
||||
const res = await fetch(`${apiBase()}/islands/${encodeURIComponent(islandId)}`, {
|
||||
method: "PATCH",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json", ...authHeaders() },
|
||||
body: JSON.stringify(updates),
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return { ok: res.ok, ...data };
|
||||
} catch (err) {
|
||||
console.warn("updateIsland error:", err);
|
||||
return { ok: false, error: err?.message || "Update failed" };
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// PLANETS API (Group spaces)
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* Fetch list of planets (group spaces)
|
||||
*/
|
||||
export async function fetchPlanets(params = {}) {
|
||||
const qs = new URLSearchParams();
|
||||
if (typeof params.limit === "number") qs.set("limit", String(params.limit));
|
||||
if (typeof params.offset === "number") qs.set("offset", String(params.offset));
|
||||
if (params.search) qs.set("search", params.search);
|
||||
|
||||
const url = `${apiBase()}/planets?${qs.toString()}`;
|
||||
|
||||
try {
|
||||
const res = await fetch(url, { credentials: "include" });
|
||||
if (!res.ok) {
|
||||
console.warn("fetchPlanets failed", res.status);
|
||||
return [];
|
||||
}
|
||||
const data = await res.json();
|
||||
return Array.isArray(data) ? data : data.planets || [];
|
||||
} catch (err) {
|
||||
console.warn("fetchPlanets error:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch single planet by ID
|
||||
*/
|
||||
export async function fetchPlanet(planetId) {
|
||||
if (!planetId) return null;
|
||||
const url = `${apiBase()}/planets/${encodeURIComponent(planetId)}`;
|
||||
|
||||
try {
|
||||
const res = await fetch(url, { credentials: "include" });
|
||||
if (!res.ok) {
|
||||
console.warn("fetchPlanet failed", res.status);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
console.warn("fetchPlanet error:", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new planet
|
||||
*/
|
||||
export async function createPlanet(payload) {
|
||||
try {
|
||||
const res = await fetch(`${apiBase()}/planets`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json", ...authHeaders() },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return { ok: res.ok, ...data };
|
||||
} catch (err) {
|
||||
console.warn("createPlanet error:", err);
|
||||
return { ok: false, error: err?.message || "Create failed" };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update planet settings
|
||||
*/
|
||||
export async function updatePlanet(planetId, updates) {
|
||||
if (!planetId) return { ok: false, error: "Missing planet ID" };
|
||||
try {
|
||||
const res = await fetch(`${apiBase()}/planets/${encodeURIComponent(planetId)}`, {
|
||||
method: "PATCH",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json", ...authHeaders() },
|
||||
body: JSON.stringify(updates),
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return { ok: res.ok, ...data };
|
||||
} catch (err) {
|
||||
console.warn("updatePlanet error:", err);
|
||||
return { ok: false, error: err?.message || "Update failed" };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a planet
|
||||
*/
|
||||
export async function joinPlanet(planetId) {
|
||||
if (!planetId) return { ok: false };
|
||||
try {
|
||||
const res = await fetch(`${apiBase()}/planets/${encodeURIComponent(planetId)}/join`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { ...authHeaders() },
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return { ok: res.ok, ...data };
|
||||
} catch (err) {
|
||||
console.warn("joinPlanet error:", err);
|
||||
return { ok: false };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a planet
|
||||
*/
|
||||
export async function leavePlanet(planetId) {
|
||||
if (!planetId) return { ok: false };
|
||||
try {
|
||||
const res = await fetch(`${apiBase()}/planets/${encodeURIComponent(planetId)}/leave`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { ...authHeaders() },
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return { ok: res.ok, ...data };
|
||||
} catch (err) {
|
||||
console.warn("leavePlanet error:", err);
|
||||
return { ok: false };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch planet members
|
||||
*/
|
||||
export async function fetchPlanetMembers(planetId, params = {}) {
|
||||
if (!planetId) return [];
|
||||
const qs = new URLSearchParams();
|
||||
if (typeof params.limit === "number") qs.set("limit", String(params.limit));
|
||||
|
||||
try {
|
||||
const res = await fetch(`${apiBase()}/planets/${encodeURIComponent(planetId)}/members?${qs.toString()}`, {
|
||||
credentials: "include",
|
||||
});
|
||||
if (!res.ok) return [];
|
||||
const data = await res.json();
|
||||
return Array.isArray(data) ? data : data.members || [];
|
||||
} catch (err) {
|
||||
console.warn("fetchPlanetMembers error:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch user's planets (planets they've joined)
|
||||
*/
|
||||
export async function fetchUserPlanets() {
|
||||
try {
|
||||
const res = await fetch(`${apiBase()}/planets/my`, {
|
||||
credentials: "include",
|
||||
headers: { ...authHeaders() },
|
||||
});
|
||||
if (!res.ok) return [];
|
||||
const data = await res.json();
|
||||
return Array.isArray(data) ? data : data.planets || [];
|
||||
} catch (err) {
|
||||
console.warn("fetchUserPlanets error:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,7 +270,12 @@
|
|||
"islandsCount": "{{count}} islands floating in virtual space",
|
||||
"clickToVisit": "Click to visit",
|
||||
"posts": "posts",
|
||||
"help": "Hover over islands to see details - Click to visit"
|
||||
"help": "Hover over islands to see details - Click to visit",
|
||||
"planets": "planets",
|
||||
"all": "All",
|
||||
"islandsTab": "Islands",
|
||||
"planetsTab": "Planets",
|
||||
"members": "members"
|
||||
},
|
||||
"controls": {
|
||||
"mySpot": "My spot",
|
||||
|
|
|
|||
|
|
@ -270,7 +270,12 @@
|
|||
"islandsCount": "{{count}} islas flotando en el espacio virtual",
|
||||
"clickToVisit": "Clic para visitar",
|
||||
"posts": "posts",
|
||||
"help": "Pasa el ratón sobre las islas para ver detalles - Clic para visitar"
|
||||
"help": "Pasa el ratón sobre las islas para ver detalles - Clic para visitar",
|
||||
"planets": "planetas",
|
||||
"all": "Todo",
|
||||
"islandsTab": "Islas",
|
||||
"planetsTab": "Planetas",
|
||||
"members": "miembros"
|
||||
},
|
||||
"controls": {
|
||||
"mySpot": "Mi ubicación",
|
||||
|
|
|
|||
|
|
@ -273,7 +273,12 @@
|
|||
"islandsCount": "{{count}} îles flottant dans l'espace virtuel",
|
||||
"clickToVisit": "Cliquez pour visiter",
|
||||
"posts": "posts",
|
||||
"help": "Survolez les îles pour voir les détails - Cliquez pour visiter"
|
||||
"help": "Survolez les îles pour voir les détails - Cliquez pour visiter",
|
||||
"planets": "planètes",
|
||||
"all": "Tout",
|
||||
"islandsTab": "Îles",
|
||||
"planetsTab": "Planètes",
|
||||
"members": "membres"
|
||||
},
|
||||
"controls": {
|
||||
"mySpot": "Ma position",
|
||||
|
|
|
|||
Loading…
Reference in New Issue