AlertPreviewPanel.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. 'use client';
  2. import { useState } from 'react';
  3. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
  4. import { faPlay } from '@fortawesome/free-solid-svg-icons';
  5. import View from '@/app/widget/alert/[widgetToken]/view';
  6. import { DonationAlertConfig, DonationAlertData } from '@/types/donation';
  7. import {
  8. DONATION_AMOUNT_MIN, DONATION_AMOUNT_MAX, DONATION_AMOUNT_STEP, DONATION_AMOUNT_DEFAULT,
  9. ALERT_NAME_MAX_LENGTH, ALERT_MESSAGE_MAX_LENGTH,
  10. PREVIEW_DEFAULT_NAME, PREVIEW_DEFAULT_MESSAGE
  11. } from '@/constants/donation';
  12. import type { FormState } from '../types';
  13. type Props = {
  14. form: FormState;
  15. };
  16. export default function AlertPreviewPanel({ form }: Props) {
  17. const [previewName, setPreviewName] = useState(PREVIEW_DEFAULT_NAME);
  18. const [previewAmount, setPreviewAmount] = useState(DONATION_AMOUNT_DEFAULT);
  19. const [previewMessage, setPreviewMessage] = useState(PREVIEW_DEFAULT_MESSAGE);
  20. const [previewKey, setPreviewKey] = useState(0);
  21. const [showPreview, setShowPreview] = useState(false);
  22. // form → DonationAlertConfig 매핑 (id만 추가)
  23. const config: DonationAlertConfig = { id: 0, ...form };
  24. const fakeAlert: DonationAlertData = {
  25. alertID: previewKey,
  26. donationID: 0,
  27. correlationID: '',
  28. sponsorMemberID: 0,
  29. sendName: previewName || PREVIEW_DEFAULT_NAME,
  30. amount: previewAmount || DONATION_AMOUNT_DEFAULT,
  31. netAmount: previewAmount || DONATION_AMOUNT_DEFAULT,
  32. message: previewMessage || null,
  33. channelID: 0,
  34. channelName: '',
  35. crewMemberID: null,
  36. crewMemberNickname: null,
  37. isTest: true,
  38. createdAt: new Date().toISOString()
  39. };
  40. const handlePreview = () => {
  41. setShowPreview(false);
  42. // 다음 tick에 다시 마운트해서 애니메이션 재실행 (key + show 토글)
  43. requestAnimationFrame(() => {
  44. setPreviewKey(prev => prev + 1);
  45. setShowPreview(true);
  46. });
  47. };
  48. const handleComplete = () => {
  49. setShowPreview(false);
  50. };
  51. return (
  52. <aside className="alert-config__preview-panel">
  53. <div className="alert-config__widget">
  54. <div className="alert-config__widget-label">미리보기</div>
  55. <div className="alert-config__widget-frame">
  56. {showPreview && (
  57. <View
  58. key={previewKey}
  59. alert={fakeAlert}
  60. config={config}
  61. isAudioOnly={false}
  62. isVideoOnly={false}
  63. onComplete={handleComplete}
  64. />
  65. )}
  66. </div>
  67. </div>
  68. <fieldset className="alert-config__fieldset">
  69. <legend className="alert-config__legend">미리보기</legend>
  70. <div className="alert-config__preview-form">
  71. <div className="alert-config__field">
  72. <label htmlFor="preview-amount" className="alert-config__field-label">후원 금액 (원)</label>
  73. <input
  74. id="preview-amount"
  75. type="number"
  76. className="alert-config__input"
  77. min={DONATION_AMOUNT_MIN}
  78. max={DONATION_AMOUNT_MAX}
  79. step={DONATION_AMOUNT_STEP}
  80. value={previewAmount}
  81. onChange={e => setPreviewAmount(parseInt(e.target.value) || DONATION_AMOUNT_DEFAULT)}
  82. />
  83. </div>
  84. <div className="alert-config__field">
  85. <label htmlFor="preview-name" className="alert-config__field-label">이름</label>
  86. <input
  87. id="preview-name"
  88. type="text"
  89. className="alert-config__input"
  90. maxLength={ALERT_NAME_MAX_LENGTH}
  91. value={previewName}
  92. onChange={e => setPreviewName(e.target.value)}
  93. placeholder="후원자 이름"
  94. />
  95. </div>
  96. <div className="alert-config__field">
  97. <label htmlFor="preview-message" className="alert-config__field-label">보낼 내용</label>
  98. <input
  99. id="preview-message"
  100. type="text"
  101. className="alert-config__input"
  102. maxLength={ALERT_MESSAGE_MAX_LENGTH}
  103. value={previewMessage}
  104. onChange={e => setPreviewMessage(e.target.value)}
  105. placeholder="후원 메시지"
  106. />
  107. </div>
  108. <button
  109. type="button"
  110. className="alert-config__btn alert-config__btn--primary alert-config__preview-btn"
  111. onClick={handlePreview}
  112. >
  113. <FontAwesomeIcon icon={faPlay} />
  114. 미리보기
  115. </button>
  116. </div>
  117. </fieldset>
  118. </aside>
  119. );
  120. }