1.2.0
注目すべき点
バージョン番号については、
package.json
ファイルのversion
フィールドをご確認ください
価格管理でクーポン設定をサポート

実装された機能:
- Stripeで作成されたクーポンを取得
- 選択可能なクーポン
- Stripeで作成された商品価格を元の価格として表示し、現在の価格はクーポン適用後の計算値
- クーポンが設定されている場合、ユーザーが購入ボタンをクリックすると、手動入力なしでクーポンが自動適用される
- 手動クーポン入力購入エントリの表示オプション
更新手順
ステップ1:Supabase SQL Editorで以下のコマンドを実行してテーブルフィールドを追加
ALTER TABLE public.pricing_plans
ADD COLUMN stripe_coupon_id character varying(255) NULL,
ADD COLUMN enable_manual_input_coupon boolean DEFAULT false NOT NULL;
COMMENT ON COLUMN public.pricing_plans.stripe_coupon_id IS 'The ID of the Stripe coupon associated with this plan.';
ステップ2:コマンドを実行してSupabaseタイプを更新
supabase gen types typescript --project-id <your-project-id> --schema public > lib/supabase/types.ts
ステップ3:types/pricing.ts
定義を修正
types/pricing.ts
export interface PricingPlan {
// ...その他のコード...
stripe_coupon_id?: string | null; // 追加
enable_manual_input_coupon?: boolean; // 追加
}
ステップ4:actions/prices/admin.ts
の価格プラン作成メソッドを修正
actions/prices/admin.ts
export async function createPricingPlanAction({
planData,
locale = DEFAULT_LOCALE,
}: CreatePricingPlanParams) {
// ...その他のコード...
const { data, error } = await supabaseAdmin
.from("pricing_plans")
.insert({
// ...その他のコード...
stripe_coupon_id: planData.stripe_coupon_id,
enable_manual_input_coupon: planData.enable_manual_input_coupon ?? false,
})
// ...その他のコード...
}
ステップ5:/prices/PricePlanForm.tsx
を修正して新しい要件を拡張
app/[locale]/(protected)/dashboard/(admin)/prices/PricePlanForm.tsx
// 1. フォームタイプ定義を拡張
const pricingPlanFormSchema = z.object({
// ...その他のコード...
stripe_coupon_id: z.string().optional().nullable(),
enable_manual_input_coupon: z.boolean().optional().nullable(),
})
// 2. クーポン機能関連の状態を提供
const [isFetchingCoupons, setIsFetchingCoupons] = useState(false);
const [coupons, setCoupons] = useState<any[]>([]);
// 3. フォーム定義を拡張
const form = useForm<PricingPlanFormValues>({
resolver: zodResolver(pricingPlanFormSchema),
defaultValues: {
// ... その他のコード ...
stripe_coupon_id: initialData?.stripe_coupon_id ?? "",
enable_manual_input_coupon: initialData?.enable_manual_input_coupon ?? false,
}
})
// 4. stripe_coupon_idの変更を監視して表示価格を計算
const watchStripeCouponId = form.watch("stripe_coupon_id");
// 5. クーポン関連メソッドを追加
useEffect(() => {
// ソースコードを直接確認し、完全なメソッドをコピーしてください
}, [watchEnvironment]);
useEffect(() => {
// ソースコードを直接確認し、完全なメソッドをコピーしてください
}, [watchStripeCouponId, coupons]);
const handleFetchCoupons = async () => {
// ソースコードを直接確認し、完全なメソッドをコピーしてください
};
// 6. 表示価格と元の価格のカスタム表示ロジックを最適化
const handleStripeVerify = async () => {
// ... その他のコード ...
// 削除
// if (!form.getValues("display_price")) {
// const formattedPrice = await formatCurrency(
// priceInCorrectUnit,
// currency
// );
// form.setValue("display_price", formattedPrice, {
// shouldValidate: true,
// });
// }
// 追加
const formattedPrice = await formatCurrency(priceInCorrectUnit, currency);
form.setValue("original_price", formattedPrice, {
shouldValidate: true,
});
if (!form.getValues("display_price")) {
form.setValue("display_price", formattedPrice, {
shouldValidate: true,
});
}
// ... その他のコード ...
}
// 7. Stripe統合セクションにフォーム項目を追加
<FormField
control={form.control}
name="stripe_coupon_id"
render={({ field }) => (
/* ソースコードを直接確認し、完全なコンポーネントをコピーしてください */
)}
/>
{watchStripeCouponId && (
<FormField
control={form.control}
name="enable_manual_input_coupon"
render={({ field }) => (
/* ソースコードを直接確認し、完全なコンポーネントをコピーしてください */
)}
/>
)}
ステップ6:クーポンを取得する新しいAPIを追加
app/api/admin/stripe/coupons/route.ts
// ソースコードを直接確認し、完全なコードをコピーしてください
ステップ7:購入ボタンを修正して自動クーポン渡し機能を統合
components/home/PricingCTA.tsx
// 1. handleCheckoutを修正してクーポン機能をサポート
const handleCheckout = async (applyCoupon = true) => {
const stripePriceId = plan.stripe_price_id ?? null;
if (!stripePriceId) {
toast.error("Price ID is missing for this plan.");
return;
}
const couponCode = plan.stripe_coupon_id;
try {
const toltReferral = (window as any).tolt_referral;
const requestBody: {
priceId: string;
couponCode?: string;
referral?: string;
} = {
priceId: stripePriceId,
};
if (applyCoupon && couponCode) {
requestBody.couponCode = couponCode;
}
if (toltReferral) {
requestBody.referral = toltReferral;
}
const response = await fetch("/api/stripe/checkout-session", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept-Language": (locale || DEFAULT_LOCALE) as string,
},
body: JSON.stringify(requestBody),
});
// ... その他のコード ...
} catch (error) {
// ... その他のコード ...
}
}
// 2. ボタンを修正してクーポン機能をサポート
return (
<div>
<Button
asChild={!!plan.button_link}
disabled={isLoading}
// classNameを修正
className={`w-full flex items-center justify-center gap-2 text-white py-5 font-medium ${
plan.is_highlighted ? highlightedCtaStyle : defaultCtaStyle
} ${
plan.stripe_coupon_id && plan.enable_manual_input_coupon
? "mb-2"
: "mb-6"
}`}
{...(!plan.button_link && {
onClick: () => handleCheckout(),
})}
>
</Button>
/* 新しい購入エントリを追加 */
{plan.stripe_coupon_id && plan.enable_manual_input_coupon && (
<div className="text-center mb-2">
<button
onClick={() => handleCheckout(false)}
disabled={isLoading}
className="text-sm text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50 underline underline-offset-2"
>
I have a different coupon code
</button>
</div>
)}
</div>
);
新しいcredit_logs
テーブル
この変更は既存のユーザー権限アップグレード/ダウングレード処理メソッドに影響します。コードが1.2.0より前で、すでに有料ユーザーがいる場合は、credit_logs
テーブル関連機能を自分で実装する必要があります。製品がまだ公開されていない、または有料ユーザーがまだいない場合は、以下の手順に従ってコードをアップグレードしてください。

データベース設計
- 元のクレジット控除メソッドを削除:
DROP FUNCTION IF EXISTS public.upsert_and_increment_one_time_credits;
DROP FUNCTION IF EXISTS public.upsert_and_set_subscription_credits;
DROP FUNCTION IF EXISTS public.revoke_credits;
DROP FUNCTION IF EXISTS public.deduct_one_time_credits(uuid, integer);
DROP FUNCTION IF EXISTS public.deduct_subscription_credits(uuid, integer);
DROP FUNCTION IF EXISTS public.deduct_credits_priority_subscription(uuid, integer);
DROP FUNCTION IF EXISTS public.deduct_credits_priority_one_time(uuid, integer);
credit_logs
テーブルをクレジット変更のトランザクションログとして作成し、すべての変更を記録して完全な監査証跡を形成。支払い時のクレジット記録、機能使用時のクレジット控除、返金時のクレジット回復のための新しいRPCを作成。
ソースコードdata/8、credit_logs.sql
をご確認ください
- ローカルSupabaseタイプを更新
supabase gen types typescript --project-id <your-project-id> --schema public > lib/supabase/types.ts
- ユーザークレジット使用例ページとメソッドを更新
app/[locale]/(protected)/dashboard/credit-usage-example/page.tsx
actions/usage/deduct.ts
- webhookイベント処理ロジックを更新
この更新はカスタムユーザー権限アップグレード/ダウングレードメソッドに影響します。すでにカスタムメソッドを実装している場合は、同じアプローチに従って機能を改善できます。カスタムメソッドを修正していない場合は、lib/stripe/webhook-handlers.ts
を完全に上書きできます。
- 「クレジット履歴」ページを作成
新しいファイル:
actions/usage/logs.ts
app/[locale]/(protected)/dashboard/(user)/credit-history/*
i18n/en/CreditHistory.json
i18n/zh/CreditHistory.json
i18n/ja/CreditHistory.json
修正されたファイル:
i18n/request.ts
messages: {
CreditHistory: (await import(`./messages/${locale}/CreditHistory.json`)).default,
// ... その他のコード ...
}