Skip to main content

ปฏิทินวางแผนแคมเปญ

ภาพรวม

Campaign Planner คือมุมมองปฏิทินรายเดือนที่รวมแคมเปญทั้งหมดมาจัดเรียงตามวัน สำหรับผู้ดูแลระบบและทีมการตลาดที่ต้องวางแผนว่าจะส่งแคมเปญวันไหน วันไหนส่งถี่เกินไป และมีแคมเปญร่างค้างอยู่หรือไม่

ฟีเจอร์นี้เป็นแบบ อ่านอย่างเดียว ทั้งหมด ไม่มีการสร้าง แก้ไข หรือลบแคมเปญจากหน้านี้ และไม่มีชั้นบริการของตัวเอง แต่ใช้ข้อมูลชุดเดียวกับหน้าจัดการแคมเปญ ทุกรายการบนปฏิทินเป็นลิงก์กลับไปยังหน้าดูรายละเอียดของแคมเปญนั้น

พูดอีกอย่างคือ Planner ทำหน้าที่เป็น "ทางเข้าอีกทางหนึ่ง" สู่ข้อมูลเดียวกัน โดยจัดเรียงตามเวลาแทนที่จะเป็นตาราง

ด้านบนของหน้ามีการ์ดสรุปของเดือนที่กำลังดูอยู่ แสดงจำนวนแคมเปญรวมและแยกตามสถานะ 4 แบบ ได้แก่ ส่งแล้ว (Sent) ตั้งเวลาไว้ (Scheduled) ยกเลิก (Cancelled) และร่าง (Draft)

Business Flow

  1. ผู้ใช้เปิดหน้า /campaign-planner ระบบตรวจสิทธิ์การดูข้อมูลแคมเปญก่อน จากนั้นตั้งค่า breadcrumb และเมนูด้านข้างให้ทำงานสอดคล้องกัน
  2. ระบบเริ่มต้นที่เดือนปัจจุบัน แล้วคำนวณช่วงวันที่ที่ต้องดึงข้อมูลเป็น ต้นเดือนย้อนหลัง 7 วัน ถึงปลายเดือนล่วงหน้า 7 วัน เพื่อให้ช่องปฏิทินแถวแรกและแถวสุดท้ายที่คาบเกี่ยวกับเดือนข้างเคียงมีข้อมูลครบ
  3. ระบบดึงข้อมูลแยกกัน 4 คำขอตามสถานะ เพื่อให้แต่ละสถานะมี cache ของตัวเอง
    • แคมเปญที่ส่งแล้วและที่ตั้งเวลาไว้ เรียงตามวันที่เริ่มจากเก่าไปใหม่
    • แคมเปญร่างและที่ยกเลิก เรียงตามวันที่แก้ไขล่าสุดจากใหม่ไปเก่า
  4. ผลลัพธ์ทั้งสี่ชุดถูกรวมเข้าด้วยกัน แล้วจัดกลุ่มตามวันที่ โดยเลือกฟิลด์วันที่ตามสถานะ คือแคมเปญที่ส่งแล้วและที่ตั้งเวลาไว้ใช้วันที่เริ่ม ส่วนแคมเปญร่างและที่ยกเลิกใช้วันที่แก้ไขล่าสุด แคมเปญที่ไม่มีวันที่จะถูกข้ามไป
  5. ภายในแต่ละวัน รายการจะเรียงตามลำดับความสำคัญของสถานะก่อน (ตั้งเวลาไว้ ส่งแล้ว ร่าง ยกเลิก ตามลำดับ) แล้วจึงเรียงตามวันเวลา
  6. การ์ดสรุปด้านบนนับเฉพาะแคมเปญที่อยู่ในเดือนที่กำลังดูจริง ไม่รวมช่วง 7 วันที่ดึงมาเผื่อ
  7. ระหว่างที่ข้อมูลยังโหลดไม่เสร็จ การ์ดสรุปจะแสดงเครื่องหมายขีดแทนตัวเลข และพื้นที่ปฏิทินจะแสดงสัญลักษณ์กำลังโหลด
  8. เมื่อข้อมูลพร้อม ระบบแสดงปฏิทินแบบเต็มหน้าจอพร้อมคำอธิบายสีของทั้ง 4 สถานะไว้ด้านบน
  9. แต่ละช่องวันแสดงแคมเปญได้สูงสุด 3 รายการ แต่ละรายการเป็นจุดสีคู่กับชื่อแคมเปญ และคลิกเพื่อเปิดหน้าดูรายละเอียดได้
  10. เมื่อผู้ใช้นำเมาส์ไปวางบนรายการ ระบบแสดงกล่องข้อมูลย่อ ประกอบด้วยป้ายสถานะ ชื่อแคมเปญ กลุ่มผู้รับ (หรือ "เพื่อนทั้งหมดบน OA" หากไม่ได้ระบุกลุ่ม) จำนวนผู้รับ และบรรทัดวันเวลาที่เปลี่ยนคำอธิบายตามสถานะ เช่น ส่งเมื่อ ตั้งเวลาไว้ ยกเลิกเมื่อ หรือแก้ไขเมื่อ
  11. หากวันใดมีเกิน 3 รายการ จะมีปุ่มแสดงจำนวนที่เหลือ กดแล้วเปิดกล่องรายการเต็มของวันนั้น พร้อมหัวข้อบอกวันและจำนวนรวม แต่ละแถวเป็นลิงก์ไปหน้าดูรายละเอียดเช่นกัน
  12. เมื่อผู้ใช้เปลี่ยนเดือนบนปฏิทิน ช่วงวันที่จะถูกคำนวณใหม่และดึงข้อมูลของเดือนใหม่โดยอัตโนมัติ

หน้าจอและองค์ประกอบหลัก

หน้าและตัวควบคุมหลัก

หน้า /campaign-planner เป็นเพียงชั้นบางที่ตั้งค่า breadcrumb เมนูด้านข้าง และการตรวจสิทธิ์ ส่วนตรรกะทั้งหมดอยู่ที่ container (src/components/campaign-planner/campaign-planner.container.tsx) ซึ่งรับผิดชอบการดึงข้อมูลทั้ง 4 สถานะ การรวมและจัดกลุ่มข้อมูลตามวัน การคำนวณสถิติประจำเดือน และการแสดงการ์ดสรุป

Container ยังรองรับรูปแบบข้อมูลตอบกลับได้สองแบบ ทั้งแบบที่เป็นอาร์เรย์โดยตรงและแบบที่ห่อไว้ในอ็อบเจ็กต์ เนื่องจากรูปแบบที่ API ตอบกลับให้หน้านี้กับหน้ารายการไม่เหมือนกัน

ปฏิทิน

คอมโพเนนต์ปฏิทินรับผิดชอบการวาดช่องวัน คำอธิบายสี กล่องข้อมูลย่อเมื่อวางเมาส์ และปุ่มดูรายการที่เหลือ รวมถึงการแจ้งกลับเมื่อผู้ใช้เปลี่ยนเดือน

กล่องข้อมูลย่อและรายการรายวัน

กล่องข้อมูลย่อ (tooltip) และกล่องรายการเต็มของวัน (popover) เป็นคอมโพเนนต์แยกกัน แต่ใช้ป้ายสถานะร่วมกัน ทำให้สีและไอคอนของสถานะสอดคล้องกันทั้งหน้า

ป้ายสถานะ

คอมโพเนนต์ป้ายสถานะกำหนดสีและไอคอนของทั้ง 4 สถานะไว้ที่จุดเดียว โดยสีที่ใช้คือเขียวสำหรับส่งแล้ว น้ำเงินสำหรับตั้งเวลาไว้ แดงสำหรับยกเลิก และเทาสำหรับร่าง ส่วนข้อความบนป้ายไม่ได้ถูกกำหนดตายตัวไว้ในค่าคงที่ แต่ถูกดึงจากระบบแปลภาษาตอนแสดงผล เพื่อให้สลับภาษาได้ถูกต้อง

ปลายทาง API ที่เรียกใช้

ฟีเจอร์นี้เรียกใช้เฉพาะ GET /campaign ของหน้าจัดการแคมเปญ โดยยิง 4 ครั้งต่อการเปลี่ยนเดือนหนึ่งครั้ง แต่ละครั้งระบุสถานะที่ต้องการ ช่วงวันที่ ลำดับการเรียง และจำกัดผลลัพธ์ที่ 500 รายการ

จุดเชื่อมต่อกับฟีเจอร์อื่น

  • จัดการแคมเปญ — เป็น dependency หลักและทางเดียวของฟีเจอร์นี้ ทั้งการดึงข้อมูล ค่าคงที่ของสถานะ โครงสร้างข้อมูล และปลายทางของลิงก์ทุกจุด
  • สิทธิ์การเข้าถึง — ใช้สิทธิ์ดูข้อมูลของหน้าจัดการแคมเปญ ไม่มีสิทธิ์แยกของ Planner เอง โดยโมดูล campaign ฝั่งเซิร์ฟเวอร์จะเปิดทั้งหน้าจัดการแคมเปญและหน้าปฏิทินพร้อมกัน ส่วนเมนูด้านข้างใช้คีย์ของตัวเองในการไฮไลต์เมนูที่กำลังใช้งาน
  • องค์ประกอบร่วม — ใช้ส่วนหัวมาตรฐานของหน้าและคอมโพเนนต์ลิงก์กลางที่รองรับการ build แบบ static export
  • ข้อสังเกตเรื่องรูปแบบวันที่และตัวเลข — การจัดรูปแบบวันที่และตัวเลขในหน้านี้ถูกกำหนดเป็น locale แบบอังกฤษไว้ตายตัว จึงไม่เปลี่ยนตามภาษาที่ผู้ใช้เลือก

รายละเอียดฝั่ง Backend (CMS API)

ไม่มีโมดูล backend ของตัวเอง

ฝั่ง cms-api ไม่มีโมดูลหรือ endpoint สำหรับปฏิทินวางแผนแคมเปญโดยเฉพาะ หน้านี้ใช้ GET /api/campaign ตัวเดียวกับหน้าจัดการแคมเปญทั้งหมด เพียงแต่ยิงหลายครั้งด้วยเงื่อนไขต่างกัน สิ่งที่ปฏิทินทำจึงเป็นการจัดเรียงและจัดกลุ่มข้อมูลฝั่งหน้าเว็บล้วน ๆ

ข้อนี้มีนัยเชิงปฏิบัติหลายอย่าง

  • ไม่มีการกรองตามช่วงวันที่ที่ backend คำนวณให้ — หน้าเว็บเป็นผู้ส่งช่วงวันที่และเงื่อนไขการเรียงลำดับเข้าไปเอง การเปลี่ยนกฎการแสดงผลของปฏิทินจึงไม่ต้องแก้ backend
  • การยิง 4 คำขอต่อการเปลี่ยนเดือนหนึ่งครั้งเป็นการออกแบบฝั่งหน้าเว็บ ไม่ใช่ข้อจำกัดของ API — API เดียวกันรับพารามิเตอร์สถานะได้ตามปกติ
  • ขีดจำกัด 500 รายการต่อคำขอเป็นค่าที่หน้าเว็บกำหนด ถ้าเดือนใดมีแคมเปญเกินจำนวนนี้ในสถานะเดียวกัน รายการส่วนเกินจะไม่ปรากฏบนปฏิทินโดยไม่มีการแจ้งเตือน

สิทธิ์ที่บังคับจริง

เพราะใช้ endpoint เดียวกัน สิทธิ์ที่บังคับจึงเป็นชุดเดียวกับหน้าจัดการแคมเปญทุกประการ

  • ต้องผ่าน ModuleGate ของโมดูล campaign ซึ่งบังคับใช้จริง ถ้าองค์กรถูกปิดโมดูลแคมเปญไว้ หน้าปฏิทินจะดึงข้อมูลไม่ได้เลยเช่นเดียวกับหน้ารายการ
  • ต้องมี token ที่ระบุ LINE OA แล้ว ข้อมูลบนปฏิทินจึงถูกจำกัดขอบเขตอยู่ที่ channel ที่เลือกโดยอัตโนมัติ
  • ไม่มีสิทธิ์แยกสำหรับปฏิทิน และไม่มีทางที่ผู้ใช้จะเห็นแคมเปญบนปฏิทินแต่เปิดหน้ารายละเอียดไม่ได้

ทำไมรูปแบบข้อมูลตอบกลับจึงมีสองแบบ

ข้อสังเกตที่ว่า container ต้องรองรับผลลัพธ์ทั้งแบบอาร์เรย์ตรงและแบบห่อในอ็อบเจ็กต์ มีที่มาจากฝั่ง backend: GET /api/campaign ตอบกลับเป็นโครงสร้างที่มีทั้งรายการข้อมูล จำนวนรวมตามเงื่อนไข และจำนวนรวมทั้งหมด ไม่ได้ตอบเป็นอาร์เรย์เปล่า การเขียนโค้ดให้รองรับทั้งสองแบบจึงเป็นการเผื่อไว้ ไม่ใช่เพราะ backend ตอบไม่คงเส้นคงวา

ข้อมูลบางฟิลด์ถูกประกอบขึ้นที่ backend

repository ฝั่ง backend จะแทรกข้อมูลกลุ่มเป้าหมายเข้าไปในผลลัพธ์ของแต่ละแคมเปญให้เลย ปฏิทินจึงแสดงชื่อกลุ่มผู้รับและจำนวนผู้รับในกล่องข้อมูลย่อได้โดยไม่ต้องยิงคำขอเพิ่ม