|
|
@@ -31,11 +31,14 @@
|
|
|
<c-footer v-if="showFooter" />
|
|
|
</template>
|
|
|
<script lang="ts">
|
|
|
+import SockJS from "sockjs-client";
|
|
|
+import Stomp from "stompjs";
|
|
|
import { defineComponent } from "vue";
|
|
|
import toast, { Toast } from "@/utils/Toast";
|
|
|
import ConstraintTranslation from "@/assets/ConstraintTranslation";
|
|
|
import Evenement from "@/models/Evenement";
|
|
|
import Creneau from "@/models/Creneau";
|
|
|
+import PlanningUpdateMessage from "@/models/PlanningUpdateMessage";
|
|
|
import {
|
|
|
AssignementPair,
|
|
|
SolverInput,
|
|
|
@@ -68,6 +71,7 @@ export default defineComponent({
|
|
|
mixins: [updatePlanningVersions, importJsonState],
|
|
|
data() {
|
|
|
return {
|
|
|
+ stompClient: Stomp.over(new SockJS("/ws")),
|
|
|
optimisationInProgress: false,
|
|
|
explanation: "",
|
|
|
showExplanation: false,
|
|
|
@@ -79,10 +83,36 @@ export default defineComponent({
|
|
|
showFooter(): boolean {
|
|
|
return this.$route.name != "Planning";
|
|
|
},
|
|
|
+ uuid(): string {
|
|
|
+ return this.$store.state.evenement.uuid;
|
|
|
+ },
|
|
|
+ username(): string {
|
|
|
+ return this.$store.state.username;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ uuid(val: string, old: string) {
|
|
|
+ if (old && this.stompClient.connected) this.stompClient.unsubscribe("/planning/" + old);
|
|
|
+ this.subscribe(val);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ beforeMount() {
|
|
|
+ this.stompClient.connect(
|
|
|
+ {},
|
|
|
+ () => {
|
|
|
+ this.stompClient.subscribe("/toast", (msg) => {
|
|
|
+ var content = JSON.parse(msg.body) as { text: string; type: string };
|
|
|
+ toast({ html: content.text, classes: content.type });
|
|
|
+ });
|
|
|
+ this.subscribe(this.uuid);
|
|
|
+ },
|
|
|
+ (error) => {
|
|
|
+ toast({ html: error.toString(), classes: "error" });
|
|
|
+ }
|
|
|
+ );
|
|
|
},
|
|
|
mounted() {
|
|
|
- const url = `${API_URL}api/evenements`;
|
|
|
- fetch(url)
|
|
|
+ fetch(`${API_URL}api/evenements`)
|
|
|
.then((response) => {
|
|
|
if (response.status == 200) {
|
|
|
return response.json();
|
|
|
@@ -93,11 +123,20 @@ export default defineComponent({
|
|
|
.then((data) => this.$store.commit(MutationTypes.refreshSavedPlanning, data));
|
|
|
|
|
|
const previousState = window.localStorage.getItem("activeState");
|
|
|
- toast({ html: "Bienvenue" });
|
|
|
+
|
|
|
if (previousState) {
|
|
|
this.importState(JSON.parse(previousState));
|
|
|
if (this.$route.path == "/planner") this.$router.push({ name: "Evenement" });
|
|
|
}
|
|
|
+ fetch(`${API_URL}username`)
|
|
|
+ .then((res) => res.text())
|
|
|
+ .then((username) => {
|
|
|
+ if (username.length < 400) {
|
|
|
+ toast({ html: "Bienvenue " + username });
|
|
|
+ this.$store.commit(MutationTypes.setUsername, username);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
window.onbeforeunload = () => {
|
|
|
this.localSave();
|
|
|
};
|
|
|
@@ -106,6 +145,32 @@ export default defineComponent({
|
|
|
this.save();
|
|
|
},
|
|
|
methods: {
|
|
|
+ subscribe(uuid: string) {
|
|
|
+ if (uuid && this.stompClient.connected) {
|
|
|
+ this.stompClient.subscribe("/planning/" + uuid, (msg) => this.handlePlanningChange(msg));
|
|
|
+ this.stompClient.send(
|
|
|
+ "/app/notify",
|
|
|
+ {},
|
|
|
+ JSON.stringify({
|
|
|
+ uuid,
|
|
|
+ user: this.username,
|
|
|
+ method: "toast",
|
|
|
+ payload: `L'utilisateur ${this.username} vient de se connecter`,
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handlePlanningChange(msg: Stomp.Message) {
|
|
|
+ var content = JSON.parse(msg.body) as PlanningUpdateMessage;
|
|
|
+ console.log("Received message ", content);
|
|
|
+ if (this.uuid == content.uuid && this.username && this.username != content.user) {
|
|
|
+ if (content.method === "toast") {
|
|
|
+ toast({ html: content.payload });
|
|
|
+ } else {
|
|
|
+ this.$store.commit(content.method, JSON.parse(content.payload));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
localSave() {
|
|
|
window.localStorage.setItem("activeState", JSON.stringify(this.$store.getters.getJSONState));
|
|
|
},
|
|
|
@@ -199,12 +264,15 @@ export default defineComponent({
|
|
|
const slots = this.$store.state.creneauList.filter((o) => !o.isMeal);
|
|
|
const timeslots = slots.map((o) => o.toTimeslotRaw());
|
|
|
const mealSlots = meals.map((o) => o.toMealSlot());
|
|
|
- const volonteerList = this.$store.state.benevoleList.map((b) => b.toVolonteeRaw());
|
|
|
+ const volonteerList = this.$store.state.benevoleList
|
|
|
+ .filter((b) => !b.isFixed)
|
|
|
+ .map((b) => b.toVolonteeRaw());
|
|
|
const constraints = this.$store.state.competenceList.map((c) => c.toSkill());
|
|
|
const getAssignementPair = (c: Creneau) =>
|
|
|
c.benevoleIdList.map((id) => {
|
|
|
const obj: AssignementPair = { volonteerId: id, slotId: c.id };
|
|
|
- if (c.fixedAttendee) obj.isFixed = true;
|
|
|
+ if (c.fixedAttendee || this.$store.getters.getBenevoleById(id)?.isFixed)
|
|
|
+ obj.isFixed = true;
|
|
|
return obj;
|
|
|
});
|
|
|
const assignements = slots.flatMap(getAssignementPair);
|