Packages
phoenix_kit
1.7.41
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/modules/billing/web/provider_settings.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="{@project_title} Payment Providers"
current_path={@url_path}
project_title={@project_title}
>
<div class="container mx-auto px-4 py-6">
<%!-- Header --%>
<div class="flex items-center gap-4 mb-6">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing")}
class="btn btn-ghost btn-sm"
>
<.icon name="hero-arrow-left" class="w-4 h-4" />
</.link>
<div>
<h1 class="text-3xl font-bold">Payment Providers</h1>
<p class="text-base-content/60 mt-1">Configure online payment integrations</p>
</div>
</div>
<%!-- Navigation Tabs --%>
<div class="tabs tabs-boxed bg-base-200 p-1 mb-6">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/billing")}
class="tab"
>
<.icon name="hero-cog-6-tooth" class="w-4 h-4 mr-2" /> General
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/billing/providers")}
class="tab tab-active"
>
<.icon name="hero-credit-card" class="w-4 h-4 mr-2" /> Payment Providers
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/currencies")}
class="tab"
>
<.icon name="hero-currency-dollar" class="w-4 h-4 mr-2" /> Currencies
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/billing/plans")}
class="tab"
>
<.icon name="hero-clipboard-document-list" class="w-4 h-4 mr-2" /> Plans
</.link>
</div>
<%!-- Active Providers Summary --%>
<div class="alert alert-info mb-6">
<.icon name="hero-information-circle" class="w-5 h-5" />
<div>
<span class="font-medium">Active Providers:</span>
<%= if Enum.empty?(@available_providers) do %>
<span class="text-base-content/60">None configured</span>
<% else %>
<%= for {provider, index} <- Enum.with_index(@available_providers) do %>
<span class="badge badge-success badge-sm ml-1">
{provider |> Atom.to_string() |> String.capitalize()}
</span>
<%= if index < length(@available_providers) - 1 do %>
<span class="mx-1"></span>
<% end %>
<% end %>
<% end %>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6">
<%!-- Stripe Provider --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center">
<.icon name="hero-credit-card" class="w-6 h-6 text-primary" />
</div>
<div>
<h2 class="card-title text-lg">Stripe</h2>
<p class="text-xs text-base-content/60">Cards, Apple Pay, Google Pay</p>
</div>
</div>
<label class="cursor-pointer">
<input
type="checkbox"
class="toggle toggle-primary"
checked={@stripe_enabled}
phx-click="toggle_stripe"
/>
</label>
</div>
<div class="divider my-2"></div>
<form phx-submit="save_stripe" class="space-y-3">
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Secret Key</span>
<%= if has_credentials?(@stripe_secret_key) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="password"
name="secret_key"
placeholder="sk_live_..."
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Publishable Key</span>
<%= if has_credentials?(@stripe_publishable_key) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="text"
name="publishable_key"
placeholder="pk_live_..."
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Webhook Secret</span>
<%= if has_credentials?(@stripe_webhook_secret) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="password"
name="webhook_secret"
placeholder="whsec_..."
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Webhook URL</span>
</label>
<div class="join w-full">
<input
type="text"
value={@stripe_webhook_url}
class="input input-bordered input-sm font-mono join-item flex-1 text-xs"
readonly
/>
<button
type="button"
class="btn btn-sm join-item"
onclick={"navigator.clipboard.writeText('#{@stripe_webhook_url}')"}
title="Copy to clipboard"
>
<.icon name="hero-clipboard" class="w-4 h-4" />
</button>
</div>
</div>
<div class="card-actions justify-end pt-2">
<button type="submit" class="btn btn-primary btn-sm">Save Stripe</button>
</div>
</form>
</div>
</div>
<%!-- PayPal Provider --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg bg-info/10 flex items-center justify-center">
<.icon name="hero-currency-dollar" class="w-6 h-6 text-info" />
</div>
<div>
<h2 class="card-title text-lg">PayPal</h2>
<p class="text-xs text-base-content/60">PayPal, Venmo, Cards</p>
</div>
</div>
<label class="cursor-pointer">
<input
type="checkbox"
class="toggle toggle-info"
checked={@paypal_enabled}
phx-click="toggle_paypal"
/>
</label>
</div>
<div class="divider my-2"></div>
<form phx-submit="save_paypal" class="space-y-3">
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Mode</span>
</label>
<select name="mode" class="select select-bordered select-sm">
<option value="sandbox" selected={@paypal_mode == "sandbox"}>
Sandbox (Test)
</option>
<option value="live" selected={@paypal_mode == "live"}>Live (Production)</option>
</select>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Client ID</span>
<%= if has_credentials?(@paypal_client_id) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="text"
name="client_id"
placeholder="AW..."
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Client Secret</span>
<%= if has_credentials?(@paypal_client_secret) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="password"
name="client_secret"
placeholder="EL..."
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Webhook ID</span>
<%= if has_credentials?(@paypal_webhook_id) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="text"
name="webhook_id"
placeholder="WH-..."
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Webhook URL</span>
</label>
<div class="join w-full">
<input
type="text"
value={@paypal_webhook_url}
class="input input-bordered input-sm font-mono join-item flex-1 text-xs"
readonly
/>
<button
type="button"
class="btn btn-sm join-item"
onclick={"navigator.clipboard.writeText('#{@paypal_webhook_url}')"}
title="Copy to clipboard"
>
<.icon name="hero-clipboard" class="w-4 h-4" />
</button>
</div>
</div>
<div class="card-actions justify-end pt-2">
<button type="submit" class="btn btn-info btn-sm">Save PayPal</button>
</div>
</form>
</div>
</div>
<%!-- Razorpay Provider --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg bg-secondary/10 flex items-center justify-center">
<.icon name="hero-banknotes" class="w-6 h-6 text-secondary" />
</div>
<div>
<h2 class="card-title text-lg">Razorpay</h2>
<p class="text-xs text-base-content/60">India payments (UPI, Cards)</p>
</div>
</div>
<label class="cursor-pointer">
<input
type="checkbox"
class="toggle toggle-secondary"
checked={@razorpay_enabled}
phx-click="toggle_razorpay"
/>
</label>
</div>
<div class="divider my-2"></div>
<form phx-submit="save_razorpay" class="space-y-3">
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Key ID</span>
<%= if has_credentials?(@razorpay_key_id) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="text"
name="key_id"
placeholder="rzp_live_..."
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Key Secret</span>
<%= if has_credentials?(@razorpay_key_secret) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="password"
name="key_secret"
placeholder="••••••••••••"
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Webhook Secret</span>
<%= if has_credentials?(@razorpay_webhook_secret) do %>
<span class="label-text-alt text-success text-xs">
<.icon name="hero-check-circle" class="w-3 h-3 inline" /> Set
</span>
<% end %>
</label>
<input
type="password"
name="webhook_secret"
placeholder="••••••••••••"
class="input input-bordered input-sm font-mono"
autocomplete="off"
/>
</div>
<div class="form-control">
<label class="label py-1">
<span class="label-text text-xs">Webhook URL</span>
</label>
<div class="join w-full">
<input
type="text"
value={@razorpay_webhook_url}
class="input input-bordered input-sm font-mono join-item flex-1 text-xs"
readonly
/>
<button
type="button"
class="btn btn-sm join-item"
onclick={"navigator.clipboard.writeText('#{@razorpay_webhook_url}')"}
title="Copy to clipboard"
>
<.icon name="hero-clipboard" class="w-4 h-4" />
</button>
</div>
</div>
<div class="card-actions justify-end pt-2">
<button type="submit" class="btn btn-secondary btn-sm">Save Razorpay</button>
</div>
</form>
</div>
</div>
</div>
<%!-- Quick Help --%>
<div class="card bg-base-100 shadow-xl mt-6">
<div class="card-body">
<h2 class="card-title">Setup Instructions</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
<div class="bg-base-200 p-4 rounded-lg">
<h3 class="font-medium flex items-center gap-2">
<.icon name="hero-credit-card" class="w-5 h-5 text-primary" /> Stripe
</h3>
<ol class="text-sm text-base-content/70 mt-2 space-y-1 list-decimal list-inside">
<li>Create account at stripe.com</li>
<li>Get API keys from Dashboard → Developers</li>
<li>Create webhook with events: checkout.session.completed, payment_intent.*</li>
<li>Copy webhook signing secret</li>
</ol>
</div>
<div class="bg-base-200 p-4 rounded-lg">
<h3 class="font-medium flex items-center gap-2">
<.icon name="hero-currency-dollar" class="w-5 h-5 text-info" /> PayPal
</h3>
<ol class="text-sm text-base-content/70 mt-2 space-y-1 list-decimal list-inside">
<li>Create app at developer.paypal.com</li>
<li>Get Client ID and Secret</li>
<li>Configure webhook with events: CHECKOUT.ORDER.*, PAYMENT.*</li>
<li>Copy Webhook ID</li>
</ol>
</div>
<div class="bg-base-200 p-4 rounded-lg">
<h3 class="font-medium flex items-center gap-2">
<.icon name="hero-banknotes" class="w-5 h-5 text-secondary" /> Razorpay
</h3>
<ol class="text-sm text-base-content/70 mt-2 space-y-1 list-decimal list-inside">
<li>Create account at razorpay.com</li>
<li>Get Key ID and Secret from Settings → API Keys</li>
<li>Create webhook with events: payment.*, order.paid</li>
<li>Copy webhook secret</li>
</ol>
</div>
</div>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>