diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
index 571a1e21ddbf8ae1f0a23f98071ad375457fadc3..97bd708a74af10d976e99e2b02ea223b95eb1c27 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
@@ -24,6 +24,7 @@
             <absence-reason-buttons
               allow-empty
               empty-value="present"
+              @input="handleMultipleAction"
             />
           </v-card-actions>
         </v-card>
@@ -69,6 +70,8 @@ import CoursebookEmptyMessage from "./CoursebookEmptyMessage.vue";
 import DocumentationModal from "./documentation/DocumentationModal.vue";
 import DocumentationAbsencesModal from "./absences/DocumentationAbsencesModal.vue";
 
+import updateParticipationMixin from "./absences/updateParticipationMixin.js";
+
 export default {
   name: "Coursebook",
   components: {
@@ -80,6 +83,7 @@ export default {
     DocumentationAbsencesModal,
     InfiniteScrollingDateSortedCRUDIterator,
   },
+  mixins: [updateParticipationMixin],
   props: {
     filterType: {
       type: String,
@@ -207,7 +211,16 @@ export default {
       if (index>=0) {
         this.selectedParticipations.splice(index, 1);
       }
-    }
+    },
+    handleMultipleAction(absenceReasonId) {
+      this.loadSelectedParticiptions = true;
+      this.sendToServer(this.selectedParticipations, "absenceReason", absenceReasonId);
+      this.$once("save", this.resetMultipleAction);
+    },
+    resetMultipleAction() {
+      this.loadSelectedParticiptions = false;
+      this.$set(this.selectedParticipations, []);
+    },
   },
 };
 </script>
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
index a9f4fb0c7411407a5e98cdfe4a386f3b2c7cf678..373fd6fcd9a63938b549b4ecfb17f006f7ebc295 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
@@ -4,10 +4,8 @@ import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.
 import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReasonGroupSelect.vue";
 import CancelButton from "aleksis.core/components/generic/buttons/CancelButton.vue";
 import MobileFullscreenDialog from "aleksis.core/components/generic/dialogs/MobileFullscreenDialog.vue";
-import mutateMixin from "aleksis.core/mixins/mutateMixin.js";
-import documentationPartMixin from "../documentation/documentationPartMixin";
+import updateParticipationMixin from "./updateParticipationMixin.js";
 import LessonInformation from "../documentation/LessonInformation.vue";
-import { updateParticipationStatuses } from "./participationStatus.graphql";
 import SlideIterator from "aleksis.core/components/generic/SlideIterator.vue";
 
 export default {
@@ -22,7 +20,7 @@ export default {
     MobileFullscreenDialog,
     SlideIterator,
   },
-  mixins: [documentationPartMixin, mutateMixin],
+  mixins: [updateParticipationMixin],
   data() {
     return {
       dialog: false,
@@ -45,58 +43,6 @@ export default {
     },
   },
   methods: {
-    sendToServer(participations, field, value) {
-      if (field !== "absenceReason") return;
-
-      this.mutate(
-        updateParticipationStatuses,
-        {
-          input: participations.map((participation) => ({
-            id: participation.id,
-            absenceReason: value === "present" ? null : value,
-          })),
-        },
-        (storedDocumentations, incomingStatuses) => {
-          const documentation = storedDocumentations.find(
-            (doc) => doc.id === this.documentation.id,
-          );
-
-          incomingStatuses.forEach((newStatus) => {
-            const participationStatus = documentation.participations.find(
-              (part) => part.id === newStatus.id,
-            );
-            participationStatus.absenceReason = newStatus.absenceReason;
-            participationStatus.isOptimistic = newStatus.isOptimistic;
-          });
-
-          return storedDocumentations;
-        },
-        // {
-        //   optimisticResponse: {
-        //     updateParticipationStatuses: {
-        //       items: [
-        //         {
-        //           id: participation.id,
-        //           isOptimistic: true,
-        //           relatedDocumentation: {
-        //             id: this.documentation.id,
-        //             __typename: "DocumentationType",
-        //           },
-        //           absenceReason: value === "present" ? null : {
-        //             id: value,
-        //             name: "",
-        //             shortName: "",
-        //             __typename: "AbsenceReasonType",
-        //           },
-        //           __typename: "ParticipationStatusType",
-        //         },
-        //       ],
-        //       __typename: "ParticipationStatusBatchPatchMutation",
-        //     },
-        //   },
-        // },
-      );
-    },
     handleMultipleAction(absenceReasonId) {
       this.loadSelected = true;
       this.sendToServer(this.selected, "absenceReason", absenceReasonId);
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/updateParticipationMixin.js b/aleksis/apps/alsijil/frontend/components/coursebook/absences/updateParticipationMixin.js
new file mode 100644
index 0000000000000000000000000000000000000000..6aab0c9bf83d097916fc4c866b8cf836d9d9c87e
--- /dev/null
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/updateParticipationMixin.js
@@ -0,0 +1,64 @@
+/**
+ * Mixin to provide shared functionality needed to update participations
+*/
+import { updateParticipationStatuses } from "./participationStatus.graphql";
+import mutateMixin from "aleksis.core/mixins/mutateMixin.js";
+import documentationPartMixin from "../documentation/documentationPartMixin";
+
+export default {
+  mixins: [documentationPartMixin, mutateMixin],
+  methods: {
+    sendToServer(participations, field, value) {
+      if (field !== "absenceReason") return;
+    
+      this.mutate(
+        updateParticipationStatuses,
+        {
+          input: participations.map((participation) => ({
+            id: Object.hasOwn(participation, "id") ? participation.id : participation,
+            absenceReason: value === "present" ? null : value,
+          })),
+        },
+        (storedDocumentations, incomingStatuses) => {
+          const documentation = storedDocumentations.find(
+            (doc) => doc.id === this.documentation.id,
+          );
+    
+          incomingStatuses.forEach((newStatus) => {
+            const participationStatus = documentation.participations.find(
+              (part) => part.id === newStatus.id,
+            );
+            participationStatus.absenceReason = newStatus.absenceReason;
+            participationStatus.isOptimistic = newStatus.isOptimistic;
+          });
+    
+          return storedDocumentations;
+        },
+        // {
+        //   optimisticResponse: {
+        //     updateParticipationStatuses: {
+        //       items: [
+        //         {
+        //           id: participation.id,
+        //           isOptimistic: true,
+        //           relatedDocumentation: {
+        //             id: this.documentation.id,
+        //             __typename: "DocumentationType",
+        //           },
+        //           absenceReason: value === "present" ? null : {
+        //             id: value,
+        //             name: "",
+        //             shortName: "",
+        //             __typename: "AbsenceReasonType",
+        //           },
+        //           __typename: "ParticipationStatusType",
+        //         },
+        //       ],
+        //       __typename: "ParticipationStatusBatchPatchMutation",
+        //     },
+        //   },
+        // },
+      );
+    },
+  },
+};