diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index cb93b043423373580d7de43abb2d9b9cd2864cde..2473dd414d9eaf67576859d78e37a25839404fb5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -15,4 +15,4 @@ repos:
     rev: 6.0.0
     hooks:
       - id: flake8
-        args: ['--max-line-length=160', '--ignore=E203,E402,E722,F403,F405,W503']
+        args: ['--max-line-length=160', '--ignore=E203,E402,E722,F403,F405,W503,E231,E702']
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0abfe237e2655bcb0fa209ae39c77d2d19b07627..52f9e461c8bd19d4d7480bf96849d4de34cc38ca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
 # ESS OP Shifter Changelog
 
+### v.1.1.4
+- Introduced the Shift market
+- ShiftSwap Summary log with filters and details
+- [bug fixes] notification email format correction
+- [bug fixes] user icon display
+- [bug fixes] date filters for shift inconsistency
+
+### v.1.1.3
+- [bug fixes] using only active users for desiderata
+- [bug fixes] plot display issues
+- [bug fixes] import messages
+
 ### v.1.1.2
 - Rota maker improvements
   - desideratas overview
diff --git a/shifter/notifications.py b/shifter/notifications.py
index f744a28098ba6c8420b1087f5240a64e64a8571e..dd2d4caa86f8eab226974c8d1c5dcbdaf2f67518 100644
--- a/shifter/notifications.py
+++ b/shifter/notifications.py
@@ -5,7 +5,7 @@ Prototype of the shifter-centralised notification implementation and classes.
 from abc import ABC, abstractmethod
 
 from django.template.loader import render_to_string
-from shifts.models import Shift, Revision, Member, ShiftExchange
+from shifts.models import Shift, Revision, Member, ShiftExchange, ShiftForMarket
 from studies.models import StudyRequest
 from django.core.mail import send_mail
 
@@ -53,6 +53,13 @@ class NotificationService(ABC):
         """
         pass
 
+    @abstractmethod
+    def _triggerNotificationForMarket(self, event):
+        """
+        triggers the notification on StudyRequest
+        """
+        pass
+
     def notify(self, event) -> int:
         if isinstance(event, (Shift, NewShiftsUpload, ShiftExchange)):
             return self._triggerShiftNotification(event)
@@ -61,6 +68,8 @@ class NotificationService(ABC):
                 return self._triggerRevisionNotification(event)
         elif isinstance(event, StudyRequest):
             return self._triggerStudyRequestNotification(event)
+        elif isinstance(event, ShiftForMarket):
+            return self._triggerNotificationForMarket(event)
         else:
             print("Do not know how to notify for ", event)
             return NOTIFICATION_CODE_ERROR
@@ -80,6 +89,9 @@ class NewShiftsUpload:
 class DummyNotifier(NotificationService):
     """Mainly for test class"""
 
+    def _triggerNotificationForMarket(self, event):
+        pass
+
     def __init__(self, name):
         super().__init__(name=name)
 
@@ -184,6 +196,24 @@ class EmailNotifier(NotificationService):
                     affectedMembersEmail=[one for one in affectedMembers if one.notification_shifts],
                 )
 
+    def _triggerNotificationForMarket(self, shiftForMarket: ShiftForMarket):
+        emailSubject = "[shifter] NEW shift on market"
+        emailBody = render_to_string(
+            "shift_market_email.html",
+            {"shiftForMarket": shiftForMarket, "domain": self.default_domain},
+        )
+        m = Member.objects.filter(role=shiftForMarket.shift.member.role)
+        affectedMembers = list(m)
+
+        self._notify_internal_and_external(
+            actor=shiftForMarket.offerer,
+            target=shiftForMarket,
+            emailSubject=emailSubject,
+            emailBody=emailBody,
+            affectedMembers=affectedMembers,
+            affectedMembersEmail=[one for one in affectedMembers if one.notification_shifts],
+        )
+
     def _triggerRevisionNotification(self, revision):
         emailSubject = "[shifter] NEW planning ready for the preview"
         emailBody = render_to_string(
diff --git a/shifter/settings.py b/shifter/settings.py
index ca4930d001dd6d2dc10d1765287e0a9b949e29dc..a605e5174d64f4dfbb965de2c15a410424d7760a 100644
--- a/shifter/settings.py
+++ b/shifter/settings.py
@@ -88,6 +88,7 @@ TEMPLATES = [
                 "shifts.permanent_contexts.application_context",
                 "shifts.permanent_contexts.rota_maker_role",
                 "shifts.permanent_contexts.nav_bar_context",
+                "shifts.permanent_contexts.shift_market_count",
             ],
         },
     },
diff --git a/shifts/admin.py b/shifts/admin.py
index ecb3239eb0e6a7b0a151e781f2955c7649d15200..9618b053b31c6c331501a5fdf930d0d5e0ae7030 100644
--- a/shifts/admin.py
+++ b/shifts/admin.py
@@ -4,7 +4,7 @@ from django.contrib import messages
 
 # Register your models here.
 
-from shifts.models import ShifterMessage, Revision, Campaign, Slot, Shift, ShiftRole, ShiftID, Contact, ShiftExchangePair, ShiftExchange
+from shifts.models import ShifterMessage, Revision, Campaign, Slot, Shift, ShiftRole, ShiftID, Contact, ShiftExchangePair, ShiftExchange, ShiftForMarket
 
 
 @admin.register(Contact)
@@ -95,6 +95,13 @@ class ShiftIDAdmin(admin.ModelAdmin):
     ordering = ("-label",)
 
 
+@admin.register(ShiftForMarket)
+class ShiftForMarketAdmin(admin.ModelAdmin):
+    model = ShiftForMarket
+    list_display = ["shift", "offerer", "offered_date", "available_until", "is_available", "is_taken", "urgency", "comments"]
+    ordering = ("-offered_date",)
+
+
 @admin.register(Shift)
 class ShiftAdmin(admin.ModelAdmin):
     def MOVE_to_newest_VALID_revision(self, request, queryset):
diff --git a/shifts/exchanges.py b/shifts/exchanges.py
index 5b511daec179cef141436dcd5092969a0341713c..73695a9c90b1bef1adf06e99b582ccf8a65bacef 100644
--- a/shifts/exchanges.py
+++ b/shifts/exchanges.py
@@ -1,11 +1,11 @@
 from django.db.models import Q
-from shifts.models import ShiftExchange, Member, Shift, ShiftExchangePair, Revision
+from shifts.models import ShiftExchange, Member, Shift, ShiftExchangePair, Revision, ShiftForMarket
 from shifts.workinghours import find_daily_rest_time_violation, find_weekly_rest_time_violation
 from datetime import timedelta
 from django.utils import timezone
 
 
-def get_exchange_exchange_preview(shiftExchange: ShiftExchange, baseRevision, previewRangeDays=7, verbose=False):
+def get_exchange_exchange_preview(shiftExchange: ShiftExchange, baseRevision, previewRangeDays=10, verbose=False):
     """
     Returns all new shift plan wrt shifts requested for change (each change component
     queries previewRangeDays forward and backward)
@@ -23,55 +23,62 @@ def get_exchange_exchange_preview(shiftExchange: ShiftExchange, baseRevision, pr
         print("\t", shiftExchange)
 
     allShiftsForNewPlanning = []
-    usedSlots = []
+    usedSlots = []  # these are needed prior to the main check!
     for shiftSwap in shiftExchange.shifts.all():
         usedSlots += [shiftSwap.shift.id, shiftSwap.shift_for_exchange.id]
 
     for shiftSwap in shiftExchange.shifts.all():
-        if verbose:
-            print("\t", shiftSwap)
-        # create new swapped shifts
-        newS = _prepare_after_swap_shifts(shiftSwap)
-        if verbose:
-            print("\t", newS)
-        allShiftsForNewPlanning += newS
-        # member 1 future setup:
-        sM1TmpBefore = Shift.objects.filter(member=shiftSwap.shift.member, revision=baseRevision).filter(
-            Q(date__lt=shiftSwap.shift_for_exchange.date) & Q(date__gt=(shiftSwap.shift_for_exchange.date + timedelta(days=-previewRangeDays)))
-        )
-        sM1TmpAfter = Shift.objects.filter(member=shiftSwap.shift.member, revision=baseRevision).filter(
-            Q(date__gt=shiftSwap.shift_for_exchange.date) & Q(date__lt=(shiftSwap.shift_for_exchange.date + timedelta(days=previewRangeDays)))
-        )
-        if verbose:
-            print("\t", sM1TmpBefore, sM1TmpAfter)
-
-        for s in list(sM1TmpAfter) + list(sM1TmpBefore):
-            if s.id in usedSlots:
-                continue
-            usedSlots.append(s.id)
-            allShiftsForNewPlanning.append(s)
-
-        sM2TmpBefore = Shift.objects.filter(member=shiftSwap.shift_for_exchange.member, revision=baseRevision).filter(
-            Q(date__lt=shiftSwap.shift.date) & Q(date__gt=(shiftSwap.shift.date + timedelta(days=-previewRangeDays)))
-        )
-        sM2TmpAfter = Shift.objects.filter(member=shiftSwap.shift_for_exchange.member, revision=baseRevision).filter(
-            Q(date__gt=shiftSwap.shift.date) & Q(date__lt=(shiftSwap.shift.date + timedelta(days=previewRangeDays)))
-        )
-        if verbose:
-            print("\t", sM2TmpBefore, sM2TmpAfter)
-
-        for s in list(sM2TmpAfter) + list(sM2TmpBefore):
-            if s.id in usedSlots:
-                continue
-            usedSlots.append(s.id)
-            allShiftsForNewPlanning.append(s)
+        allShiftsForNewPlanning = _verifyForOneShiftSwap(shiftSwap, usedSlots, baseRevision, previewRangeDays=previewRangeDays, verbose=verbose)
 
     if verbose:
         print(allShiftsForNewPlanning)
+        print(shiftExchange.applicable)
         print("\t============================")
     return allShiftsForNewPlanning
 
 
+def _verifyForOneShiftSwap(shiftSwap: ShiftExchangePair, usedSlots, baseRevision, previewRangeDays=10, verbose=False):
+    """
+    Performs a virtual check for the
+    """
+    allShiftsForNewPlanning = []
+    if verbose:
+        print("\t", shiftSwap)
+    # create new swapped shifts
+    newS = _prepare_after_swap_shifts(shiftSwap)
+    if verbose:
+        print("\t", newS)
+    allShiftsForNewPlanning += newS
+    # member 1 future setup:
+    sM1TmpBefore = Shift.objects.filter(member=shiftSwap.shift.member, revision=baseRevision).filter(
+        Q(date__lt=shiftSwap.shift_for_exchange.date) & Q(date__gt=(shiftSwap.shift_for_exchange.date + timedelta(days=-previewRangeDays)))
+    )
+    sM1TmpAfter = Shift.objects.filter(member=shiftSwap.shift.member, revision=baseRevision).filter(
+        Q(date__gt=shiftSwap.shift_for_exchange.date) & Q(date__lt=(shiftSwap.shift_for_exchange.date + timedelta(days=previewRangeDays)))
+    )
+    if verbose:
+        print("\t", sM1TmpBefore, sM1TmpAfter)
+    for s in list(sM1TmpAfter) + list(sM1TmpBefore):
+        if s.id in usedSlots:
+            continue
+        usedSlots.append(s.id)
+        allShiftsForNewPlanning.append(s)
+    sM2TmpBefore = Shift.objects.filter(member=shiftSwap.shift_for_exchange.member, revision=baseRevision).filter(
+        Q(date__lt=shiftSwap.shift.date) & Q(date__gt=(shiftSwap.shift.date + timedelta(days=-previewRangeDays)))
+    )
+    sM2TmpAfter = Shift.objects.filter(member=shiftSwap.shift_for_exchange.member, revision=baseRevision).filter(
+        Q(date__gt=shiftSwap.shift.date) & Q(date__lt=(shiftSwap.shift.date + timedelta(days=previewRangeDays)))
+    )
+    if verbose:
+        print("\t", sM2TmpBefore, sM2TmpAfter)
+    for s in list(sM2TmpAfter) + list(sM2TmpBefore):
+        if s.id in usedSlots:
+            continue
+        usedSlots.append(s.id)
+        allShiftsForNewPlanning.append(s)
+    return allShiftsForNewPlanning
+
+
 def _create_shift(shift, member, revision=None, permanent=False, pre_comment=None):
     """
     Creates a shift from a shift but with changed member and revision
@@ -118,7 +125,20 @@ def is_valid_for_hours_constraints(
     # FIXME consider ShiftExchange per only TWO members, then one can save calls to check validity for each member
     s1 = find_daily_rest_time_violation([x for x in closeScheduleAfterUpdate if x.member == member])
     s2 = find_weekly_rest_time_violation([x for x in closeScheduleAfterUpdate if x.member == member])
+    return len(s1) == 0 & len(s2) == 0, (s1, s2)
+
+
+def is_valid_for_hours_constraints_from_market(sfm: ShiftForMarket, revision: Revision, member: Member) -> tuple:
+    """
+    returns tuple of boolean, and list of violated shifts
+    """
+    shiftSwap = ShiftExchangePair(shift=sfm.shift, shift_for_exchange=_create_shift(sfm.shift, member))
+    # print(sfm)
+    usedSlots = [shiftSwap.shift.id, shiftSwap.shift_for_exchange.id]
+    a = _verifyForOneShiftSwap(shiftSwap, usedSlots, revision, verbose=False)
 
+    s1 = find_daily_rest_time_violation([x for x in a if x.member == member])
+    s2 = find_weekly_rest_time_violation([x for x in a if x.member == member])
     return len(s1) == 0 & len(s2) == 0, (s1, s2)
 
 
@@ -153,14 +173,17 @@ def perform_exchange_and_save_backup(shiftExchange: ShiftExchange, approver: Mem
     return shiftsAfterSwap
 
 
-def perform_simplified_exchange_and_save_backup(shift: Shift, newMember: Member, approver: Member, revisionBackup: Revision) -> ShiftExchange:
+def perform_simplified_exchange_and_save_backup(
+    shift: Shift, newMember: Member, requestor: Member, approver: Member, revisionBackup: Revision, exType="Normal"
+) -> ShiftExchange:
     """Performs a simplified shift exchange when in the existing shift new member is created"""
     fakeShift = _create_shift(
         shift, newMember, revision=revisionBackup, pre_comment="FakeAndTemporary shift created when updating the change of Member", permanent=True
     )
     sPair = ShiftExchangePair.objects.create(shift=shift, shift_for_exchange=fakeShift)
     sEx = ShiftExchange()
-    sEx.requestor = approver
+    sEx.requestor = requestor
+    sEx.type = exType
     sEx.approver = approver
     sEx.backupRevision = revisionBackup
     sEx.requested = timezone.now()
diff --git a/shifts/migrations/0016_auto_20240904_0814.py b/shifts/migrations/0016_auto_20240904_0814.py
new file mode 100644
index 0000000000000000000000000000000000000000..30bcb5bcd5366a5dd826df2bb173795edfd8b5e0
--- /dev/null
+++ b/shifts/migrations/0016_auto_20240904_0814.py
@@ -0,0 +1,40 @@
+# Generated by Django 3.2.16 on 2024-09-04 06:14
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ("shifts", "0015_shiftexchange_shiftexchangepair"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="desiderata",
+            name="type",
+            field=models.CharField(
+                choices=[("vac", "Vacation"), ("conf", "Conference"), ("wfh", "Work From Home"), ("other", "Other")], default="vac", max_length=10
+            ),
+        ),
+        migrations.CreateModel(
+            name="ShiftForMarket",
+            fields=[
+                ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
+                ("offered_date", models.DateTimeField(default=django.utils.timezone.now)),
+                ("is_available", models.BooleanField(default=True)),
+                ("is_taken", models.BooleanField(default=False)),
+                ("comments", models.TextField(blank=True, null=True)),
+                ("offerer", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+                ("shift", models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to="shifts.shift")),
+            ],
+            options={
+                "verbose_name": "Shift for market",
+                "verbose_name_plural": "Shifts for market",
+                "ordering": ["offered_date"],
+            },
+        ),
+    ]
diff --git a/shifts/migrations/0017_auto_20240905_1227.py b/shifts/migrations/0017_auto_20240905_1227.py
new file mode 100644
index 0000000000000000000000000000000000000000..31cbebbbaab5ea53a50eb90f0d8b7d4840e26814
--- /dev/null
+++ b/shifts/migrations/0017_auto_20240905_1227.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.16 on 2024-09-05 10:27
+
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("shifts", "0016_auto_20240904_0814"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="shiftformarket",
+            name="available_until",
+            field=models.DateField(blank=True, null=True),
+        ),
+        migrations.AddField(
+            model_name="shiftformarket",
+            name="taken_date",
+            field=models.DateTimeField(default=django.utils.timezone.now),
+        ),
+    ]
diff --git a/shifts/migrations/0018_shiftformarket_urgency.py b/shifts/migrations/0018_shiftformarket_urgency.py
new file mode 100644
index 0000000000000000000000000000000000000000..d37af2c3de1b368c231743e0c6527bdc9048f0a9
--- /dev/null
+++ b/shifts/migrations/0018_shiftformarket_urgency.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.16 on 2024-09-05 10:39
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("shifts", "0017_auto_20240905_1227"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="shiftformarket",
+            name="urgency",
+            field=models.CharField(choices=[("Normal", "Normal"), ("Urgent", "Urgent")], default="Normal", max_length=10),
+        ),
+    ]
diff --git a/shifts/migrations/0019_alter_shiftformarket_taken_date.py b/shifts/migrations/0019_alter_shiftformarket_taken_date.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3ef861cef475c80186238562c57a1c517757a14
--- /dev/null
+++ b/shifts/migrations/0019_alter_shiftformarket_taken_date.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.16 on 2024-09-05 11:12
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("shifts", "0018_shiftformarket_urgency"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="shiftformarket",
+            name="taken_date",
+            field=models.DateTimeField(blank=True, null=True),
+        ),
+    ]
diff --git a/shifts/migrations/0020_shiftexchange_type.py b/shifts/migrations/0020_shiftexchange_type.py
new file mode 100644
index 0000000000000000000000000000000000000000..142f2a56c1a44ffc5fa400fd355dc32977968361
--- /dev/null
+++ b/shifts/migrations/0020_shiftexchange_type.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.16 on 2024-09-05 20:33
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("shifts", "0019_alter_shiftformarket_taken_date"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="shiftexchange",
+            name="type",
+            field=models.CharField(choices=[("Normal", "Normal"), ("Urgent", "Urgent"), ("Business", "Business")], default="Normal", max_length=10),
+        ),
+    ]
diff --git a/shifts/migrations/0021_alter_shiftformarket_urgency.py b/shifts/migrations/0021_alter_shiftformarket_urgency.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4ba6648ef5ab5149cacb38739b0e14a24d89cb5
--- /dev/null
+++ b/shifts/migrations/0021_alter_shiftformarket_urgency.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.16 on 2024-09-07 13:16
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("shifts", "0020_shiftexchange_type"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="shiftformarket",
+            name="urgency",
+            field=models.CharField(blank=True, choices=[("Normal", "Normal"), ("Urgent", "Urgent")], default="Normal", max_length=10),
+        ),
+    ]
diff --git a/shifts/migrations/0022_alter_shiftformarket_urgency.py b/shifts/migrations/0022_alter_shiftformarket_urgency.py
new file mode 100644
index 0000000000000000000000000000000000000000..6315fb2d787e815964a2058c7dc8494547f6d735
--- /dev/null
+++ b/shifts/migrations/0022_alter_shiftformarket_urgency.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.2.16 on 2024-09-07 13:22
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("shifts", "0021_alter_shiftformarket_urgency"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="shiftformarket",
+            name="urgency",
+            field=models.CharField(choices=[("Normal", "Normal"), ("Urgent", "Urgent")], default="Normal", max_length=10),
+        ),
+    ]
diff --git a/shifts/models.py b/shifts/models.py
index a042c6e3190a561401ac8f8e2a0ca4151d831a6b..a03bafc6eaca30d8a9bf66d121aa5be38bc8aae0 100644
--- a/shifts/models.py
+++ b/shifts/models.py
@@ -153,7 +153,13 @@ class Desiderata(models.Model):
     )
 
     def get_as_json_for_gantt(self):
-        return {"name": self.member.name, "start": int(timezone.localtime(self.start).timestamp()), "end": int(timezone.localtime(self.stop).timestamp())}
+        event = {
+            "name": self.member.name,
+            "role": self.member.role,
+            "start": int(timezone.localtime(self.start).timestamp()),
+            "end": int(timezone.localtime(self.stop).timestamp()),
+        }
+        return event
 
     def get_as_json_event(self, team=False, editable=True):
         event = {
@@ -294,6 +300,10 @@ class Shift(models.Model):
     def shift_end(self) -> str:
         return self.get_proper_times(self.Moment.END).strftime(DATE_FORMAT_FULL)
 
+    @cached_property
+    def shift_day_of_week(self):
+        return self.date.strftime("%A")
+
     def get_proper_times(self, moment) -> datetime:
         timeToUse = self.slot.hour_start
         if moment == self.Moment.END:
@@ -305,12 +315,81 @@ class Shift(models.Model):
         return datetime.datetime.combine(self.date, timeToUse) + datetime.timedelta(days=deltaToAdd)
 
 
+class ShiftForMarket(models.Model):
+    URGENCY_CHOICES = [
+        ("Normal", "Normal"),
+        ("Urgent", "Urgent"),
+    ]
+
+    shift = models.ForeignKey(Shift, on_delete=DO_NOTHING)
+    offerer = models.ForeignKey(Member, on_delete=CASCADE)
+    offered_date = models.DateTimeField(default=timezone.now)
+    available_until = models.DateField(null=True, blank=True)
+    taken_date = models.DateTimeField(null=True, blank=True)
+    urgency = models.CharField(max_length=10, choices=URGENCY_CHOICES, default="Normal")
+    is_available = models.BooleanField(default=True)
+    is_taken = models.BooleanField(default=False)
+    comments = models.TextField(blank=True, null=True)
+
+    class Meta:
+        verbose_name = "Shift for market"
+        verbose_name_plural = "Shifts for market"
+        ordering = ["offered_date"]
+
+    def __str__(self):
+        return f"Shift [{self.shift}] put by {self.offerer} on {self.offered_date.strftime(DATE_FORMAT_FULL)}"
+
+    def mark_as_taken(self):
+        self.is_available = False
+        self.is_taken = True
+        self.taken_date = timezone.now()
+        self.save()
+
+    def check_if_available(self, date):
+        # print(self.available_until, date)
+        if self:
+            if date > self.shift.date:
+                self.is_available = False
+                self.save()
+        if self.available_until is not None:
+            if date > self.available_until:
+                self.is_available = False
+                self.save()
+
+    def mark_as_available(self):
+        self.is_available = True
+        self.is_taken = False
+        self.taken_date = None
+        self.save()
+
+    def get_offer_details(self):
+        return {
+            "shift": str(self.shift),
+            "offerer": str(self.offerer),
+            "offered_date": self.offered_date.strftime(DATE_FORMAT_FULL),
+            "is_available": self.is_available,
+            "is_taken": self.is_taken,
+            "comments": self.comments,
+        }
+
+    def get_market_shift_as_json_event(self) -> dict:
+        event = {
+            "id": self.id,
+            "title": f"{self.shift.slot.name} from Market [{self.urgency}]",
+            "start": self.shift.get_proper_times(self.shift.Moment.START).strftime(format=DATE_FORMAT_FULL),
+            "end": self.shift.get_proper_times(self.shift.Moment.END).strftime(format=DATE_FORMAT_FULL),
+            "url": reverse("shifter:market_shift_view", kwargs={"shift_id": self.id}),
+            "color": "#FF5733" if "Urgent" in self.urgency else "#ffb8a9",
+        }
+        return event
+
+
 class ShiftExchangePair(models.Model):
     shift = models.ForeignKey(Shift, on_delete=DO_NOTHING)
     shift_for_exchange = models.ForeignKey(Shift, on_delete=DO_NOTHING, related_name="for_exchange")
 
     def __str__(self):
-        return "[BEFORE] {} on {} {} with {} on {} {}".format(
+        return "[WAS] {} on {} {} with {} on {} {}".format(
             self.shift.member,
             self.shift.date,
             self.shift.slot.abbreviation,
@@ -321,6 +400,7 @@ class ShiftExchangePair(models.Model):
 
 
 class ShiftExchange(models.Model):
+    EXCHANGE_TYPE = [("Normal", "Normal"), ("Market", "Market"), ("Business", "Business")]
     requestor = models.ForeignKey(Member, on_delete=DO_NOTHING)
     requested = models.DateTimeField()
     tentative = models.BooleanField(default=True)
@@ -329,15 +409,15 @@ class ShiftExchange(models.Model):
         blank=True,
         null=True,
     )
-
+    type = models.CharField(max_length=10, choices=EXCHANGE_TYPE, default="Normal")
     shifts = models.ManyToManyField(ShiftExchangePair, blank=True)
     applicable = models.BooleanField(default=False)
     backupRevision = models.ForeignKey(Revision, on_delete=DO_NOTHING, related_name="revision")
     implemented = models.BooleanField(default=False)
 
     def __str__(self):
-        return "{} on {} for {} shifts swap; implemented:{}".format(
-            self.requestor, self.requested.strftime(SIMPLE_DATE), self.shifts.all().count(), self.implemented
+        return "[{}] {} on {} for {} shifts swap; implemented:{}".format(
+            self.type, self.requestor, self.requested.strftime(SIMPLE_DATE), self.shifts.all().count(), self.implemented
         )
 
     @cached_property
diff --git a/shifts/permanent_contexts.py b/shifts/permanent_contexts.py
index 2ac0a538caecb79513534b8dc89a73c0dec675c5..eb2dd86d60a35e2254f82082b7e75d5b08f42139 100644
--- a/shifts/permanent_contexts.py
+++ b/shifts/permanent_contexts.py
@@ -1,5 +1,5 @@
 from .activeshift import prepare_active_crew
-from .models import Contact
+from .models import Contact, ShiftForMarket
 
 import django.contrib.messages as messages
 from members.models import Team
@@ -31,6 +31,13 @@ def useful_contact_context(request):
     return {"useful_contact": contacts}
 
 
+def shift_market_count(request):
+    if request.user.is_authenticated:
+        shift_count = ShiftForMarket.objects.filter(is_available=True, shift__member__role=request.user.role).count()
+        return {"shift_count": shift_count}
+    return {}
+
+
 def nav_bar_context(request):
     teams = Team.objects.all().order_by("name")
     return {"teams": teams}
diff --git a/shifts/static/js/calendar_script.js b/shifts/static/js/calendar_script.js
index c3d0186a0eba2858bcdc81ffdb5ab24fabdc12a7..35ca7680d0ca9ab838aebea60ec1ee8a86965b37 100644
--- a/shifts/static/js/calendar_script.js
+++ b/shifts/static/js/calendar_script.js
@@ -85,10 +85,30 @@ $(document).ready(function () {
         info.jsEvent.preventDefault();
         var eventObj = info.event;
         $('#modalTitle').html(eventObj.title + " for " + eventObj.extendedProps.slot + " on " + eventObj.start);
-        $('#modalPre').html( "Pre shift comments  : " + eventObj.extendedProps.pre_comment);
-        $('#modalPost').html("Post shift comments : " + eventObj.extendedProps.post_comment);
         $('#eventUrl').attr('href',eventObj.url);
-        $('#eventEdit').attr('href',"/shift/"+eventObj.id);
+        if (eventObj.url.includes('market')) {
+            $('#eventUrl').text("See on market");
+            $('#eventEdit').addClass("disabled");
+            $('#eventView').addClass("disabled");
+            $('#modalPre').text("");
+            $('#modalPost').text("");
+        }
+        else if (eventObj.url.includes('studies')) {
+            $('#eventUrl').text("Check the study details");
+            $('#eventEdit').addClass("disabled");
+            $('#eventView').addClass("disabled");
+            $('#modalPre').text("");
+            $('#modalPost').text("");
+        }
+        else {
+            $('#eventUrl').text("Continue to overview");
+            $('#eventView').removeClass("disabled");
+            $('#eventEdit').removeClass("disabled");
+            $('#eventEdit').attr('href',"/shift/"+eventObj.id);
+            $('#eventView').attr('href',"/shift/"+eventObj.id+"/view");
+            $('#modalPre').html( "Pre shift comments  : " + eventObj.extendedProps.pre_comment);
+            $('#modalPost').html("Post shift comments : " + eventObj.extendedProps.post_comment);
+        }
         $('#calendarModal').modal("show");
       },
       eventLimit: true, // allow 'more' link when too many events
@@ -117,6 +137,14 @@ $(document).ready(function () {
         alert('there was an error while fetching events!');
       },
 
+    },
+    {
+      id: "market",
+      url: $('#calendar').data('source-market-events'),
+      failure: function() {
+        alert('there was an error while fetching events!');
+      },
+
     },
     {
       id: "holidays",
diff --git a/shifts/static/js/calendar_script.min.js b/shifts/static/js/calendar_script.min.js
index 20cde604796ededf2185cbd032dd3544594acf62..d9c6607d9b29ff45f94fca8cf122e89cc45b4b23 100644
--- a/shifts/static/js/calendar_script.min.js
+++ b/shifts/static/js/calendar_script.min.js
@@ -1 +1 @@
-function get_selected_campaigns(){return $(".displayed_campaigns").val()}function get_revision(){return null!==document.getElementById("displayed_revision")?$(".displayed_revision").val():-1}function get_revision_next(){return $("[name='future_revisions_checkboxes']").length?$("input[name='future_revisions_checkboxes']:checked").data("future_rev_id"):-1}function get_specific_users(){return null!==document.getElementById("users_selection")?$(".users_selection").val():-1}function get_team_id(){let e=$("#team_id_for_ajax");return e.length?e.data("id"):-1}function get_member_id(){let e=$("member_id");return e.length?e.data("id"):-1}$(document).ready(function(){let e=document.getElementById("calendar"),t=new FullCalendar.Calendar(e,{themeSystem:"bootstrap5",contentHeight:"auto",customButtons:{myCustomButton:{text:"Tools",click:function(){myOffcanvas=$("#tools_off_canvas"),new bootstrap.Offcanvas(myOffcanvas).show()}}},headerToolbar:{left:"prev,today,next",center:"title",right:"myCustomButton dayGridMonth,timeGridWeek"},columnFormat:{month:"ddd",week:"ddd M/d"},initialDate:$("#calendar").data("default-date"),weekNumbers:!0,navLinks:!0,editable:!1,firstDay:1,businessHours:[{daysOfWeek:[1,2,3,4,5],startTime:"08:00",endTime:"18:00"},],eventClick:function(e){e.jsEvent.preventDefault();var t=e.event;$("#modalTitle").html(t.title+" for "+t.extendedProps.slot+" on "+t.start),$("#modalPre").html("Pre shift comments  : "+t.extendedProps.pre_comment),$("#modalPost").html("Post shift comments : "+t.extendedProps.post_comment),$("#eventUrl").attr("href",t.url),$("#eventEdit").attr("href","/shift/"+t.id),$("#calendarModal").modal("show")},eventLimit:!0,eventDisplay:"block",eventOrder:"start,id,name,title",eventSources:[{id:"shifts",url:$("#calendar").data("source-shifts"),extraParams:function(){return{all_roles:$("#all_roles").is(":checked"),all_states:$("#all_states").is(":checked"),companion:$("#show_companion").is(":checked"),revision:get_revision(),revision_next:get_revision_next(),campaigns:get_selected_campaigns(),team:get_team_id(),member:get_member_id(),users:get_specific_users()}},failure:function(){alert("there was an error while fetching events!")}},{id:"holidays",url:$("#calendar").data("source-holidays"),failure:function(){alert("there was an error while fetching public holidays!")}},{id:"teamevents",url:$("#calendar").data("source-team-events"),failure:function(){alert("there was an error while fetching team-events dates!")}},{id:"studies",url:$("#calendar").data("source-studies"),extraParams:function(){return{show_studies:$("#show_studies").is(":checked"),team:get_team_id(),member:get_member_id()}},failure:function(){alert("there was an error while fetching studies planning!")}}]});t.render(),$("#all_roles").change(function(){t.getEventSourceById("shifts").refetch()}),$("#all_states").change(function(){t.getEventSourceById("shifts").refetch()}),$("#show_companion").change(function(){t.getEventSourceById("shifts").refetch()}),$("#show_studies").change(function(){t.getEventSourceById("studies").refetch()}),$(".users_selection").change(function(){t.getEventSourceById("shifts").refetch()}),$(".displayed_campaigns").change(function(){t.getEventSourceById("shifts").refetch()}),$("#planning-tab").click(function(){t.render()}),$("input[type=radio][name=future_revisions_checkboxes]").change(function(){t.getEventSourceById("shifts").refetch()})});
+function get_selected_campaigns(){return $(".displayed_campaigns").val()}function get_revision(){return null!==document.getElementById("displayed_revision")?$(".displayed_revision").val():-1}function get_revision_next(){return $("[name='future_revisions_checkboxes']").length?$("input[name='future_revisions_checkboxes']:checked").data("future_rev_id"):-1}function get_specific_users(){return null!==document.getElementById("users_selection")?$(".users_selection").val():-1}function get_team_id(){let e=$("#team_id_for_ajax");return e.length?e.data("id"):-1}function get_member_id(){let e=$("member_id");return e.length?e.data("id"):-1}$(document).ready(function(){let e=document.getElementById("calendar"),t=new FullCalendar.Calendar(e,{themeSystem:"bootstrap5",contentHeight:"auto",customButtons:{myCustomButton:{text:"Tools",click:function(){myOffcanvas=$("#tools_off_canvas"),new bootstrap.Offcanvas(myOffcanvas).show()}}},headerToolbar:{left:"prev,today,next",center:"title",right:"myCustomButton dayGridMonth,timeGridWeek"},columnFormat:{month:"ddd",week:"ddd M/d"},initialDate:$("#calendar").data("default-date"),weekNumbers:!0,navLinks:!0,editable:!1,firstDay:1,businessHours:[{daysOfWeek:[1,2,3,4,5],startTime:"08:00",endTime:"18:00"},],eventClick:function(e){e.jsEvent.preventDefault();var t=e.event;$("#modalTitle").html(t.title+" for "+t.extendedProps.slot+" on "+t.start),$("#eventUrl").attr("href",t.url),t.url.includes("market")?($("#eventUrl").text("See on market"),$("#eventEdit").addClass("disabled"),$("#eventView").addClass("disabled"),$("#modalPre").text(""),$("#modalPost").text("")):t.url.includes("studies")?($("#eventUrl").text("Check the study details"),$("#eventEdit").addClass("disabled"),$("#eventView").addClass("disabled"),$("#modalPre").text(""),$("#modalPost").text("")):($("#eventUrl").text("Continue to overview"),$("#eventView").removeClass("disabled"),$("#eventEdit").removeClass("disabled"),$("#eventEdit").attr("href","/shift/"+t.id),$("#eventView").attr("href","/shift/"+t.id+"/view"),$("#modalPre").html("Pre shift comments  : "+t.extendedProps.pre_comment),$("#modalPost").html("Post shift comments : "+t.extendedProps.post_comment)),$("#calendarModal").modal("show")},eventLimit:!0,eventDisplay:"block",eventOrder:"start,id,name,title",eventSources:[{id:"shifts",url:$("#calendar").data("source-shifts"),extraParams:function(){return{all_roles:$("#all_roles").is(":checked"),all_states:$("#all_states").is(":checked"),companion:$("#show_companion").is(":checked"),revision:get_revision(),revision_next:get_revision_next(),campaigns:get_selected_campaigns(),team:get_team_id(),member:get_member_id(),users:get_specific_users()}},failure:function(){alert("there was an error while fetching events!")}},{id:"market",url:$("#calendar").data("source-market-events"),failure:function(){alert("there was an error while fetching events!")}},{id:"holidays",url:$("#calendar").data("source-holidays"),failure:function(){alert("there was an error while fetching public holidays!")}},{id:"teamevents",url:$("#calendar").data("source-team-events"),failure:function(){alert("there was an error while fetching team-events dates!")}},{id:"studies",url:$("#calendar").data("source-studies"),extraParams:function(){return{show_studies:$("#show_studies").is(":checked"),team:get_team_id(),member:get_member_id()}},failure:function(){alert("there was an error while fetching studies planning!")}}]});t.render(),$("#all_roles").change(function(){t.getEventSourceById("shifts").refetch()}),$("#all_states").change(function(){t.getEventSourceById("shifts").refetch()}),$("#show_companion").change(function(){t.getEventSourceById("shifts").refetch()}),$("#show_studies").change(function(){t.getEventSourceById("studies").refetch()}),$(".users_selection").change(function(){t.getEventSourceById("shifts").refetch()}),$(".displayed_campaigns").change(function(){t.getEventSourceById("shifts").refetch()}),$("#planning-tab").click(function(){t.render()}),$("input[type=radio][name=future_revisions_checkboxes]").change(function(){t.getEventSourceById("shifts").refetch()})});
diff --git a/shifts/static/js/desiderata_gantt.js b/shifts/static/js/desiderata_gantt.js
index e2ec41785267ac735a5aa8ee8881fe778512e787..379aff584ad5d966dbb2af1f4bfa07ca98558645 100644
--- a/shifts/static/js/desiderata_gantt.js
+++ b/shifts/static/js/desiderata_gantt.js
@@ -38,6 +38,15 @@ function fill_gantt_plots() {
         url: $('#gantt-container').data('content_url'),
         data: { start: dStart, end: dEnd, team: teamId},
         success: function(dataJSON) {
+            var roleColors = {
+                'Operator': '#AFF359',
+                'ShiftLeader': '#1338BE',
+            };
+
+            dataJSON.series.data.forEach(function(point) {
+                point.color = roleColors[point.role] || '#000000';
+            });
+
             Highcharts.ganttChart('gantt-container', {
                 title: {
                     text: "Team Desiderata for overview"
@@ -47,7 +56,7 @@ function fill_gantt_plots() {
                     max: xAxisMax,
                     labels: {
                         formatter: function() {
-                            var diffInMonths = (endDate.getFullYear() - startDate.getFullYear()) * 12 + endDate.getMonth() - startDate.getMonth() +1;
+                            var diffInMonths = (endDate.getFullYear() - startDate.getFullYear()) * 12 + endDate.getMonth() - startDate.getMonth() + 1;
                             if (diffInMonths < 6) {
                                 return Highcharts.dateFormat('W %W', this.value);
                             } else {
diff --git a/shifts/static/js/desiderata_gantt.min.js b/shifts/static/js/desiderata_gantt.min.js
index a27d26adefd1a78610f92110b074284291a5cdfc..e7f83899ccb127ae314adbbbfa221d4228c2f918 100644
--- a/shifts/static/js/desiderata_gantt.min.js
+++ b/shifts/static/js/desiderata_gantt.min.js
@@ -1 +1 @@
-var dStart,dEnd;const currentYear=new Date().getFullYear();function fill_gantt_plots(){var t=$("team_id").data("id"),a=new Date(dStart),e=new Date(dEnd),r=Date.UTC(a.getFullYear(),a.getMonth(),a.getDate()),n=Date.UTC(e.getFullYear(),e.getMonth(),e.getDate());$.ajax({dataType:"json",method:"GET",url:$("#gantt-container").data("content_url"),data:{start:dStart,end:dEnd,team:t},success:function(t){Highcharts.ganttChart("gantt-container",{title:{text:"Team Desiderata for overview"},xAxis:{min:r,max:n,labels:{formatter:function(){return(e.getFullYear()-a.getFullYear())*12+e.getMonth()-a.getMonth()+1<6?Highcharts.dateFormat("W %W",this.value):Highcharts.dateFormat("%b",this.value)}}},yAxis:t.yAxis,series:[{name:t.series.Name,data:t.series.data,pointWidth:30}]})},error:function(){alert("There was an error while fetching stats!")}})}$(document).ready(function(){dStart=`${currentYear}-01-01`,dEnd=`${currentYear}-12-31`,$("#stat_desiderata_data_range_picker").daterangepicker({opens:"left"}),$("#stat_desiderata_data_range_picker").on("change",function(){dStart=$("#stat_desiderata_data_range_picker").data("daterangepicker").startDate.format("YYYY-MM-DD"),dEnd=$("#stat_desiderata_data_range_picker").data("daterangepicker").endDate.format("YYYY-MM-DD"),fill_gantt_plots()}),fill_gantt_plots()});
+var dStart,dEnd;const currentYear=new Date().getFullYear();function fill_gantt_plots(){var t=$("team_id").data("id"),a=new Date(dStart),e=new Date(dEnd),r=Date.UTC(a.getFullYear(),a.getMonth(),a.getDate()),n=Date.UTC(e.getFullYear(),e.getMonth(),e.getDate());$.ajax({dataType:"json",method:"GET",url:$("#gantt-container").data("content_url"),data:{start:dStart,end:dEnd,team:t},success:function(t){var d={Operator:"#AFF359",ShiftLeader:"#1338BE"};t.series.data.forEach(function(t){console.log(t),t.color=d[t.role]||"#000000"}),Highcharts.ganttChart("gantt-container",{title:{text:"Team Desiderata for overview"},xAxis:{min:r,max:n,labels:{formatter:function(){return(e.getFullYear()-a.getFullYear())*12+e.getMonth()-a.getMonth()+1<6?Highcharts.dateFormat("W %W",this.value):Highcharts.dateFormat("%b",this.value)}}},yAxis:t.yAxis,series:[{name:t.series.Name,data:t.series.data,pointWidth:30}]})},error:function(){alert("There was an error while fetching stats!")}})}$(document).ready(function(){dStart=`${currentYear}-01-01`,dEnd=`${currentYear}-12-31`,$("#stat_desiderata_data_range_picker").daterangepicker({opens:"left"}),$("#stat_desiderata_data_range_picker").on("change",function(){dStart=$("#stat_desiderata_data_range_picker").data("daterangepicker").startDate.format("YYYY-MM-DD"),dEnd=$("#stat_desiderata_data_range_picker").data("daterangepicker").endDate.format("YYYY-MM-DD"),fill_gantt_plots()}),fill_gantt_plots()});
diff --git a/shifts/static/js/shift_control.js b/shifts/static/js/shift_control.js
index 074d9b92d39b2ab3dff930a3926fdf2c8d286146..3c282ff222a4fd40ff19443a91ea3d28e99966cb 100644
--- a/shifts/static/js/shift_control.js
+++ b/shifts/static/js/shift_control.js
@@ -20,9 +20,12 @@ $(document).ready(function() {
         dom: 'P',
         bPaginate: false,
         paging: false,
+        searchPanes: {
+            initCollapsed: true
+        },
         columns: [
             { data: 'date', title: 'Day' },
-            { data: 'members', title: 'Shifts' },
+            { data: 'members', title: 'Crew' },
         ],
         autoWidth: false,
     });
diff --git a/shifts/static/js/shift_control.min.js b/shifts/static/js/shift_control.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..638e5e7cbbb6aad9bf57e269c490effd461b212f
--- /dev/null
+++ b/shifts/static/js/shift_control.min.js
@@ -0,0 +1 @@
+$(document).ready(function(){$("#shiftControl_date_range_picker").daterangepicker({opens:"left"}),$("#shiftControl_date_range_picker").on("change",function(){$("#table_ShiftControl").DataTable().ajax.reload()}),$("#table_ShiftControl").DataTable({ajax:{url:$("#table_ShiftControl").data("source"),data:function(a){a.start=$("#shiftControl_date_range_picker").data("daterangepicker").startDate.format("YYYY-MM-DD"),a.end=$("#shiftControl_date_range_picker").data("daterangepicker").endDate.format("YYYY-MM-DD"),a.team=$("team_id").data("id")},dataSrc:"data"},dom:"P",bPaginate:!1,paging:!1,searchPanes:{initCollapsed:!0},columns:[{data:"date",title:"Day"},{data:"members",title:"Crew"},],autoWidth:!1})});
diff --git a/shifts/static/js/team_shiftswaps.js b/shifts/static/js/team_shiftswaps.js
index 091f76993427597a4a62b10b2cf558f3f9f722ff..ce7e5c6b523e85ddc76ec29eade3adfeba79234a 100644
--- a/shifts/static/js/team_shiftswaps.js
+++ b/shifts/static/js/team_shiftswaps.js
@@ -6,6 +6,7 @@ $(document).ready(function() {
     $('#shiftswap_date_range_picker').on('change', function() {
         $('#table_shiftswap').DataTable().ajax.reload();
     });
+
     $('#table_shiftswap').DataTable({
         ajax: {
             url: $('#table_shiftswap').data('source'),
@@ -18,25 +19,31 @@ $(document).ready(function() {
         dom: 'P',
         bPaginate: false,
         paging: false,
-//        searchPanes: {
-//            initCollapsed: true
-//        },
-        "columns": [{
+        searchPanes: {
+            initCollapsed: true
+        },
+        columns: [{
                 searchPanes: {
                     show: false
                 }
             },
+            { // type
+            },
             {
                 searchPanes: {
                     show: false
                 }
             },
+            { // name req
+            },
             {
-//                visible:true,
                 searchPanes: {
                     show: false
                 }
             },
+            { // name approve
+            },
+
             {
                 searchPanes: {
                     show: false
diff --git a/shifts/static/js/team_shiftswaps.min.js b/shifts/static/js/team_shiftswaps.min.js
index 1c7156a8c0fd65f66a28db7937376f332b3b6228..3c875e9c29165bcc5e334a49623f1a64a025f799 100644
--- a/shifts/static/js/team_shiftswaps.min.js
+++ b/shifts/static/js/team_shiftswaps.min.js
@@ -1 +1 @@
-$(document).ready(function(){$("#shiftswap_date_range_picker").daterangepicker({opens:"left"}),$("#shiftswap_date_range_picker").on("change",function(){$("#table_shiftswap").DataTable().ajax.reload()}),$("#table_shiftswap").DataTable({ajax:{url:$("#table_shiftswap").data("source"),data:function(a){a.start=$("#shiftswap_date_range_picker").data("daterangepicker").startDate.format("YYYY-MM-DD"),a.end=$("#shiftswap_date_range_picker").data("daterangepicker").endDate.format("YYYY-MM-DD"),a.team=$("team_id").data("id")}},dom:"P",bPaginate:!1,paging:!1,columns:[{searchPanes:{show:!1}},{searchPanes:{show:!1}},{searchPanes:{show:!1}},{searchPanes:{show:!1}},],autoWidth:!1})});
+$(document).ready(function(){$("#shiftswap_date_range_picker").daterangepicker({opens:"left"}),$("#shiftswap_date_range_picker").on("change",function(){$("#table_shiftswap").DataTable().ajax.reload()}),$("#table_shiftswap").DataTable({ajax:{url:$("#table_shiftswap").data("source"),data:function(a){a.start=$("#shiftswap_date_range_picker").data("daterangepicker").startDate.format("YYYY-MM-DD"),a.end=$("#shiftswap_date_range_picker").data("daterangepicker").endDate.format("YYYY-MM-DD"),a.team=$("team_id").data("id")}},dom:"P",bPaginate:!1,paging:!1,searchPanes:{initCollapsed:!0},columns:[{searchPanes:{show:!1}},{},{searchPanes:{show:!1}},{},{searchPanes:{show:!1}},{},{searchPanes:{show:!1}},],autoWidth:!1})});
diff --git a/shifts/templates/calendar.html b/shifts/templates/calendar.html
index ba41e7ee1a40610fd6e7545914603a2d7e16b414..050f57a8f9079dceb887bf0fb70da415cda4ce7d 100644
--- a/shifts/templates/calendar.html
+++ b/shifts/templates/calendar.html
@@ -3,6 +3,7 @@
         <div class="col-lg-10">
             <div id="calendar" style="padding-top: 10px;"
                  data-source-shifts="{{event_source}}"
+                 data-source-market-events="{{market_event_source}}"
                  data-source-studies="{% url 'studies:ajax.get_studies' %}"
                  data-source-holidays="{% url 'ajax.get_holidays' %}"
                  data-source-team-events="{% url 'ajax.get_team_events' %}"
@@ -25,8 +26,10 @@
         </div>
         {%endif%}
         <div class="modal-footer">
-            {%if request.user.is_staff %} <a id="eventEdit" type="button" class="btn btn-danger" data-dismiss="modal">Edit pre/post messages</a> {%endif%}
-            <a id="eventUrl" type="button" class="btn btn-success" data-dismiss="modal">Continue to shifter's schedule</a>
+            {%if request.user.is_staff or user_view %} <a id="eventEdit" type="button" class="btn btn-danger" data-dismiss="modal">
+            <i class="fa-solid fa-user-tie fa-1x"></i>&nbsp&nbsp<strong>EDIT</strong></a> {%endif%}
+            <a id="eventView" type="button" class="btn btn-success" data-dismiss="modal">View details</a>
+            <a id="eventUrl" type="button" class="btn btn-success" data-dismiss="modal">Continue to overview</a>
         </div>
     </div>
 </div>
diff --git a/shifts/templates/layout/navbar.html b/shifts/templates/layout/navbar.html
index f401ae001135f73320f020468ca600f539b28469..9b035fb226419a9533ccf8ca8856e6ba81668cc1 100644
--- a/shifts/templates/layout/navbar.html
+++ b/shifts/templates/layout/navbar.html
@@ -70,13 +70,24 @@
                         </div>
                     </a>
                 </li>
+                <li class="nav-item position-relative">
+                    <a class="nav-link {% if request.resolver_match.url_name == 'shifts_market' %}active{% endif %}" href="{% url 'shifts_market' %}">
+                        <div class="d-flex flex-column align-items-center">
+                            <i class="fa-solid fa-store fa-1x"></i>
+                            <span class="text-center">Shift Market</span>
+                            {% if shift_count > 0 %}
+                                <span class="badge bg-danger position-absolute top-0 start-100 translate-middle badge rounded-pill">{{ shift_count }}</span>
+                            {% endif %}
+                        </div>
+                    </a>
+                </li>
                 {% endif %}
                 <!-- Rota-maker Link (Rota-maker role required) -->
                 {% if rota_maker_for %}
                 <li class="nav-item dropdown">
                     <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                         <div class="d-flex flex-column align-items-center">
-                            <i class="fa-solid fa-people-group fa-1x"></i>
+                            <i class="fa-solid fa-user-tie fa-1x"></i>
                             <span class="text-center">Rota-maker</span>
                         </div>
                     </a>
@@ -103,7 +114,7 @@
                 {% if user.is_authenticated %}
                 <li class="nav-item dropdown dropstart">
                     <a class="nav-link dropdown-toggle d-flex align-items-center m-0 p-0 ps-3" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
-                        <img class="rounded-circle" loading="lazy" height="35" src={% if shift.member.photo|length > 0 %} "data:image/gif;base64,{{shift.member.photo}}" {% else %} {% static 'img/anonymous.png' %} {% endif %} />
+                        <img class="rounded-circle" loading="lazy" height="35" src={% if request.user.photo|length > 0 %} "data:image/gif;base64,{{request.user.photo}}" {% else %} {% static 'img/anonymous.png' %} {% endif %} />
                         {% live_notify_badge badge_class="badge" %}
                     </a>
                     <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
@@ -130,11 +141,11 @@
 </nav>
 
 <style>
-.nav-link {
-  color: #000000; /* Icons color */
-  transition: color 0.3s, background-color 0.3s, transform 0.3s;
-  display: flex;
-  align-items: center;
-  padding: 0.5rem 1rem; /* Adjust padding as needed */
-}
+    .nav-link {
+            color: #000000; /* Icons color */
+            transition: color 0.3s, background-color 0.3s, transform 0.3s;
+            display: flex;
+            align-items: center;
+            padding: 0.5rem 1rem; /* Adjust padding as needed */
+    }
 </style>
diff --git a/shifts/templates/shift_edit.html b/shifts/templates/shift_edit.html
index 25263b02ebfce30df67616b8032390c413f53d33..563cf3fd9188aedc0bd75738c825a0d209453d15 100644
--- a/shifts/templates/shift_edit.html
+++ b/shifts/templates/shift_edit.html
@@ -1,16 +1,16 @@
 {% extends 'template_main.html'%}
 {% block body %}
 
-{%if request.user.is_staff %}
+{%if not edit or request.user.is_staff or shift.member == request.user %}
 <div class="container mb-5 pb-5">
     <div class="col">
         <h2>{{shift}}</h2>
+         {% if request.user.is_staff and edit%}
          <form action="{% url 'shifter:shift-single-exchange-post' shift.id %}" method="POST" enctype="multipart/form-data" class="form-horizontal">
             {% csrf_token %}
-
             <div class="form-select bg-warning">
-                <label for="shiftMember" class="form-label">Assigned shift member:</label>
-                <p>Note: Updating member will create an approved ShiftExchange with respective notifications!</p>
+                <h4>Re-assign shift member</h4>
+                <p>Note: Updating member will create an <strong>approved ShiftExchange</strong> with respective notifications!</p>
                 <select class="form-select" name='shiftMember' id='shiftMember'>
                     {% for sr in replacement %}
                         <option value="{{sr.id}}" {%if shift.member == sr%} selected {%endif%}>Shifter - {{sr.name}}</option>
@@ -18,20 +18,23 @@
                 </select>
                 <br>
                 <div class="form-floating">
-                <button class="btn btn-dark">Update shift member</button>
+                  <button class="btn btn-danger"><i class="fa-solid fa-user-tie fa-1x"></i>&nbsp Update shift member</button>
                 </div>
             </div>
-         </form>
-        <form action="{% url 'shifter:shift-edit-post' shift.id %}" method="POST" enctype="multipart/form-data" class="form-horizontal">
+          </form>
+          {% endif %}
+          {% if edit %}
+          <form action="{% url 'shifter:shift-edit-post' shift.id %}" method="POST" enctype="multipart/form-data" class="form-horizontal">
             {% csrf_token %}
             <hr class="hr" />
             <h4>Update current shift</h4>
+              Make an update to the shift, accoding to the need.
             <div class="form-select">
                 <label for="shiftRole" class="form-label">Assigned shift role:</label>
                 <select class="form-select" name='shiftRole' id='shiftRole'>
                     <option value="-1">Default: Member Role - {{shift.member.role}}</option>
                     {% for sr in shiftRoles %}
-                        <option value="{{sr.id}}" {%if shift.role == sr%} selected {%endif%}>Shift Role - {{sr.name}}</option>
+                        <option value="{{sr.id}}" {% if shift.role == sr %} selected {% endif %}>Shift Role - {{sr.name}}</option>
                     {% endfor %}
                 </select>
             </div>
@@ -40,39 +43,118 @@
                         style="height: 100px">{{shift.pre_comment}}</textarea>
               <label for="preShiftComment">Pre-shift memo</label>
             </div>
-
             <div class="form-check">
               <input class="form-check-input" type="checkbox" name="activeShift"
-                     id="activeShift" {%if shift.is_active%}checked{%endif%} >
+                     id="activeShift" {% if shift.is_active %}checked{% endif %}>
               <label class="form-check-label" for="activeShift">
                 Is this shift valid and still in schedule? Note: removing will require admin access to undo!
               </label>
             </div>
-
             <div class="form-check">
               <input class="form-check-input" type="checkbox" name="cancelledLastMinute"
-                     id="cancelledLastMinute" {%if shift.is_cancelled%}checked{%endif%}>
+                     id="cancelledLastMinute" {% if shift.is_cancelled %}checked{% endif %}>
               <label class="form-check-label" for="cancelledLastMinute">
                 Canceled last minute?
               </label>
             </div>
-
             <div class="form-floating">
               <textarea class="form-control" placeholder="Anything to add?" name="postShiftComment" id="postShiftComment"
                         style="height: 100px">{{shift.post_comment}}</textarea>
               <label for="postShiftComment">Post shift/cancellation comment</label>
             </div>
-
             <div class="form-floating">
                 <button class="btn btn-primary">Update shift details</button>
             </div>
         </form>
+        {% endif %}
+        <div>
+            <hr/>
+        </div>
+        <h4>Submit to shift market or Take shift</h4>
+        <p>Make it available for others or take it yourself. Note: Once transferred, you may need to find another time to work the missing hours.</p>
+
+        {% if not on_market %}
+            <button type="button" class="btn btn-secondary btn-lg" data-bs-toggle="modal" data-bs-target="#addShiftToMarketModal">
+                Add to market <i class="fa-solid fa-store fa-1x"></i>
+            </button>
+        {% else %}
+        {% if on_market.is_available %}
+            <button type="button" class="btn btn-success btn-lg" data-bs-toggle="modal" data-bs-target="#takeShiftModal">
+                Take shift <i class="fa-solid fa-check fa-1x"></i>
+            </button>
+
+            <div class="modal fade" id="takeShiftModal" tabindex="-1" aria-labelledby="takeShiftModalLabel" aria-hidden="true">
+                <div class="modal-dialog">
+                    <div class="modal-content">
+                        <div class="modal-header">
+                            <h5 class="modal-title" id="takeShiftModalLabel">Confirm Shift Take</h5>
+                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                        </div>
+                        <div class="modal-body">
+                            <p>Are you sure you want to take this shift?</p>
+                            <p><strong>Shift:</strong> {{ shift }}</p>
+                            <p><strong>Date:</strong> {{ shift.date }}</p>
+                        </div>
+                        <div class="modal-footer">
+                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
+                            <a href="{% url 'shifter:take_shift' on_market.id %}" class="btn btn-success">Confirm</a>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        {% endif %}
+
+
+        {% endif %}
+
+
+
+
+        <div class="modal fade" id="addShiftToMarketModal" tabindex="-1" aria-labelledby="addShiftToMarketModalLabel" aria-hidden="true">
+          <div class="modal-dialog">
+              <div class="modal-content">
+                  <div class="modal-header">
+                      <h5 class="modal-title" id="addShiftToMarketModalLabel">Add Shift to Market</h5>
+                      <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                  </div>
+                  <form action="{% url 'shifter:add_shift_to_market' shift.id %}" method="POST">
+                      {% csrf_token %}
+                      <div class="modal-body">
+                          <div class="form-floating">
+                              <textarea class="form-control" placeholder="Add a comment" name="marketComment" id="marketComment" style="height: 100px"></textarea>
+                              <label for="marketComment">Comment for the market</label>
+                          </div>
+
+                          <div class="form-floating mt-3">
+                              <input type="date" class="form-control" name="availableUntil" id="availableUntil">
+                              <label for="availableUntil">Available Until</label>
+                          </div>
+
+                          <div class="form-floating mt-3">
+                              <select class="form-select" id="urgency" name="urgency" required>
+                                  <option value="Normal" selected>Normal</option>
+                                  <option value="Urgent">Urgent</option>
+                              </select>
+                              <label for="urgency">Urgency</label>
+                          </div>
+                      </div>
+                      <div class="modal-footer">
+                          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
+                          <button type="submit" class="btn btn-primary">Submit to Market</button>
+                      </div>
+                  </form>
+              </div>
+          </div>
+      </div>
     </div>
 </div>
-{%else%}
-<div class="container mb-5 pb-5"> <h3>You do not have permission to navigate here! Contact OP group for further assistance.</h3></div>
-{%endif%}
+{% else %}
+<div class="container mb-5 pb-5">
+    <h3>You do not have permission to navigate here! Contact OP group for further assistance.</h3>
+</div>
+{% endif %}
 {% endblock %}
 
-{%  block js %}
+{% block js %}
+<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
 {% endblock %}
diff --git a/shifts/templates/shift_market_email.html b/shifts/templates/shift_market_email.html
new file mode 100644
index 0000000000000000000000000000000000000000..b75ee3e00c04d1fe299e18a187777c6f10cf8524
--- /dev/null
+++ b/shifts/templates/shift_market_email.html
@@ -0,0 +1,13 @@
+Dear Shifter ({{shiftForMarket.shift.member.role}}),
+
+This is an automatic message regarding a new shift put on market.
+Consult {{domain}}/shift-market for details.
+
+{{shiftForMarket}}
+     Comment: {{shiftForMarket.comments}}
+     Urgency: {{shiftForMarket.urgency}}
+
+Manage your notifications in {{ domain }}/user?notifications
+Thanks!
+--
+CR_OperationsGroup@ess.eu
diff --git a/shifts/templates/shiftexchange_edit.html b/shifts/templates/shiftexchange_edit.html
new file mode 100644
index 0000000000000000000000000000000000000000..96a92b5670a201c9c683957f31100aece7f79a0b
--- /dev/null
+++ b/shifts/templates/shiftexchange_edit.html
@@ -0,0 +1,36 @@
+{% extends 'template_main.html'%}
+{% block body %}
+
+{%if request.user.is_staff %}
+<div class="container mb-5 pb-5">
+    <div class="col">
+        <div class="empty-div"></div>
+        <div class="card text-center">
+          <div class="card-header">
+            <span class="badge bg-dark">{{sEx.type}}</span> shift exchange.
+          </div>
+          <div class="card-body">
+            <h5 class="card-title">Shift exchange details</h5>
+            <p class="card-text">Requested by {{sEx.requestor}} on {{sEx.requested}}</p>
+            <p class="card-text">The follwoing shifts were exchanged:</p>
+            <hr>
+            {% for onePair in sEx.shifts.all%}
+              <p> <small>[WAS]</small> {{onePair.shift}} <i class="fa-solid fa-arrows-left-right"></i>
+                  <small>[IS now]</small> {{onePair.shift_for_exchange.member}}</p>
+            <p>[taker old shift] {{onePair.shift_for_exchange}}</p>
+            <hr>
+            {%endfor%}
+          </div>
+          <div class="card-footer text-muted">
+            Approved on: {{sEx.approved}} by {{sEx.approver}}
+          </div>
+        </div>
+    </div>
+</div>
+{%else%}
+<div class="container mb-5 pb-5"> <h3>You do not have permission to navigate here! Contact OP group for further assistance.</h3></div>
+{%endif%}
+{% endblock %}
+
+{%  block js %}
+{% endblock %}
diff --git a/shifts/templates/shifts_market.html b/shifts/templates/shifts_market.html
new file mode 100644
index 0000000000000000000000000000000000000000..0bbb8cc469d5e736b0d3518995fdbf5bc738bb09
--- /dev/null
+++ b/shifts/templates/shifts_market.html
@@ -0,0 +1,110 @@
+{% extends 'template_main.html' %}
+{% load static %}
+{% load crispy_forms_tags %}
+
+{% block body %}
+    <div class="container-fluid mb-5 pb-5">
+        <h1 class="text-center mb-3">Available Shifts on Market for {{request.user.role}}</h1>
+        <div class="card-deck">
+            {% for marketShift in available_shifts %}
+            <div class="modal fade" id="confirmTakeModal-{{ marketShift.id }}" tabindex="-1" aria-labelledby="confirmTakeLabel-{{ marketShift.id }}" aria-hidden="true">
+              <div class="modal-dialog">
+                <div class="modal-content">
+                  <div class="modal-header">
+                    <h5 class="modal-title" id="confirmTakeLabel-{{ marketShift.id }}">Confirm Action</h5>
+                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                  </div>
+                  <div class="modal-body">
+                    Are you sure you want to take this shift?
+                  </div>
+                  <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
+                    <a href="{% url 'take_shift' marketShift.id %}" class="btn btn-success">Confirm</a>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="modal fade" id="confirmDeleteModal-{{ marketShift.id }}" tabindex="-1" aria-labelledby="confirmDeleteLabel-{{ marketShift.id }}" aria-hidden="true">
+              <div class="modal-dialog">
+                <div class="modal-content">
+                  <div class="modal-header">
+                    <h5 class="modal-title" id="confirmDeleteLabel-{{ marketShift.id }}">Confirm Delete</h5>
+                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+                  </div>
+                  <div class="modal-body">
+                    Are you sure you want to delete this shift? This action cannot be undone. The shift is available until {{ marketShift.available_until }}.
+                  </div>
+                  <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
+                    <a href="{% url 'delete_shift' marketShift.id %}" class="btn btn-danger">Remove</a>
+                  </div>
+                </div>
+              </div>
+            </div>
+
+            <div id="market-card-{{marketShift.id}}" class="card" style=" display: inline-block; width: 23rem; ">
+                <h5 class="card-header {% if marketShift.urgency == 'Urgent' %}text-white bg-secondary mb-3{% endif %}">
+                    {{marketShift.shift.shift_day_of_week}}, {{ marketShift.shift.date }}
+                    <br>  {{ marketShift.shift.slot}}  {% if marketShift.urgency == 'Urgent' %}
+                    <i class="fa-solid fa-circle-exclamation"></i>{% endif %} </h5>
+                <div class="card-body">
+                    <p class="mb-2">Shift to take: {{ marketShift.shift }}</P>
+                    <p class="mb-2"><strong>Offered by:</strong> {{ marketShift.offerer }} on {{ marketShift.offered_date }} </p>
+<!--                    <p class="mb-2">Status: {{ marketShift.urgency }}</p>-->
+                    <p class="mb-2"><strong>Comment</strong>: {{ marketShift.comments }}</p>
+                </div>
+                <div class="card-footer">
+                    <p><strong>Available until:</strong>
+                    {% if marketShift.available_until %}
+                        {{ marketShift.available_until }}
+                    {% else %}
+                        Not specified
+                    {% endif %}
+                    </p>
+                    <div class="btn-group" role="group" aria-label="Shift actions">
+                    <button id="take-{{marketShift.id}}" href="#" class="btn btn-success disabled"  data-bs-toggle="modal"
+                            data-bs-target="#confirmTakeModal-{{ marketShift.id }}"> <i class="fa-solid fa-thumbs-up"></i> I take it!
+                          <span id="take-spinner-{{marketShift.id}}" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
+                    </button>
+                        {% if request.user == marketShift.offerer %}
+                    <button href="#" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#confirmDeleteModal-{{ marketShift.id }}">
+                            <i class="fa-solid fa-trash fa-1x"></i> Remove from Market</button>
+                    {% endif %}
+                </div>
+                </div>
+            </div>
+
+
+            {% empty %}
+                <p>No shifts available on the market at the moment.</p>
+            {% endfor %}
+
+        </div>
+    </div>
+{% endblock %}
+
+{%  block js %}
+<script>
+{% for marketShift in available_shifts %}
+$("#take-{{marketShift.id}}").ready(function () {
+    $.ajax({
+        type: "GET",
+        url: '{% url 'ajax.check_market' %}?market_id={{marketShift.id}}',
+        success: function(res) {
+            $("#take-spinner-{{marketShift.id}}").removeClass("spinner-border");
+            if (res.applicable){
+                $("#take-{{marketShift.id}}").removeClass("disabled");
+            } else {
+                $("#take-{{marketShift.id}}").removeClass("btn-success")
+                $("#take-{{marketShift.id}}").addClass("btn-danger")
+                $("#take-{{marketShift.id}}").addClass("btn-danger")
+                $("#take-{{marketShift.id}}").addClass("btn-danger")
+                $("#take-{{marketShift.id}}").text("Does not fit your schedule!")
+                $("#market-card-{{marketShift.id}}").addClass("text-secondary")
+            }
+        }
+    });
+});
+{%endfor%}
+</script>
+{% endblock %}
diff --git a/shifts/templates/shifts_upload.html b/shifts/templates/shifts_upload.html
index d9c8910eb45641769b86da7a618ddfacca1fe89f..b5f1917a628d683594d256ef5464a5db8a7b2c22 100644
--- a/shifts/templates/shifts_upload.html
+++ b/shifts/templates/shifts_upload.html
@@ -15,7 +15,7 @@
                 {% csrf_token %}
                 <div class="mb-3">
                     <label for="csv_file" class="form-label">CSV File: </label>
-                    <input class="form-control-file" type="file" name="csv_file" id="csv_file" required>
+                    <input class="form-control" type="file" name="csv_file" id="csv_file" required>
                 </div>
                 <div class="mb-3">
                     <label for="camp" class="form-label">Campaign: </label>
@@ -58,7 +58,7 @@
                       <small>Notify for available preview after successful upload (can be notified later from the admin panel)</small>
                     </label>
                 </div>
-            <button class="btn btn-primary"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span>Upload </button>
+            <button class="btn btn-primary"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span><i class="fa-solid fa-user-tie fa-1x"></i>&nbsp Upload </button>
             </form>
         </div>
     </div>
diff --git a/shifts/templates/team_desiderata.html b/shifts/templates/team_desiderata.html
index 787aae0e1f141f5e2df8d476313c99fa974c1751..489563b65db0ac9f26812dd65cbaf1b8deaea7a0 100644
--- a/shifts/templates/team_desiderata.html
+++ b/shifts/templates/team_desiderata.html
@@ -241,10 +241,13 @@
                                     <table class="table table-striped" id="table_shiftswap" data-source="{% url 'ajax.get_team_shiftswaps' %}">
                                         <thead>
                                             <tr>
-                                                <th scope="col">#</th>
-                                                <th scope="col">When</th>
-                                                <th scope="col">Who</th>
-                                                <th scope="col">Swap</th>
+                                                <th scope="col">Id</th>
+                                                <th scope="col">Type</th>
+                                                <th scope="col">When requested</th>
+                                                <th scope="col">Who requested</th>
+                                                <th scope="col">When finalised</th>
+                                                <th scope="col">Who finalised</th>
+                                                <th scope="col">Swapped shifts</th>
                                             </tr>
                                         </thead>
                                         <tbody>
@@ -256,6 +259,9 @@
                                                 <th></th>
                                                 <th></th>
                                                 <th></th>
+                                                <th></th>
+                                                <th></th>
+                                                <th></th>
                                             </tr>
                                         </tfoot>
                                     </table>
@@ -316,7 +322,7 @@
                                     </div>
                                     <div class="mb-3">
                                         <div class="col-md-3 col-sm-3 col-xs-12 col-md-offset-3" style="margin-bottom:10px;">
-                                             <button class="btn btn-warning"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span>Update</button>
+                                             <button class="btn btn-warning"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span><i class="fa-solid fa-user-tie fa-1x"></i>&nbspUpdate</button>
                                         </div>
                                     </div>
                                 </form>
@@ -350,7 +356,7 @@
                                     </div>
                                     <div class="mb-3">
                                         <div class="col-md-3 col-sm-3 col-xs-12 col-md-offset-3" style="margin-bottom:10px;">
-                                             <button class="btn btn-danger"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span>Merge revisions</button>
+                                             <button class="btn btn-danger"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span><i class="fa-solid fa-user-tie fa-1x"></i>&nbspMerge revisions</button>
                                         </div>
                                     </div>
                                  </form>
@@ -378,7 +384,7 @@
                                     </div>
                                     <div class="mb-3">
                                         <div class="col-md-3 col-sm-3 col-xs-12 col-md-offset-3" style="margin-bottom:10px;">
-                                             <button class="btn btn-danger"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span>Remove</button>
+                                             <button class="btn btn-danger"> <span class="glyphicon glyphicon-upload" style="margin-right:5px;"></span><i class="fa-solid fa-user-tie fa-1x"></i>&nbspRemove</button>
                                         </div>
                                     </div>
                                 </form>
@@ -415,7 +421,7 @@
 <script type="text/javascript" src="{% static 'js/desiderata_space.min.js' %}"></script>
 <script type="text/javascript" src="{% static 'js/team_stats.min.js' %}"></script>
 <script type="text/javascript" src="{% static 'js/team_shiftswaps.min.js' %}"></script>
-<script type="text/javascript" src="{% static 'js/shift_control.js' %}"></script>
+<script type="text/javascript" src="{% static 'js/shift_control.min.js' %}"></script>
 <script type="text/javascript" src="{% static 'js/desiderata_gantt.min.js' %}"></script>
 
 
diff --git a/shifts/templates/user.html b/shifts/templates/user.html
index 38588a5ca2388ff6b4b9303d6cd09bb92584af81..6be7fa5f0e5da62b30e61488c5f990441a065a1e 100644
--- a/shifts/templates/user.html
+++ b/shifts/templates/user.html
@@ -58,7 +58,7 @@
             </ul>
             <div class="tab-content" id="user_tabs_content">
                 <div class="tab-pane fade show active" id="planning-tab-pane" role="tabpanel" aria-labelledby="planning-tab" tabindex=""0>
-                        {% include 'calendar.html' with event_source=the_url %}
+                        {% include 'calendar.html' with event_source=the_url market_event_source=the_market_url user_view=True%}
                 </div>
                 <!-- Tab displaying the time reporting breakdown -->
                 <div class="tab-pane fade" id="time_report-tab-pane" role="tabpanel" aria-labelledby="time_report-tab" tabindex="1">
@@ -303,7 +303,7 @@
                                   <div class="accordion-item">
                                     <h2 class="accordion-header" id="headingOne">
                                       <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{oneSE.id}}" aria-expanded="true" aria-controls="collapse{{oneSE.id}}">
-                                        {{oneSE.requestor}} <br> <small>&nbsp;requested on {{oneSE.requested_date}}</small>&nbsp;
+                                        <span class="badge text-bg-light">{{oneSE.type}}</span>&nbsp;&nbsp;{{oneSE.requestor}} <br> <small>&nbsp;on {{oneSE.requested_date}}</small>&nbsp;
                                           <span class="badge text-bg-{%if oneSE.implemented%}success">IMPLEMENTED{%else%}primary">NOT IMPLEMENTED{%endif%}</span>&nbsp;
                                           <span class="badge text-bg-{%if oneSE.applicable%}success">APPLICABLE{%else%}danger">NOT APPLICABLE{%endif%}</span>
                                       </button>
@@ -319,14 +319,14 @@
                                                 {%endfor%}
                                         </dd>
                                         {%if oneSE.tentative%}
-                                            <a class="btn btn-outline-success btn-light" href={% url 'shifter:shift-exchange-close' oneSE.id %}>Close request and await for approval
+                                            <a class="btn btn-outline-success btn-light" href="{% url 'shifter:shift-exchange-close' oneSE.id %}">Close request and await for approval
                                             <span class="fa-stack">
                                             <i class="fa-solid fa-circle fa-stack-2x" style="color:#198754"></i>
                                                 <i class="fa-solid fa-bolt fa-stack-1x fa-inverse"></i>
                                             </span> </a>
                                         {%endif%}
                                         {%if not oneSE.implemented%}
-                                           <a class="btn btn-outline-danger btn-light" href={% url 'shifter:shift-exchange-cancel' oneSE.id %}>Cancel this request (cannot be undone!)
+                                           <a class="btn btn-outline-danger btn-light" href="{% url 'shifter:shift-exchange-cancel' oneSE.id %}">Cancel this request (cannot be undone!)
                                             <span class="fa-stack">
                                             <i class="fa-solid fa-circle fa-stack-2x" ></i>
                                                 <i class="fa-solid fa-trash fa-stack-1x fa-inverse"></i>
@@ -336,12 +336,13 @@
                                     <dl class="row">
                                         <dd class="col-sm-1">
                                             {%if oneSE.implemented%}<span class="fa-stack">
+                                            <a href="{% url 'shifter:shift-exchange-view' oneSE.id %}">
                                             <i class="fa-solid fa-circle fa-stack-2x" style="color:#198754">{{oneSE.approver.first_name}}</i>
-                                            <i class="fa-solid fa-thumbs-up fa-stack-1x fa-inverse"></i>
+                                                <i class="fa-solid fa-thumbs-up fa-stack-1x fa-inverse"></i></a>
                                             </span>{%endif%}
                                             {%if not oneSE.implemented and oneSE.applicable and not oneSE.tentative%}
                                             {%if oneSE.approver == member%}
-                                            <a class="btn btn-outline-success btn-light" href={% url 'shifter:shift-exchange' oneSE.id %}>Approve
+                                            <a class="btn btn-outline-success btn-light" href="{% url 'shifter:shift-exchange' oneSE.id %}">Approve
                                             <span class="fa-stack">
                                             <i class="fa-solid fa-circle fa-stack-2x" style="color:#198754"></i>
                                             <i class="fa-solid fa-thumbs-up fa-stack-1x fa-inverse"></i>
diff --git a/shifts/urls/ajax.py b/shifts/urls/ajax.py
index 7799f58bc78bc4bb0bf9e0e1fad5ce6e5771b501..d8b91110c7be04ba130c5a6127147187a02263db 100644
--- a/shifts/urls/ajax.py
+++ b/shifts/urls/ajax.py
@@ -21,5 +21,7 @@ urlpatterns = [
     path("get_team_shift_inconsistencies", ajax_views.get_team_shift_inconsistencies, name="ajax.get_team_shift_inconsistencies"),
     path("get_stats", ajax_views.get_shift_stats, name="ajax.get_stats"),
     path("get_team_shiftswaps", ajax_views.get_team_shiftswaps, name="ajax.get_team_shiftswaps"),
+    path("get_market_events", ajax_views.get_market_events, name="ajax.get_market_events"),
+    path("check_market", ajax_views.get_market_validity, name="ajax.check_market"),
     path("search", ajax_views.search, name="ajax.search"),
 ]
diff --git a/shifts/urls/main.py b/shifts/urls/main.py
index 088968d5ddcbf7a980340fa269a7c7a66dad4e9b..df96d273fc8dfcef3bcc26f3a3dc864841d1d9aa 100644
--- a/shifts/urls/main.py
+++ b/shifts/urls/main.py
@@ -23,10 +23,17 @@ urlpatterns = [
     path("scheduled-work-time", views.scheduled_work_time, name="scheduled_work_time"),
     path("shifts", views.shifts, name="shifts"),
     path("shift/<int:sid>", views.shift_edit, name="shift-edit"),
+    path("shift/<int:sid>/view", views.shift_view, name="shift-view"),
     path("shift/<int:sid>/edit", views.shift_edit_post, name="shift-edit-post"),
+    path("shift-market/", views.market_shifts, name="shifts_market"),
+    path("shift-market/<int:shift_id>/view/", views.market_shift_view, name="market_shift_view"),
+    path("shift-market/<int:shift_id>/take/", views.market_shift_take, name="take_shift"),
+    path("shift-market/<int:shift_id>/delete/", views.market_shift_delete, name="delete_shift"),
+    path("shift/<int:shift_id>/add-to-market/", views.market_shift_add, name="add_shift_to_market"),
     path("shift/<int:sid>/exchange", views.shift_single_exchange_post, name="shift-single-exchange-post"),
     path("shift-exchange", views.shiftExchangeRequestCreateOrUpdate, name="shift-exchange-request"),
     path("shift-exchange/<int:ex_id>", views.shiftExchangeRequestCreateOrUpdate, name="shift-exchange-request"),
+    path("shift-exchange/<int:ex_id>/view", views.shiftExchangeView, name="shift-exchange-view"),
     path("shift-exchange/<int:ex_id>/close", views.shiftExchangeRequestClose, name="shift-exchange-close"),
     path("shift-exchange/<int:ex_id>/cancel", views.shiftExchangeRequestCancel, name="shift-exchange-cancel"),
     path("shift-exchange/<int:ex_id>/finalize", views.shiftExchangePerform, name="shift-exchange"),
diff --git a/shifts/views/ajax.py b/shifts/views/ajax.py
index 28523ec53c46d41e4c6f24fabbbc13dc7f794f9e..72ff2daf77d5d45d8e403c961021f855ee088d5b 100644
--- a/shifts/views/ajax.py
+++ b/shifts/views/ajax.py
@@ -3,6 +3,8 @@ from django.http import HttpRequest
 from django.db.models import Count, Q
 from django.contrib.auth.decorators import login_required
 from django.views.decorators.http import require_safe
+
+from shifts.exchanges import is_valid_for_hours_constraints_from_market
 from shifts.io import write_csv
 from shifts.models import *
 from studies.models import *
@@ -387,6 +389,26 @@ def get_shift_breakdown(request: HttpRequest) -> HttpResponse:
     )
 
 
+@login_required
+def get_market_events(request: HttpRequest) -> HttpResponse:
+    shifts_on_market = ShiftForMarket.objects.filter(is_available=True, shift__member__role=request.user.role)
+    calendar_market_events = [d.get_market_shift_as_json_event() for d in shifts_on_market]
+    return HttpResponse(json.dumps(calendar_market_events), content_type="application/json")
+
+
+@login_required
+def get_market_validity(request: HttpRequest) -> HttpResponse:
+    revision = _get_revision(request)
+    try:
+        sfm = ShiftForMarket.objects.get(id=request.GET.get("market_id"))
+    except:
+        return HttpResponse(json.dumps({"applicable": False, "info": "Wrong ID"}), content_type="application/json")
+
+    is_applicable = is_valid_for_hours_constraints_from_market(sfm, revision, request.user)
+    # print(is_applicable)
+    return HttpResponse(json.dumps({"applicable": is_applicable[0]}), content_type="application/json")
+
+
 @login_required
 def get_shifts_for_exchange(request: HttpRequest) -> HttpResponse:
     member = _get_member(request)
@@ -404,7 +426,7 @@ def get_shifts_for_exchange(request: HttpRequest) -> HttpResponse:
 def _get_inconsistencies_per_member(member, revision):
     # TODO fix it with proper js file to build it out of JSON
     # TODO once with json, return count of inconsistencies to enable badge
-    ss = Shift.objects.filter(revision=revision).filter(member=member)
+    ss = Shift.objects.filter(revision=revision, is_active=True).filter(member=member)
     dailyViolations = find_daily_rest_time_violation(scheduled_shifts=ss)
     weeklyViolations = find_weekly_rest_time_violation(scheduled_shifts=ss)
     toReturnHTML = ""
@@ -531,18 +553,32 @@ def get_team_shiftswaps(request: HttpRequest) -> HttpResponse:
     start = datetime.datetime.fromisoformat(request.GET.get("start")).date()
     end = datetime.datetime.fromisoformat(request.GET.get("end")).date()
     team = request.user.team
-    # TODO apply date filter on CONCERNED shifts (not requesting/approval times)
-    sExs = ShiftExchange.objects.filter(requestor__team=team, implemented=True)
+    sExs = ShiftExchange.objects.filter(implemented=True).filter(
+        (Q(requestor__team=team) | Q(shifts__shift_for_exchange__member__team=team) | Q(shifts__shift__member__team=team))
+        & (
+            Q(shifts__shift__date__gte=start)
+            & Q(shifts__shift__date__lte=end)
+            & Q(shifts__shift_for_exchange__date__gte=start)
+            & Q(shifts__shift_for_exchange__date__lte=end)
+        )
+    )
+    ids = []
     data = []
     for onesEx in sExs:
+        if onesEx.id in ids:
+            continue  # poor's man remove duplicates
+        ids.append(onesEx.id)
         swaps = ""
         for oneSwap in onesEx.shifts.all():
             swaps += str(oneSwap) + "<br>"
         data.append(
             [
-                onesEx.id,
-                "Requested: " + onesEx.requested_date + " <br>Approved:  " + onesEx.approved_date,
-                onesEx.requestor.name + " <br> " + onesEx.approver.name,
+                '<a class="link" href="' + reverse("shifter:shift-exchange-view", kwargs={"ex_id": onesEx.id}) + '">' + str(onesEx.id) + "</a>",
+                onesEx.type,
+                onesEx.requested_date,
+                onesEx.requestor.name,
+                onesEx.approved_date,
+                onesEx.approver.name,
                 swaps,
             ]
         )
diff --git a/shifts/views/desiderata.py b/shifts/views/desiderata.py
index c58819ebb58de221600f6e77fe6fb3a5bf6c5cac..6e442c444aa1c1abcda02da1d892edb5d34955f0 100644
--- a/shifts/views/desiderata.py
+++ b/shifts/views/desiderata.py
@@ -225,6 +225,7 @@ def gantt_data(request):
         toFix["y"] = ordered_names.index(d.member.name)
         toFix["start"] = int((d.start.timestamp()) + 24 * 60 * 60) * 1000
         toFix["end"] = int(d.stop.timestamp() * 1000)
+        toFix["role"] = str(d.member.role)
         all_indexed_events.append(toFix)
 
     series["data"] = all_indexed_events
diff --git a/shifts/views/main.py b/shifts/views/main.py
index 3051da198ff80e041d068e1a0a2e2db2b9eba0ca..342df8483cdfeedda4e9f9d5aa42d8332cb2b36b 100644
--- a/shifts/views/main.py
+++ b/shifts/views/main.py
@@ -23,7 +23,12 @@ from shifts.activeshift import prepare_active_crew, prepare_for_JSON
 from shifts.contexts import prepare_default_context, prepare_user_context
 from shifter.settings import DEFAULT_SHIFT_SLOT
 from shifts.workinghours import find_working_hours
-from shifts.exchanges import is_valid_for_hours_constraints, perform_exchange_and_save_backup, perform_simplified_exchange_and_save_backup
+from shifts.exchanges import (
+    is_valid_for_hours_constraints,
+    perform_exchange_and_save_backup,
+    perform_simplified_exchange_and_save_backup,
+    is_valid_for_hours_constraints_from_market,
+)
 from shifts.io import importShiftsFromCSV
 
 from django.utils import timezone
@@ -174,6 +179,7 @@ def user(request, u=None, rid=None):
     context["hide_extra_role_selection"] = True
     context["show_companion"] = True
     context["the_url"] = reverse("ajax.get_user_events")
+    context["the_market_url"] = reverse("ajax.get_market_events")
     context["unread_notifications"] = member.notifications.unread()
     if rid is not None:
         requested_revision = get_object_or_404(Revision, number=rid)
@@ -185,7 +191,10 @@ def user(request, u=None, rid=None):
         messages.warning(request, "On top of the current schedule, you're seeing revision '{}'".format(requested_revision))
         context["requested_future_rev_id"] = rid
 
-    shiftExchanges = ShiftExchange.objects.filter(Q(requestor=member) | Q(shifts__shift_for_exchange__member__exact=member)).order_by("-requested")
+    shiftExchanges = ShiftExchange.objects.filter(
+        Q(requestor=member) | Q(shifts__shift_for_exchange__member__exact=member) | Q(shifts__shift__member__exact=member)
+    ).order_by("-requested")
+
     shiftExchangesLast = ShiftExchange.objects.filter(requestor=member, tentative=True, applicable=True).order_by("-requested").first()
     # FIXME this one is to clear the 'over select' from the query above that
     shiftExchangesUnique = []
@@ -258,6 +267,13 @@ def shiftExchangeRequestCancel(request, ex_id=None):
     return HttpResponseRedirect(reverse("shifter:user"))
 
 
+@login_required
+def shiftExchangeView(request, ex_id=None):
+    sEx = ShiftExchange.objects.get(id=ex_id)
+    context = {"sEx": sEx}
+    return render(request, "shiftexchange_edit.html", prepare_default_context(request, context))
+
+
 @require_http_methods(["POST"])
 @csrf_protect
 @login_required
@@ -597,14 +613,27 @@ def shifts_update_status_post(request):
 @require_safe
 @login_required
 def shift_edit(request, sid=None):
+    s = Shift.objects.get(id=sid)
+    sfm = ShiftForMarket.objects.filter(shift=s).first()
     data = {
-        "shift": Shift.objects.get(id=sid),
+        "shift": s,
+        "on_market": sfm,
         "shiftRoles": ShiftRole.objects.all(),
         "replacement": Member.objects.filter(team=request.user.team, is_active=True).order_by("role"),
+        "edit": True,
     }
     return render(request, "shift_edit.html", prepare_default_context(request, data))
 
 
+@require_safe
+@login_required
+def shift_view(request, sid=None):
+    s = Shift.objects.get(id=sid)
+    sfm = ShiftForMarket.objects.filter(shift=s).first()
+    data = {"shift": s, "on_market": sfm}
+    return render(request, "shift_edit.html", prepare_default_context(request, data))
+
+
 @require_http_methods(["POST"])
 @csrf_protect
 @login_required
@@ -637,6 +666,133 @@ def shift_edit_post(request, sid=None):
     return HttpResponseRedirect(reverse("shifter:index"))
 
 
+@require_http_methods(["POST"])
+@csrf_protect
+@login_required
+def market_shift_add(request, shift_id):
+    shift = get_object_or_404(Shift, id=shift_id)
+    member = request.user
+
+    if shift.date < timezone.now().date():
+        messages.error(request, "You cannot add a shift to the market with a date in the past.")
+        return redirect("shifter:user")
+
+    if ShiftForMarket.objects.filter(shift=shift, is_available=True).exists():
+        messages.error(request, "This shift is already on the market.")
+        return redirect("shifter:user")
+
+    market_comment = request.POST.get("marketComment", "")
+    available_until = request.POST.get("availableUntil", None)
+    urgency = request.POST.get("urgency", "Normal")
+
+    if available_until:
+        available_until_date = timezone.datetime.strptime(available_until, "%Y-%m-%d").date()
+
+        if available_until_date < timezone.now().date():
+            messages.error(request, "The 'available until' date cannot be in the past.")
+            return redirect("shifter:user")
+    else:
+        available_until_date = None
+
+    sfm = ShiftForMarket.objects.create(
+        shift=shift,
+        offerer=member,
+        offered_date=timezone.now(),
+        comments=market_comment,
+        available_until=available_until_date,
+        urgency=urgency,
+        is_available=True,
+        is_taken=False,
+    )
+    notificationService.notify(sfm)
+    messages.success(request, "Shift successfully added to the market.")
+    return redirect("shifter:shifts_market")
+
+
+@login_required
+def market_shifts(request):
+    user_role = request.user.role
+
+    available_shifts = ShiftForMarket.objects.filter(is_available=True, shift__member__role=user_role).order_by("shift__date")
+    for a in available_shifts:
+        a.check_if_available(timezone.now().date())
+    available_shifts = ShiftForMarket.objects.filter(is_available=True, shift__member__role=user_role).order_by("shift__date")
+
+    shift_count = available_shifts.count()
+
+    user_shifts = Shift.objects.filter(member=request.user, date__gt=timezone.now().date()).order_by("date")
+
+    context = {
+        "available_shifts": available_shifts,
+        "user_shifts": user_shifts,
+        "shift_count": shift_count,
+    }
+    return render(request, "shifts_market.html", context)
+
+
+@login_required
+def market_shift_view(request, shift_id):
+    context = {
+        "available_shifts": [ShiftForMarket.objects.get(id=shift_id)],
+    }
+    return render(request, "shifts_market.html", context)
+
+
+@login_required
+def market_shift_take(request, shift_id):
+    try:
+        shift_market = ShiftForMarket.objects.get(id=shift_id, is_available=True)
+    except ShiftForMarket.DoesNotExist:
+        messages.error(request, "The shift you tried to take is no longer available.")
+        return redirect("shifts_market")
+
+    is_applicable = is_valid_for_hours_constraints_from_market(shift_market, shift_market.shift.revision, request.user)
+    if not is_applicable[0]:
+        messages.error(request, "Your schedule does not fit to accept this shift! Contact your rota maker to find out " "possible solutions!")
+        return redirect("shifts_market")
+
+    # FIXME think if that should go inside the 'simplified exchange'
+    # for now, the 'my shift' on the same day are invalidated and put with comment
+    shifts = Shift.objects.filter(date=shift_market.shift.date, member=request.user, revision=Revision.objects.filter(valid=True).order_by("-number").first())
+    for shift in shifts:
+        shift.is_active = False
+        shift.pre_comment = "Removed with the market shift: {}".format(shift_market)
+        shift.save()
+
+    sExDone = perform_simplified_exchange_and_save_backup(
+        shift_market.shift,
+        request.user,
+        requestor=shift_market.offerer,
+        approver=request.user,
+        revisionBackup=Revision.objects.filter(name__startswith="BACKUP").first(),
+        exType="Market",
+    )
+    notificationService.notify(sExDone)
+    shift_market.mark_as_taken()
+
+    messages.success(request, "Requested shift exchange (update) is now successfully implemented.")
+    messages.success(request, "You have successfully taken the shift.")
+    return redirect("shifts_market")
+
+
+@login_required
+def market_shift_delete(request, shift_id):
+    shift_market = get_object_or_404(ShiftForMarket, id=shift_id)
+
+    if request.user != shift_market.offerer:
+        messages.error(request, "You cannot delete this shift because you did not add it.")
+        return redirect("shifts_market")
+
+    shift_market.delete()
+    messages.success(request, "Shift has been deleted from the market.")
+    return redirect("shifts_market")
+
+
+@login_required
+def user_page(request):
+    return redirect("user")
+
+
 @require_http_methods(["POST"])
 @csrf_protect
 @login_required
@@ -649,7 +805,7 @@ def shift_single_exchange_post(request, sid=None):
         return HttpResponseRedirect(reverse("shifter:index"))
 
     sExDone = perform_simplified_exchange_and_save_backup(
-        s, m, approver=request.user, revisionBackup=Revision.objects.filter(name__startswith="BACKUP").first()
+        s, m, requestor=request.user, approver=request.user, revisionBackup=Revision.objects.filter(name__startswith="BACKUP").first()
     )
     messages.success(request, "Requested shift exchange (update) is now successfully implemented.")
     notificationService.notify(sExDone)
diff --git a/studies/models.py b/studies/models.py
index 02c95f51923a09482e18dec31bb386f0e88e1dc4..7324a748d2c406e301c8506be8432fa74a8da49b 100644
--- a/studies/models.py
+++ b/studies/models.py
@@ -231,6 +231,7 @@ class StudyRequest(models.Model):
             "start": self.study_start,
             "end": self.study_end,
             "color": "#F5D959",
+            "url": reverse("studies:single_study_view", kwargs={"sid": self.id}),
             "textColor": "#FF3333" if self.priority else "#676767",
             "borderColor": "#FF3333" if self.priority else "#BBBBBB",
         }
diff --git a/studies/templates/request.html b/studies/templates/request.html
index db0e994a6dced100c7fe0fd482b7bd1387420672..69c773be20f9cb22136a38d8e00363fafb0a0861 100644
--- a/studies/templates/request.html
+++ b/studies/templates/request.html
@@ -63,6 +63,28 @@
                         </div>
                     </div>
                 </div>
+                {%if request.user.is_staff %}
+                <!-- Import Study Request List -->
+                <div class="accordion-item">
+                    <h2 class="accordion-header" id="import_request_header">
+                        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#accordion_import_request" aria-expanded="false" aria-controls="accordion_import_request">
+                            Import Study Request
+                        </button>
+                    </h2>
+                    <div id="accordion_import_request" class="accordion-collapse collapse" aria-labelledby="import_request_header" data-bs-parent="#assets_accordion">
+                        <div class="accordion-body">
+                            <form action="{% url 'studies:import_requests' %}" method="POST" enctype="multipart/form-data">
+                                {% csrf_token %}
+                                <div class="mb-3">
+                                    <label for="csv_file" class="form-label">Upload CSV File</label>
+                                    <input class="form-control" type="file" id="csv_file" name="csv_file" accept=".csv" required>
+                                </div>
+                                <input class="btn btn-primary" type="submit" value="Import">
+                            </form>
+                        </div>
+                    </div>
+                </div>
+                {%endif%}
             </div>
         </div>
     </div>
diff --git a/studies/urls/main.py b/studies/urls/main.py
index 97f8747128c531036fc9817259d032015477d956..b6a2ff7c871f5b32009c6f6d990677b6d9dcba73 100644
--- a/studies/urls/main.py
+++ b/studies/urls/main.py
@@ -8,4 +8,5 @@ urlpatterns = [
     path("", login_required(views.StudyView.as_view()), name="study_request"),
     path("<int:sid>", login_required(views.SingleStudyView.as_view()), name="single_study_view"),
     path("close", views.studies_close, name="studies-close"),
+    path("import-requests/", views.import_requests, name="import_requests"),
 ]
diff --git a/studies/views/main.py b/studies/views/main.py
index fc0f45872989341c2c35ad0ec3a5e85d4451daab..a1f9cebafe7eaadefc1d7eca4c5c9c1be71bc6f9 100644
--- a/studies/views/main.py
+++ b/studies/views/main.py
@@ -5,6 +5,9 @@ from studies.forms import StudyRequestForm, StudyRequestFormClosing
 import django.contrib.messages as messages
 from django.views import View
 from django.utils import timezone
+import csv
+from members.models import Member
+from datetime import datetime
 
 from shifter.notifications import notificationService
 
@@ -78,3 +81,63 @@ def studies_close(request):
         message = "Booking form is not valid, please correct."
         messages.success(request, message)
     return redirect("studies:study_request")
+
+
+def import_requests(request):
+    def get_state_key(state_description):
+        state_mapping = {"Planned": "P", "Requested": "R", "Booked": "B", "Canceled": "C", "Done": "D"}
+        return state_mapping.get(state_description, None)
+
+    def parse_date(date_str):
+        return datetime.strptime(date_str, DATE_FORMAT_FULL)
+
+    if request.method == "POST":
+        csv_file = request.FILES.get("csv_file")
+        if csv_file:
+            data = csv_file.read().decode("utf-8").splitlines()
+            reader = csv.DictReader(data)
+
+            for row in reader:
+                state_key = get_state_key(row["State"])
+                if not state_key:
+                    messages.error(request, f"Invalid state value: {row['State']} in CSV. Row skipped.")
+                    continue
+
+                booked_by_user = Member.objects.get(first_name=row["# name + bookedby"])
+                if not booked_by_user:
+                    messages.error(request, f"User {row['# name + bookedby']} not found. Skipping.")
+                    continue
+
+                slot_start = parse_date(row["slot start"])
+                slot_end = parse_date(row["slot end"])
+
+                if not slot_start or not slot_end:
+                    messages.error(request, f"Invalid date format for start or end time in row: {row}")
+                    continue
+
+                collaborators_names = row["Many users"].split(":")
+                collaborators = []
+
+                for name in collaborators_names:
+                    collaborator = Member.objects.get(first_name=name.strip())
+                    if collaborator:
+                        collaborators.append(collaborator)
+
+                study_request = StudyRequest(
+                    title=row["Title"],
+                    description=row["Description"],
+                    state=state_key,
+                    booked_by=booked_by_user,
+                    member=booked_by_user,
+                    slot_start=slot_start,
+                    slot_end=slot_end,
+                    booking_created=timezone.now(),
+                )
+                study_request.save()
+                if collaborators:
+                    study_request.collaborators.set(collaborators)
+
+            messages.success(request, "CSV file processed successfully.")
+            return redirect("studies:study_request")
+
+    return render(request, "your_template.html")
diff --git a/tests/test_shift_exchange.py b/tests/test_shift_exchange.py
index a46359440b25fb891ed51545759eae0054b59c49..85fa1ece63bf063d02dce8df4618ce2ae8303c47 100644
--- a/tests/test_shift_exchange.py
+++ b/tests/test_shift_exchange.py
@@ -75,7 +75,7 @@ class ExchangeShifts(TestCase):
 
     def test_simple_exchange_just_member(self):
         self.assertEqual(self.m1, self.shift_m1_am.member)
-        perform_simplified_exchange_and_save_backup(self.shift_m1_am, self.m2, self.m2, revisionBackup=self.revisionBackup)
+        perform_simplified_exchange_and_save_backup(self.shift_m1_am, self.m2, self.m2, self.m2, revisionBackup=self.revisionBackup)
         aa = Shift.objects.filter(member=self.m2, date=self.shift_m1_am.date, slot=self.shift_m1_am.slot, revision=self.shift_m1_am.revision)
         self.assertEqual(1, len(aa))