Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,12 @@ const emailAddress = ref("");
const clearInput = ref(false);
const emailDomain = "fhstp.ac.at";


const updateMail = (value: string) => {
emailAddress.value = value;
};

const editButtonLabel = computed(() => {
return isEditing.value ? t('generic.done') : t('generic.edit');
return isEditing.value ? t("generic.done") : t("generic.edit");
});

const editButtonIcon = computed(() => {
Expand Down Expand Up @@ -219,17 +218,27 @@ watch(
studentToRemove?.lastName
: ''
"
:image-src="studentToRemove?.src || getPlaceholderImage(studentToRemove?.firstName, studentToRemove?.lastName) || ''"
:image-src="
studentToRemove?.src ||
getPlaceholderImage(
studentToRemove?.firstName,
studentToRemove?.lastName
) ||
''
"
:main-text="
t('supervisorStudentList.removeStudent.mainText', {
firstName: studentToRemove?.firstName,
lastName: studentToRemove?.lastName,
})
"
:confirm-text="t('supervisorStudentList.removeStudent.confirmText')"
:checkbox-label="t('supervisorStudentList.checkboxLabel')"
:confirm-text="
t('settings.supervisorStudentList.removeStudent.confirmText')
"
:checkbox-label="t('settings.supervisorStudentList.checkboxLabel')"
setting-key="showRemoveStudentModal"
:title="t('supervisorStudentList.removeStudent.title')"
:sub-text="t('supervisorStudentList.removeStudent.subText')"
icon="trash"
@confirm="confirmRemoveStudent"
/>
Expand All @@ -246,16 +255,22 @@ watch(
modal_user.last_name
: ''
"
:image-src="modal_user?.profile_image || getPlaceholderImage(modal_user?.first_name, modal_user?.last_name) || ''"
:image-src="
modal_user?.profile_image ||
getPlaceholderImage(modal_user?.first_name, modal_user?.last_name) ||
''
"
:main-text="
t('supervisorStudentList.addExistingStudent.mainText', {
firstName: modal_user?.first_name,
lastName: modal_user?.last_name,
})
"
:show-checkbox="true"
:checkbox-label="t('supervisorStudentList.checkboxLabel')"
:confirm-text="t('supervisorStudentList.addExistingStudent.confirmText')"
:checkbox-label="t('settings.supervisorStudentList.checkboxLabel')"
:confirm-text="
t('settings.supervisorStudentList.addExistingStudent.confirmText')
"
icon="user-group"
setting-key="showAddStudentModal"
:sub-text="t('supervisorStudentList.addExistingStudent.subText')"
Expand All @@ -273,14 +288,18 @@ watch(
})
"
:show-checkbox="true"
:checkbox-label="t('supervisorStudentList.checkboxLabel')"
confirm-text=""
:checkbox-label="t('settings.supervisorStudentList.checkboxLabel')"
:confirm-text="
t('settings.supervisorStudentList.addNotExistingStudent.confirmText')
"
icon="user-group"
image-alt="Logo"
image-src="../images/Superwise_Logo.svg"
setting-key="showAddStudentModal"
:sub-text="t('supervisorStudentList.addExistingStudent.subText')"
:title="t('supervisorStudentList.addNewStudent.title')"
:sub-text="
t('settings.supervisorStudentList.addNotExistingStudent.subText')
"
:title="t('settings.supervisorStudentList.addNewStudent.title')"
@confirm="addStudent"
/>
</div>
Expand Down
199 changes: 110 additions & 89 deletions Frontend/components/SwipeContainer/SwipeContainer.vue
Original file line number Diff line number Diff line change
@@ -1,113 +1,134 @@
<script setup lang="ts">
import { usePointerSwipe } from '@vueuse/core'
import { computed, shallowRef } from 'vue'
import { usePointerSwipe } from "@vueuse/core";
import { computed, shallowRef, ref } from "vue";
import { faCheck, faBan } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";

interface Props {
swipeThreshold?: number
swipeThreshold?: number;
swipeLeftText?: string;
swipeRightText?: string;
}

const props = withDefaults(defineProps<Props>(), {
swipeThreshold: 40,
})
swipeThreshold: 40,
swipeLeftText: "Request",
swipeRightText: "Reject",
});

const emit = defineEmits(['swipeRight', 'swipeLeft'])
const emit = defineEmits(["swipeRight", "swipeLeft"]);

defineExpose({
reset,
})
reset,
});

const target = shallowRef<HTMLElement | null>(null)
const container = shallowRef<HTMLElement | null>(null)
const target = shallowRef<HTMLElement | null>(null);
const container = shallowRef<HTMLElement | null>(null);

const containerWidth = computed(() => container.value?.offsetWidth || 0)
const containerWidth = computed(() => container.value?.offsetWidth || 0);

const left = shallowRef('0')
const opacity = shallowRef(1)
const left = shallowRef("0");
const opacity = shallowRef(1);

const cardIsAtStartPosition = ref(false)
const cardIsAtStartPosition = ref(false);

function reset() {
left.value = '0'
opacity.value = 1
cardIsAtStartPosition.value = true
left.value = "0";
opacity.value = 1;
cardIsAtStartPosition.value = true;
}

const { distanceX, isSwiping } = usePointerSwipe(target, {
disableTextSelect: true,
threshold: props.swipeThreshold,
onSwipe() {
cardIsAtStartPosition.value = false
if (containerWidth.value) {
if (distanceX.value < 0) {
// Swipe right direction (negative distanceX)
const distance = Math.abs(distanceX.value)
left.value = `${distance}px`
opacity.value = 1.25 - distance / containerWidth.value
}
else if (distanceX.value > 0) {
// Swipe left direction (positive distanceX)
const distance = distanceX.value
left.value = `-${distance}px`
opacity.value = 1.25 - distance / containerWidth.value
}
else {
left.value = '0'
opacity.value = 1
}
}
},
onSwipeEnd() {
if (containerWidth.value) {
// Calculate the ratio relative to container width
const ratio = Math.abs(distanceX.value) / containerWidth.value

if (distanceX.value < 0 && ratio >= 0.5) {
// Swipe right direction threshold reached
left.value = '100%'
opacity.value = 0
emit('swipeRight')
}
else if (distanceX.value > 0 && ratio >= 0.5) {
// Swipe left direction threshold reached
left.value = '-100%'
opacity.value = 0
emit('swipeLeft')
}
else {
// Reset if threshold not reached
cardIsAtStartPosition.value = true
left.value = '0'
opacity.value = 1
}
}
},
})

const backgroundColorClasses = computed(() => {
return {
'bg-base-100': cardIsAtStartPosition.value,
'bg-success': distanceX.value < -props.swipeThreshold/10,
'bg-error': distanceX.value > props.swipeThreshold/10,
disableTextSelect: true,
threshold: props.swipeThreshold,
onSwipe() {
cardIsAtStartPosition.value = false;
if (containerWidth.value) {
if (distanceX.value < 0) {
// Swipe right direction (negative distanceX)
const distance = Math.abs(distanceX.value);
left.value = `${distance}px`;
opacity.value = 1.25 - distance / containerWidth.value;
} else if (distanceX.value > 0) {
// Swipe left direction (positive distanceX)
const distance = distanceX.value;
left.value = `-${distance}px`;
opacity.value = 1.25 - distance / containerWidth.value;
} else {
left.value = "0";
opacity.value = 1;
}
}
})
},
onSwipeEnd() {
if (containerWidth.value) {
// Calculate the ratio relative to container width
const ratio = Math.abs(distanceX.value) / containerWidth.value;

if (distanceX.value < 0 && ratio >= 0.5) {
// Swipe right direction threshold reached
left.value = "100%";
opacity.value = 0;
emit("swipeRight");
} else if (distanceX.value > 0 && ratio >= 0.5) {
// Swipe left direction threshold reached
left.value = "-100%";
opacity.value = 0;
emit("swipeLeft");
} else {
// Reset if threshold not reached
cardIsAtStartPosition.value = true;
left.value = "0";
opacity.value = 1;
}
}
},
});

const backgroundColorClasses = computed(() => ({
"bg-base-100": cardIsAtStartPosition.value,
"bg-success": distanceX.value < -props.swipeThreshold / 10,
"bg-error": distanceX.value > props.swipeThreshold / 10,
}));

const swipeIcon = computed(() => {
if (!isSwiping.value) return null;

if (distanceX.value < -props.swipeThreshold / 10) return faCheck;
if (distanceX.value > props.swipeThreshold / 10) return faBan;
return null;
});

const textPositionClass = computed(() => {
if (distanceX.value < -props.swipeThreshold / 10) return "left-4";
if (distanceX.value > props.swipeThreshold / 10) return "right-4";
return "";
});
</script>

<template>
<div class="inline-flex">
<div
ref="container"
class="rounded-3xl relative inline-block overflow-hidden shadow-lg"
:class="backgroundColorClasses"
>
<div
ref="target"
class="relative w-full flex items-center justify-center"
:class="{ 'transition-all duration-200 ease-linear': !isSwiping }"
:style="{ left, opacity }"
>
<slot />
</div>
</div>
<div class="inline-flex">
<div
ref="container"
class="rounded-3xl relative inline-block overflow-hidden shadow-lg"
:class="backgroundColorClasses"
>
<div
ref="target"
class="relative w-full flex items-center justify-center z-10"
:class="{ 'transition-all duration-200 ease-linear': !isSwiping }"
:style="{ left, opacity }"
>
<slot />
</div>
<!-- Overlay text for swipe direction -->
<div
v-if="swipeIcon"
class="absolute top-1/2 transform -translate-y-1/2 pointer-events-none"
:class="textPositionClass"
>
<FontAwesomeIcon :icon="swipeIcon" class="text-3xl text-white" />
</div>
</div>
</template>
</div>
</template>
17 changes: 11 additions & 6 deletions Frontend/composables/useUserApi.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {makeRequest} from './useApi'
import type {UserCreateData, UserRegistrationData} from "~/shared/types/userInterfaces";
import { makeRequest } from './useApi'
import type { UserCreateData, UserRegistrationData } from "~/shared/types/userInterfaces";

export const useUserApi = () => {

const getUserRegistrationStatus = async (email: string) => {
const data = await $fetch(`/api/users/check-registration?email=${email}`);
return data as UserRegistrationData;
const data = await $fetch(`/api/users/check-registration?email=${email}`);
return data as UserRegistrationData;
}
const createUser = async (data: UserCreateData) => {
return await makeRequest('users', 'POST', data)
Expand Down Expand Up @@ -40,13 +40,17 @@ export const useUserApi = () => {
const getRecommendedSupervisors = async (data: string) => {
return await makeRequest(`match/${data}`, 'GET');
}

const createStudentProfile = async (data: string) => {
return await makeRequest('students', 'POST', {
thesis_description: data
})
}

const deleteUser = async (id: string) => {
return await makeRequest(`users/${id}`, 'DELETE')
}

return {
getUserRegistrationStatus,
createUser,
Expand All @@ -56,7 +60,8 @@ export const useUserApi = () => {
getUserById,
addUserTag,
getRecommendedSupervisors,
createStudentProfile
createStudentProfile,
deleteUser
}

}
Loading
Loading