Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3631609
feat: added staff scan qr page
dhanavadh Jul 13, 2025
fe86339
Merge branch 'dev' into feat/firstdate/staff-qr
dhanavadh Jul 13, 2025
076210b
fix: firstdate staff bg
dhanavadh Jul 13, 2025
a25dc69
Merge branch 'dev' into feat/firstdate/staff-qr
dhanavadh Jul 14, 2025
2eb62c2
feat: add @yudiel/react-qr-scanner
dhanavadh Jul 14, 2025
4cbcbd3
Merge branch 'dev' into feat/firstdate/staff-qr
dhanavadh Jul 14, 2025
a70b642
Merge branch 'dev' into feat/firstdate/staff-qr
dhanavadh Jul 14, 2025
2fa23d2
Merge branch 'dev' into feat/firstdate/staff-qr
dhanavadh Jul 14, 2025
560d6a0
Feat: added staff-qr page
dhanavadh Jul 14, 2025
382c2c8
Merge branch 'dev' into feat/firstdate/staff-qr
neennera Jul 15, 2025
a5e278f
chore: fix middleware doesn't work
Dpyde Jul 16, 2025
9846fda
feat: Implement qr scan with api
Dpyde Jul 16, 2025
6b9742a
Merge branch 'dev' into feat/firstdate/staff-qr
dhanavadh Jul 16, 2025
9447040
fix: staff-qr code
dhanavadh Jul 16, 2025
d3ac27c
Merge branch 'feat/firstdate/staff-qr' of https://github.com/isd-sgcu…
neennera Jul 16, 2025
cd6e983
Merge branch 'dev' into feat/firstdate/staff-qr
neennera Jul 17, 2025
e53584f
fix: conflicts
MasterIceZ Jul 17, 2025
707f4a7
fix: qr scan error, body stream err, cannot send cookie to backend err
dhanavadh Jul 17, 2025
8395fc4
Fix: alternative form handle error
dhanavadh Jul 17, 2025
919a945
fix: no event active layout
dhanavadh Jul 17, 2025
9523a05
Merge branch 'dev' into feat/firstdate/staff-qr
dhanavadh Jul 17, 2025
7878eff
Merge branch 'feat/firstdate/staff-qr' of https://github.com/isd-sgcu…
neennera Jul 17, 2025
4104be7
[Fix] Staff-QR (#71)
dhanavadh Jul 17, 2025
80569df
feat: getGroupByInviteCode
BadLuckZ Jul 17, 2025
0b94782
fix: fest content
neennera Jul 17, 2025
e0c6a73
fix: qrcode in /events go to /firstdate/qrcode
neennera Jul 17, 2025
f6e264a
add : checkin not found & remove freshmennight
neennera Jul 17, 2025
d0acd9f
feat: joinGroup and leaveGroup
BadLuckZ Jul 17, 2025
09d2d67
add: fix event period
neennera Jul 17, 2025
1c252d1
fix: staff with navbar
neennera Jul 17, 2025
0bd0a31
Update Routes.ts
BadLuckZ Jul 17, 2025
82d9fc3
feat: add nonStartedRoutes time constraint whitelist
Taihenc Jul 17, 2025
c3c7d6a
fix : home & map unclickable
neennera Jul 17, 2025
8448136
fix: new Date()
neennera Jul 17, 2025
05e7123
Merge pull request #80 from isd-sgcu/fix/qr-code-not-scan
neennera Jul 17, 2025
375308a
fix: qr load
Taihenc Jul 17, 2025
be3ec12
Merge branch 'main' into dev
Taihenc Jul 17, 2025
366cf26
fix: check in not found event
neennera Jul 18, 2025
c56c4d6
fix: qa profile , firstdate register
neennera Jul 18, 2025
2b8d55e
Merge branch 'main' into dev
neennera Jul 18, 2025
b8cf671
Merge pull request #79 from isd-sgcu/feat/rpkm/groupAPI
RawSalmon69 Jul 18, 2025
96e5daf
fix: qrcode
neennera Jul 19, 2025
6a6f02d
Merge branch 'dev' into feat/firstdate/staff-qr
neennera Jul 19, 2025
ac39a95
Merge branch 'feat/firstdate/staff-qr' into fix/qr-code-not-scan
neennera Jul 17, 2025
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
18 changes: 14 additions & 4 deletions src/components/common/profile/EditProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,18 @@ function EditProfileContent({
Authorization: `Bearer ${getAuthToken()}`,
},
});
const raw_data = reponse.data as EditProfileFormData;

return reponse.data as EditProfileFormData;
const data = {
user: {
...raw_data.user,
hasAllergies: raw_data.user.foodAllergy !== "",
hasMedications: raw_data.user.drugAllergy !== "",
hasChronicDiseases: raw_data.user.illness !== "",
},
};

return data as EditProfileFormData;
},
});

Expand Down Expand Up @@ -184,9 +194,9 @@ function EditProfileContent({
parentName: data.user.parentName,
parentPhoneNumber: data.user.parentPhoneNumber,
parentRelationship: data.user.parentRelationship,
foodAllergy: data.user.hasAllergies ? data.user.foodAllergy : null,
drugAllergy: data.user.hasMedications ? data.user.drugAllergy : null,
illness: data.user.hasChronicDiseases ? data.user.illness : null,
foodAllergy: data.user.hasAllergies ? data.user.foodAllergy : "",
drugAllergy: data.user.hasMedications ? data.user.drugAllergy : "",
illness: data.user.hasChronicDiseases ? data.user.illness : "",
};

const reponse = await api.patch("/user/update", formData, {
Expand Down
4 changes: 2 additions & 2 deletions src/components/firstdate/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const footerGradient = variant
>
<p class="text-xl font-semibold">Contact Us</p>
<div class="flex flex-row gap-x-2">
<div class="mt-3 flex flex-col gap-y-1">
<div class="mt-3 flex flex-col items-center gap-y-1">
<a href="https://isd.sgcu.in.th" target="_blank">
<img src="/common/isd-logo.svg" alt="ISD Logo" class="h-8 w-auto" />
</a>
Expand All @@ -61,7 +61,7 @@ const footerGradient = variant
Website
</a>
</div>
<div class="mt-3 flex flex-col gap-y-1">
<div class="mt-3 flex flex-col items-center gap-y-1">
<a href="https://instagram.com/isd.sgcu" target="_blank">
<img
src="/common/instagram.svg"
Expand Down
175 changes: 145 additions & 30 deletions src/components/rpkm/components/group-picker.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,37 @@ import GroupProfile from "@rpkm/rubpuen/GroupProfile";
import Divider from "@/components/common/Divider.astro";
import Frame from "@/components/common/Frame.astro";
import { getGroupData } from "@/lib/groupAPI";
import type { Group } from "@/types/common";
import { getProfile } from "@/lib/profileAPI";
import type { Group, User } from "@/types/common";

const token = Astro.cookies.get("token")?.value;

let groupData = null;
let user = null;

if (token) {
const response = await getGroupData(token);
if (response.success && response.data) {
groupData = response.data.data as Group;
}

try {
const userResponse = await getProfile(token);
if (userResponse.success && userResponse.data) {
user = userResponse.data.user as User;
} else {
console.error("Failed to fetch user data:", userResponse.error);
}
} catch (error) {
console.error("Error fetching user data:", error);
}
}

if (!groupData) {
if (!groupData || !user) {
return Astro.redirect("/login");
}

const inviteCode = groupData.inviteCode;
const headName =
groupData.owner.firstName +
" " +
groupData.owner.lastName +
" (" +
groupData.owner.nickname +
")";
const headId = groupData.owner.studentId;

const member1 = groupData.memberCount > 1 ? groupData.users[1] : null;
const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
Expand Down Expand Up @@ -59,6 +65,9 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
</div>
</div>

<!-- Error Message -->
<p class="text-sm text-red-500" id="error-room-message"></p>

<!-- Submit Button -->
<div class="drop-shadow-[0_0_4px_white] filter">
<button
Expand Down Expand Up @@ -104,7 +113,9 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
>
{"<"}
</p>
<p class="text-2xl font-semibold text-white">จับกลุ่มเพื่อน (1/3)</p>
<p class="text-2xl font-semibold text-white">
{`จับกลุ่มเพื่อน (${groupData.memberCount}/3)`}
</p>
</div>

<!-- Profile -->
Expand Down Expand Up @@ -182,7 +193,7 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
<!-- Title -->
<div class="relative w-full pt-2 text-center">
<p class="z-20 text-center text-2xl font-semibold text-white">
จับกลุ่มเพื่อน (2/3)
{`จับกลุ่มเพื่อน (${groupData.memberCount}/3)`}
</p>
<img
src="/images/rpkm/exit-icon.svg"
Expand All @@ -195,9 +206,9 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;

<!-- Profile -->
<div class="z-20 flex w-full justify-center gap-[10px] pt-6">
<img src="/images/rpkm/sample-profile2.png" width="80" height="80" />
<img src="/images/rpkm/sample-profile.png" width="80" height="80" />
<img src="/images/rpkm/sample-blank.png" width="80" height="80" />
<GroupProfile user={groupData.owner} variant="red-star" />
<GroupProfile user={member1} variant="blue" />
<GroupProfile user={member2} variant="blue" />
</div>

<!-- Invite URL -->
Expand Down Expand Up @@ -279,14 +290,16 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
</p>

<!-- Profile -->
<div class="z-20 flex w-full justify-center gap-3 px-5 pt-4">
<img src="/images/rpkm/sample-profile2.png" width="80" height="80" />
<div
class="z-20 flex w-full justify-center gap-3 px-5 pt-4"
id="target-head-profile"
>
</div>

<!-- Name -->
<div class="flex flex-col items-center pt-1">
<p class="text-xl font-semibold text-white">{headName}</p>
<p class="text-white">{headId}</p>
<p class="text-xl font-semibold text-white" id="target-head-name"></p>
<p class="text-white" id="target-head-id"></p>
</div>

<!-- Submit Button -->
Expand Down Expand Up @@ -336,7 +349,7 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
<!-- Information -->
<div class="flex flex-col items-center gap-1 pt-4 text-white">
<p class="text-2xl font-medium">คุณได้จับกลุ่มกับ</p>
<p class="text-xl font-semibold">{headName}</p>
<p class="text-xl font-semibold" id="target-head-name-popup"></p>
<p class="text-2xl font-medium">สำเร็จแล้ว</p>
</div>
</div>
Expand All @@ -354,6 +367,9 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;

<!-- Script -->
<script>
import { getGroupByInviteCode, joinGroup, leaveGroup } from "@/lib/groupAPI";
import { AvatarMap } from "@rpkm/data/profile";

const input = document.getElementById("room-id-insert") as HTMLInputElement;

const headGroupBtn = document.getElementById(
Expand Down Expand Up @@ -394,13 +410,34 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
const roomCodeMemberContainer = document.getElementById(
"room-code-member-container"
);
const errorRoomMessage = document.getElementById(
"error-room-message"
) as HTMLParagraphElement;

const targetHeadName = document.getElementById(
"target-head-name"
) as HTMLParagraphElement;
const targetHeadId = document.getElementById(
"target-head-id"
) as HTMLParagraphElement;

const targetHeadNamePopup = document.getElementById(
"target-head-name-popup"
) as HTMLParagraphElement;

let targetGroupData: any = null;
let inviteCode = "";

function formatRoomId(raw: string): string {
return raw.toUpperCase().replace(/[^A-Z0-9]/g, "");
}

function toggleSubmitButton() {
if (!input || !joinGroupButton) return;
if (!input || !joinGroupButton || !errorRoomMessage) return;

if (document.activeElement === input) {
errorRoomMessage.innerHTML = "";
}

// Input Validation
const formattedRoomId = formatRoomId(input.value);
Expand Down Expand Up @@ -447,17 +484,95 @@ const member2 = groupData.memberCount > 2 ? groupData.users[2] : null;
toggleSubmitButton();
});

joinGroupButton?.addEventListener("click", () => {
groupPopupView?.classList.remove("hidden");
input.value = "";
toggleSubmitButton();
joinGroupButton?.addEventListener("click", async () => {
if (!input.value) return;

inviteCode = formatRoomId(input.value);
if (inviteCode.length !== 6) return;

errorRoomMessage.innerHTML = "";

// Add loading state
joinGroupButton.disabled = true;
joinGroupButton.textContent = "กำลังค้นหา...";

try {
const response = await getGroupByInviteCode(inviteCode);
if (response.success && response.data) {
targetGroupData = response.data.data;

const profileContainer = document.getElementById("target-head-profile");

if (profileContainer && targetGroupData.owner) {
const avatarSrc =
targetGroupData.owner?.avatarId &&
AvatarMap[targetGroupData.owner.avatarId as keyof typeof AvatarMap]
? AvatarMap[
targetGroupData.owner.avatarId as keyof typeof AvatarMap
]
: "/images/rpkm/profile/profile-unknown.png";

profileContainer.innerHTML = `
<div class="user-profile flex flex-col items-center justify-center">
<div class="relative flex h-[80px] w-[80px]">
<img
src="${avatarSrc}"
alt="${targetGroupData.owner.firstName} ${targetGroupData.owner.lastName} avatar"
class="h-full w-full object-cover"
/>
<img
src="/images/frame-profile-image/frame-profile-image-red-star.svg"
alt="Frame"
class="absolute h-full w-full"
/>
</div>
</div>
`;
}

targetHeadName.innerHTML =
targetGroupData.owner.firstName +
" " +
targetGroupData.owner.lastName +
" (" +
targetGroupData.owner.nickname +
")";
targetHeadId.innerHTML = targetGroupData.owner.studentId;

groupPopupView?.classList.remove("hidden");
} else {
errorRoomMessage.innerHTML = response.error || "ไม่พบห้องที่ระบุ";
}
} catch (error) {
console.error("Unexpected error:", error);
errorRoomMessage.innerHTML = "เกิดข้อผิดพลาดในการค้นหาห้อง";
} finally {
joinGroupButton.disabled = false;
joinGroupButton.innerHTML =
'<p class="text-lg font-medium text-white">ยืนยัน</p>';
input.value = "";
toggleSubmitButton();
}
});

submitGroupButton?.addEventListener("click", () => {
groupPopupView?.classList.add("hidden");
groupPopupSuccessView?.classList.remove("hidden");
groupDefaultView?.classList.add("hidden");
groupMemberView?.classList.remove("hidden");
submitGroupButton?.addEventListener("click", async () => {
const response = await joinGroup(inviteCode);

if (response.success) {
targetHeadNamePopup.innerHTML =
targetGroupData.owner.firstName +
" " +
targetGroupData.owner.lastName +
" (" +
targetGroupData.owner.nickname +
")";
groupPopupView?.classList.add("hidden");
groupPopupSuccessView?.classList.remove("hidden");
groupDefaultView?.classList.add("hidden");
groupMemberView?.classList.remove("hidden");
} else {
console.error("Failed to leave group before:", response.error);
}
});

cancelGroupButton?.addEventListener("click", () => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/rpkm/components/house-picker.astro
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
import { houseDisplayData } from "@rpkm/data/house.js";
import HouseConfirmPopup from "@rpkm/elements/house-confirm-popup.astro";
import HouseDetailCard from "@rpkm/elements/house-detail-card.astro";
import HouseInfoPopup from "@rpkm/elements/house-info-popup.astro";
import HousePickingCard from "@rpkm/elements/house-picking-card.astro";

import Divider from "@/components/common/Divider.astro";
import Frame from "@/components/common/Frame.astro";
import { houseDisplayData } from "@/components/rpkm/data/house.js";

const houseSizes = ["ทั้งหมด", "S", "M", "L", "XL", "XXL"];

Expand Down
File renamed without changes.
15 changes: 15 additions & 0 deletions src/components/rpkm/data/profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { User } from "@/types/common";

export interface ProfileProps {
user: User | null;
variant?: "blue-star" | "red-star" | "blue" | "red";
className?: string;
}

export const AvatarMap: Record<number, string> = {
1: "/images/rpkm/profile/robot-01.png",
2: "/images/rpkm/profile/robot-02.png",
3: "/images/rpkm/profile/robot-03.png",
4: "/images/rpkm/profile/robot-04.png",
5: "/images/rpkm/profile/robot-05.png",
};
20 changes: 3 additions & 17 deletions src/components/rpkm/rubpuen/GroupProfile.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
import type { JSX } from "astro/jsx-runtime";

import type { User } from "@/types/common";

interface GroupProfileProps {
user: User | null;
variant?: "blue-star" | "red-star" | "blue" | "red";
className?: string;
}

const groupAvatarMap: Record<number, string> = {
1: "/images/rpkm/profile/robot-01.png",
2: "/images/rpkm/profile/robot-02.png",
3: "/images/rpkm/profile/robot-03.png",
4: "/images/rpkm/profile/robot-04.png",
5: "/images/rpkm/profile/robot-05.png",
};
import { AvatarMap, type ProfileProps } from "@rpkm/data/profile";

export default function GroupProfile({
user,
variant = "red",
className = "",
}: GroupProfileProps): JSX.Element {
}: ProfileProps): JSX.Element {
const frameSvg = `/images/frame-profile-image/frame-profile-image-${variant}.svg`;

return (
Expand All @@ -31,7 +17,7 @@ export default function GroupProfile({
<img
src={
user
? groupAvatarMap[user.avatarId]
? AvatarMap[user.avatarId]
: "/images/rpkm/profile/profile-unknown.png"
}
alt={
Expand Down
Loading
Loading