diff --git a/src/classes/Favorite.js b/src/classes/Favorite.js new file mode 100644 index 0000000..a3e30b7 --- /dev/null +++ b/src/classes/Favorite.js @@ -0,0 +1,16 @@ +import { Data } from "@lenra/app-server"; + +export class Favorite extends Data { + /** + * + * @param {string[]} sessions + * @param {boolean} filter + * @param {user} user + */ + constructor(sessions, user, filter = false) { + super(); + this.user = user; + this.sessions = sessions; + this.filter = filter; + } +} \ No newline at end of file diff --git a/src/index.gen.js b/src/index.gen.js index c6c5a75..ebb73bd 100644 --- a/src/index.gen.js +++ b/src/index.gen.js @@ -15,5 +15,7 @@ export const views = { export const listeners = { "onEnvStart": "onEnvStart", "onSessionStart": "onSessionStart", - "onUserFirstJoin": "onUserFirstJoin" + "onUserFirstJoin": "onUserFirstJoin", + "toggleFavorite": "toggleFavorite", + "toggleFavoriteFilter": "toggleFavoriteFilter" }; diff --git a/src/listeners/favorite.js b/src/listeners/favorite.js new file mode 100644 index 0000000..7381b80 --- /dev/null +++ b/src/listeners/favorite.js @@ -0,0 +1,30 @@ +import { Favorite } from "../classes/Favorite.js"; + +/** + * + * @param {import("@lenra/app-server").props} props + * @param {import("@lenra/app-server").event} _event + * @param {import("@lenra/app-server").Api} api + */ +export async function toggleFavorite(props, _event, api) { + const [fav] = await api.data.find(Favorite, { user: "@me" }) + if (!fav) return api.data.createDoc(new Favorite([props.session], "@me")); + + if (fav.sessions.includes(props.session)) fav.sessions = fav.sessions.filter(s => s !== props.session); + else fav.sessions.push(props.session); + await api.data.updateDoc(fav); +} + +/** + * + * @param {import("@lenra/app-server").props} props + * @param {import("@lenra/app-server").event} _event + * @param {import("@lenra/app-server").Api} api + */ +export async function toggleFavoriteFilter(props, _event, api) { + console.log("_event", _event); + const [fav] = await api.data.find(Favorite, { user: "@me" }) + if (!fav) return api.data.createDoc(new Favorite([], "@me", true)); + fav.filter = !fav.filter; + await api.data.updateDoc(fav); +} \ No newline at end of file diff --git a/src/manifest.js b/src/manifest.js index 376e24b..c16a0a2 100644 --- a/src/manifest.js +++ b/src/manifest.js @@ -1,10 +1,19 @@ +import { DataApi } from "@lenra/app-server"; import { View } from "@lenra/components"; +import { Favorite } from "./classes/Favorite.js"; import { views } from "./index.gen.js"; export const lenraRoutes = [ { path: "/", - view: View(views.layout).props({ page: views.pages.agenda }), + view: View(views.layout).props({ + page: views.pages.agenda, + find: { + coll: DataApi.collectionName(Favorite), + query: { user: "@me" }, + } + }) + .data(DataApi.collectionName(Favorite), {}), }, { path: "/sessions/:key", diff --git a/src/views/layout.js b/src/views/layout.js index f9174b5..574114d 100644 --- a/src/views/layout.js +++ b/src/views/layout.js @@ -1,10 +1,11 @@ import { Container, Flex, Flexible, padding, View } from "@lenra/components"; import { views } from "../index.gen.js"; -export default function (_data, { page/* , context */ }, context) { +export default function (_data, { page/* , context */, find }, context) { const pageView = View(page); // if (context) pageView.context(context); if (context) pageView.props({ context }); + if (find) pageView.find(find); return Flex([ View(views.menu), Flexible( diff --git a/src/views/pages/agenda.js b/src/views/pages/agenda.js index b865b04..72c56bc 100644 --- a/src/views/pages/agenda.js +++ b/src/views/pages/agenda.js @@ -1,50 +1,75 @@ -import { Actionable, Container, Flex, Flexible, Image, padding, Text, View } from "@lenra/components"; +import { Actionable, colors, Container, Flex, Flexible, Icon, Image, padding, Text, Toggle, View } from "@lenra/components"; import { days, rooms, sessions, speakers } from "../../camping-data.js"; +import { Favorite } from "../../classes/Favorite.js"; import { listeners, views } from "../../index.gen.js"; -export default function (_data, _props) { - const sortedSessions = Object.values(sessions).sort((a, b) => { - if (a.attributes.day !== b.attributes.day) { - return a.attributes.day - b.attributes.day; - } - if (a.attributes.time !== b.attributes.time) { - return a.attributes.time.localeCompare(b.attributes.time); - } - return a.attributes.title.localeCompare(b.attributes.title); - }); - let currentDay = null; - let currentTime = null; - return Flex( - sortedSessions.flatMap((session) => { - const elements = []; - if (session.attributes.day !== currentDay) { - currentDay = session.attributes.day; - elements.push( - Text(days[currentDay].long) - .style({ - fontSize: 24, - }) - ); +/** + * @param {Favorite[]} param0 + * @param {*} _props + * @returns + */ +export default function ([favorite], _props) { + const sortedSessions = Object.values(sessions) + .filter(session => favorite?.filter ? favorite?.sessions?.includes(session.attributes.key) : true) + .sort((a, b) => { + if (a.attributes.day !== b.attributes.day) { + return a.attributes.day - b.attributes.day; } - if (session.attributes.time !== currentTime) { - currentTime = session.attributes.time; - elements.push( - Text(currentTime) - .style({ - fontSize: 20, - }) - ); + if (a.attributes.time !== b.attributes.time) { + return a.attributes.time.localeCompare(b.attributes.time); } - elements.push(sessionCard(session)); - return elements; - }) - ) + return a.attributes.title.localeCompare(b.attributes.title); + }); + let currentDay = null; + let currentTime = null; + return Flex([ + Flex([ + Text("Mes sessions favorites"), + Toggle(favorite?.filter ?? false) + .onPressed(listeners.toggleFavoriteFilter), + ]) + .mainAxisAlignment("spaceBetween") + .crossAxisAlignment("center"), + Flex( + sortedSessions.flatMap((session) => { + const elements = []; + if (session.attributes.day !== currentDay) { + currentDay = session.attributes.day; + elements.push( + Text(days[currentDay].long) + .style({ + fontSize: 24, + }) + ); + } + if (session.attributes.time !== currentTime) { + currentTime = session.attributes.time; + elements.push( + Text(currentTime) + .style({ + fontSize: 20, + }) + ); + } + elements.push(sessionCard(session, favorite?.sessions?.includes(session.attributes.key) ?? false)); + return elements; + }) + ) + .direction("vertical") + .crossAxisAlignment("stretch") + .spacing(16) + ]) .direction("vertical") .crossAxisAlignment("stretch") - .spacing(16) + .spacing(32) } -function sessionCard(session) { +/** + * @param {Session} session + * @param {boolean} isFavorite + * @returns + */ +function sessionCard(session, isFavorite) { return Actionable( Container.card( Flex([ @@ -58,14 +83,25 @@ function sessionCard(session) { .filter(speaker => speaker in speakers) .map(speaker => View(views.pages.agenda.speaker).props({ speaker })) ) - .direction("vertical") - .spacing(8), - Flex([ - Text(`${session.attributes.time} - ${session.attributes.duration}`) - , - Text(rooms[session.attributes.room].name), - ]) .direction("vertical"), + Flex( + [ + Flex([ + Text(`${session.attributes.time} - ${session.attributes.duration}`), + Text(rooms[session.attributes.room].name), + ]) + .direction("vertical"), + Actionable( + Icon("local_fire_department") + .color(isFavorite ? colors.LenraColors.yellowPulse : colors.Colors.black) + .style(isFavorite ? "rounded" : "outlined") + ) + .onPressed(listeners.toggleFavorite, { session: session.attributes.key }), + ] + ) + .fillParent(true) + .mainAxisAlignment("spaceBetween") + .crossAxisAlignment("end"), ]) .direction("vertical") .spacing(16)