implement phase 4

This commit is contained in:
Suphonchai Phoonsawat 2026-08-19 21:35:07 +07:00
parent 25c2ce53cd
commit f4b1c3e14b
27 changed files with 6929 additions and 48 deletions

View file

@ -0,0 +1,16 @@
<!doctype html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title>Sign-in</title>
<!-- Office JavaScript API — ต้องโหลดก่อนเรียก messageParent -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
</head>
<body style="width: 100%; height: 100%; margin: 0; padding: 16px; font-family: 'Segoe UI', sans-serif; color: #333;">
<p id="status">กำลังกลับสู่ add-in…</p>
</body>
</html>

View file

@ -0,0 +1,61 @@
/* global Office, window, URLSearchParams, document */
/**
* หน้า redirect ของ Keycloak — รัน "ใน Office Dialog" ไม่ใช่ task pane (FR-8)
* หน้าที่: parse code/state จาก URL → messageParent กลับ task pane → ปิด dialog
* ตัวแลก token อยู่ฝั่ง task pane (authService.login) เพราะ verifier ถูก generate ที่นั่น
*/
interface CallbackPayload {
code?: string;
state?: string;
error?: string;
errorDescription?: string;
}
function setStatus(text: string): void {
const element = document.getElementById("status");
if (element) {
element.textContent = text;
}
}
Office.onReady(() => {
const params = new URLSearchParams(window.location.search);
const payload: CallbackPayload = {};
const error = params.get("error");
if (error) {
payload.error = error;
const description = params.get("error_description");
if (description) {
payload.errorDescription = description;
}
setStatus("เข้าสู่ระบบไม่สำเร็จ — กำลังปิดหน้าต่าง…");
} else {
const code = params.get("code");
const state = params.get("state");
if (code && state) {
payload.code = code;
payload.state = state;
setStatus("เข้าสู่ระบบสำเร็จ — กำลังกลับสู่ add-in…");
} else {
// เปิดตรงๆ ไม่ใช่ redirect จาก Keycloak — ไม่มีอะไรจะส่งกลับ
payload.error = "invalid_callback";
payload.errorDescription = "ไม่พบ code/state ใน URL";
setStatus("หน้านี้เปิดโดยตรงไม่ได้ — ต้องเข้าผ่านการ login ของ add-in");
}
}
try {
Office.context.ui.messageParent(JSON.stringify(payload));
} catch (error) {
// เช่นเปิดเป็น tab เองนอก dialog — บอกผู้ใช้แทนที่จะ throw
setStatus("ไม่สามารถติดต่อกลับ task pane ได้ (หน้านี้ต้องเปิดผ่าน add-in)");
console.error("messageParent failed:", error);
return;
}
// ปิด dialog ตัวเองหลังส่ง message กลับแล้ว (task pane ก็จะเรียก dialog.close() อีกชั้น)
window.close();
});

View file

@ -5,7 +5,7 @@ import { Button, Field, Textarea, tokens, makeStyles } from "@fluentui/react-com
/* global HTMLTextAreaElement */
interface TextInsertionProps {
insertText: (text: string) => void;
insertText: (_text: string) => void;
}
const useStyles = makeStyles({