+
+
プラン設定
+
テナントの料金プランを変更できます。
+
+ {/* 編集不可の場合の説明をページ上部に1箇所のみ表示 */}
+ {!canEdit() && (
+
+
+
+
+
+ 編集制限中: 変更予定が10分以内のため、プラン設定・解除・予約取り消しができません。
+
+
+
+
+ )}
+
+
+ {/* 現在のプラン情報 */}
+
+
+
現在のプラン
+ {/* プラン解除ボタン: SaaSus Platformと同じ制御 */}
+ {cancelButtonIsVisible() && canEdit() && (
+
+ )}
+
+
+
+ 現在のプラン:
+ {currentPlan?.display_name || "未設定"}
+
+
+ 現在の税率:
+
+ {tenantInfo?.tax_rate_id
+ ? getTaxRateDisplayName(tenantInfo.tax_rate_id)
+ : "未設定"
+ }
+
+
+ {/* 予約情報の表示 */}
+ {tenantInfo?.plan_reservation && (
+ <>
+
+
+
+
プラン変更予約
+ {/* 予約取り消しボタン: SaaSus Platformと同じ制御 */}
+ {deleteScheduleButtonIsVisible() && canEdit() && (
+
+ )}
+
+
+
+ 予約プラン:
+ {getPlanDisplayName(tenantInfo.plan_reservation.next_plan_id || "")}
+
+
+ 変更予定日時:
+
+ {tenantInfo.plan_reservation.using_next_plan_from
+ ? new Date(tenantInfo.plan_reservation.using_next_plan_from * 1000).toLocaleString('ja-JP')
+ : "未設定"
+ }
+
+
+
+ 変更予定税率:
+
+ {tenantInfo.plan_reservation.next_plan_tax_rate_id
+ ? getTaxRateDisplayName(tenantInfo.plan_reservation.next_plan_tax_rate_id)
+ : "未設定"
+ }
+
+
+
+
+
+ >
+ )}
+
+
+
+ {/* プラン変更フォーム */}
+
+
+
プラン変更
+
+
+
+ {/* プラン選択 */}
+
+
+
+
+
+ {/* 税率選択 */}
+
+
+
+
+
+ {/* 反映日 */}
+
+
+
+
+
+
+
+ {usingNextPlanFrom === "custom" && (
+
+
{
+ const selectedDate = e.target.value;
+
+ // ユーザーが入力を開始したらエラーメッセージをクリア
+ setDateValidationError("");
+
+ const fiveMinutesLater = new Date(Date.now() + PLAN_SETTINGS_CONSTANTS.DELAYS.MIN_DATETIME_MINUTES * 60 * 1000);
+ const minDateString = formatToDateTimeLocal(fiveMinutesLater);
+
+ // 選択された日時が5分後より前の場合は5分後に設定
+ if (selectedDate < minDateString) {
+ setCustomDate(minDateString);
+ setDateValidationError(`5分後の日時より前は選択できません。${minDateString}に設定しました。`);
+ } else {
+ setCustomDate(selectedDate);
+ }
+ }}
+ onBlur={(e) => {
+ const selectedDate = e.target.value;
+ const fiveMinutesLater = new Date(Date.now() + PLAN_SETTINGS_CONSTANTS.DELAYS.MIN_DATETIME_MINUTES * 60 * 1000);
+ const minDateString = formatToDateTimeLocal(fiveMinutesLater);
+
+ // フォーカスが外れた時にもバリデーション(テキスト入力時用)
+ if (selectedDate && selectedDate < minDateString) {
+ setCustomDate(minDateString);
+ setDateValidationError(`5分後の日時より前は選択できません。${minDateString}に設定しました。`);
+ }
+ }}
+ min={formatToDateTimeLocal(new Date(Date.now() + PLAN_SETTINGS_CONSTANTS.DELAYS.MIN_DATETIME_MINUTES * 60 * 1000))}
+ disabled={!canEdit()}
+ className={`w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
+ !canEdit() ? 'bg-gray-100 cursor-not-allowed' : ''
+ }`}
+ />
+ {dateValidationError && (
+
+ {dateValidationError}
+
+ )}
+
+ )}
+
+
+ {/* ボタン */}
+
+
+
+
+
+
+
+ {/* 確認モーダル */}
+ {showConfirmModal && (
+
+
+
+ プラン変更の確認
+
+
+
+ 新しいプラン:
+ {getPlanDisplayName(selectedPlanId)}
+
+ {selectedTaxRateId && (
+
+ 税率:
+ {getTaxRateDisplayName(selectedTaxRateId)}
+
+ )}
+
+ 反映日:
+ {usingNextPlanFrom === "immediate"
+ ? PLAN_SETTINGS_CONSTANTS.UI.IMMEDIATE_LABEL
+ : `${PLAN_SETTINGS_CONSTANTS.UI.CUSTOM_LABEL}(${customDate})`
+ }
+
+
+
+
+
+
+
+
+ )}
+
+ {/* 完了モーダル */}
+ {showCompletedModal && (
+
+
+
+ プラン変更完了
+
+
+ {PLAN_SETTINGS_CONSTANTS.MESSAGES.PLAN_UPDATE_SUCCESS}
+ {usingNextPlanFrom === "immediate"
+ ? "5分後に新しいプランが適用されます。"
+ : `指定した日時に新しいプランが適用されます。`
+ }
+
+
+
+
+
+
+ )}
+
+ {/* プラン解除確認モーダル */}
+ {showCancelModal && (
+
+
+
+ プラン解除の確認
+
+
+ プランを解除すると、5分後に現在のプランが利用できなくなります。
+ 本当に解除しますか?
+
+
+
+
+
+
+
+ )}
+
+ {/* 予約取り消し確認モーダル */}
+ {showReservationCancelModal && (
+
+
+
+ 予約取り消しの確認
+
+
+ プラン変更予約を取り消しますか?
+ 取り消すと、現在のプランが継続されます。
+
+
+
+
+
+
+
+ )}
+
+ {/* エラーダイアログ */}
+
+
+ );
+};
+
+export default PlanSettings;
\ No newline at end of file
diff --git a/src/pages/TenantList.tsx b/src/pages/TenantList.tsx
index 1f98f06..218cf93 100644
--- a/src/pages/TenantList.tsx
+++ b/src/pages/TenantList.tsx
@@ -2,7 +2,7 @@ import axios from "axios";
import { useEffect, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { API_ENDPOINT } from "../const";
-import { idTokenCheck, handleUserListClick } from "../utils";
+import { idTokenCheck, navigateToUserPageByRole } from "../utils";
import { Tenant, UserInfo, TenantAttributesResponse } from "../types";
// テナント属性の値を適切にフォーマットする関数
@@ -111,7 +111,7 @@ const TenantList = () => {
|
|