vindi-rails-engines 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd5650350d72f19ce46bb8299bfa0d8f367bb0b05f8156debfd2f44e36e895fe
4
- data.tar.gz: cd1aa4aba1b7adf14a2d0214b972d2d5ddf58ca045c8aff659e7bed0ee3d1e57
3
+ metadata.gz: 9347d8197d23330da13a6947dc28e853af29b1c4e52965b78f5c04c3b0fb729e
4
+ data.tar.gz: b792917b938b99f07396fc978afe55e3fbd982904e3026b215a12203a1567135
5
5
  SHA512:
6
- metadata.gz: 98320a6117259fc565010460295bf2c86b1710aa257831d94e8737e98fdc461506a85bff1915704a8f23cdbe8ee4b80066a8f65eaa79480b92bc00336de8af36
7
- data.tar.gz: b514be52d1dbdee74b80e1e9bbcaae154cd2d482130ea0f421eb910e7440f12ce157282d172559e29bed7335115d5e3a0040d58a7762cf19d155cb4bc3ce6e97
6
+ metadata.gz: f74ea0f2ad5b40797d60a5f3363389e87d5e5239e47b2c7df1464cfcec5925e12c51c4372b53c1cc2fe943d1debd19e2d049e5044f2c9302a71d043ef0a9b09a
7
+ data.tar.gz: ef3e03f46375f2221e2c9700c8e1396a7d4dfb8052c666f52e56d2f24118c47150a0417dbdb18c24ec176b7625cad96c34873e523c3689c2eafa986789908866
data/README.md CHANGED
@@ -23,7 +23,17 @@ This generates:
23
23
  - Checkout view form partial (`app/views/vindi/checkout/_form.html.erb`)
24
24
  - Stimulus controller (`app/javascript/controllers/vindi_checkout_controller.js`)
25
25
 
26
- ### 2. Environment Setup
26
+ ### 2. Rails Engine Dashboard
27
+ Mount the integration control panel in your host application routes:
28
+ ```ruby
29
+ # config/routes.rb
30
+ Rails.application.routes.draw do
31
+ mount Vindi::Engine => "/admin/vindi"
32
+ end
33
+ ```
34
+ This boots an administrative dashboard containing credentials mapping status, API connectivity diagnostic tools, and active Plan previews.
35
+
36
+ ### 3. Environment Setup
27
37
  Configure your public key in your environment file:
28
38
  ```bash
29
39
  ENV["VINDI_PUBLIC_KEY"] = "YOUR_PUBLIC_KEY"
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vindi
4
+ class DashboardController < ActionController::Base
5
+ layout "vindi/application"
6
+
7
+ def index
8
+ @api_key = Vindi.configuration.api_key
9
+ @api_url = Vindi.configuration.api_url
10
+ @cache_enabled = !Vindi.configuration.cache_store.nil?
11
+ @cache_ttl = Vindi.configuration.cache_ttl
12
+ @cached_resources = Vindi.configuration.cached_resources
13
+
14
+ fetch_plans_for_dashboard
15
+ end
16
+
17
+ def test_connection
18
+ Vindi::Plan.list(per_page: 1)
19
+ render json: { status: "success", message: "Successfully connected to Vindi API!" }
20
+ rescue => e
21
+ render json: { status: "error", message: e.message }
22
+ end
23
+
24
+ private
25
+
26
+ def fetch_plans_for_dashboard
27
+ if @api_key
28
+ @plans = Vindi::Plan.list(per_page: 5)
29
+ @connection_status = "Connected"
30
+ else
31
+ @connection_status = "Not Configured"
32
+ @plans = []
33
+ end
34
+ rescue => e
35
+ @connection_status = "Error: #{e.message}"
36
+ @plans = []
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,199 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Vindi Rails Engine Dashboard</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ :root {
12
+ --bg-color: #0b0f19;
13
+ --card-bg: #111827;
14
+ --border-color: #1f2937;
15
+ --text-main: #f3f4f6;
16
+ --text-muted: #9ca3af;
17
+ --primary: #3b82f6;
18
+ --primary-hover: #2563eb;
19
+ --success: #10b981;
20
+ --danger: #ef4444;
21
+ --warning: #f59e0b;
22
+ }
23
+
24
+ * {
25
+ box-sizing: border-box;
26
+ margin: 0;
27
+ padding: 0;
28
+ }
29
+
30
+ body {
31
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
32
+ background-color: var(--bg-color);
33
+ color: var(--text-main);
34
+ line-height: 1.5;
35
+ padding: 2rem 1rem;
36
+ }
37
+
38
+ .container {
39
+ max-width: 1000px;
40
+ margin: 0 auto;
41
+ }
42
+
43
+ header {
44
+ display: flex;
45
+ justify-content: space-between;
46
+ align-items: center;
47
+ margin-bottom: 2.5rem;
48
+ border-bottom: 1px solid var(--border-color);
49
+ padding-bottom: 1.5rem;
50
+ }
51
+
52
+ .brand {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 0.75rem;
56
+ }
57
+
58
+ .logo-icon {
59
+ background: linear-gradient(135deg, var(--primary), #8b5cf6);
60
+ width: 40px;
61
+ height: 40px;
62
+ border-radius: 8px;
63
+ display: flex;
64
+ align-items: center;
65
+ justify-content: center;
66
+ font-weight: 700;
67
+ color: #fff;
68
+ font-size: 1.25rem;
69
+ }
70
+
71
+ h1 {
72
+ font-size: 1.5rem;
73
+ font-weight: 700;
74
+ letter-spacing: -0.025em;
75
+ }
76
+
77
+ .badge {
78
+ display: inline-flex;
79
+ align-items: center;
80
+ padding: 0.25rem 0.75rem;
81
+ border-radius: 9999px;
82
+ font-size: 0.875rem;
83
+ font-weight: 600;
84
+ }
85
+
86
+ .badge-success {
87
+ background-color: rgba(16, 185, 129, 0.1);
88
+ color: var(--success);
89
+ border: 1px solid rgba(16, 185, 129, 0.2);
90
+ }
91
+
92
+ .badge-danger {
93
+ background-color: rgba(239, 68, 68, 0.1);
94
+ color: var(--danger);
95
+ border: 1px solid rgba(239, 68, 68, 0.2);
96
+ }
97
+
98
+ .badge-warning {
99
+ background-color: rgba(245, 158, 11, 0.1);
100
+ color: var(--warning);
101
+ border: 1px solid rgba(245, 158, 11, 0.2);
102
+ }
103
+
104
+ .btn {
105
+ display: inline-flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ padding: 0.625rem 1.25rem;
109
+ border-radius: 6px;
110
+ font-size: 0.875rem;
111
+ font-weight: 600;
112
+ border: none;
113
+ cursor: pointer;
114
+ transition: all 0.2s ease;
115
+ text-decoration: none;
116
+ }
117
+
118
+ .btn-primary {
119
+ background-color: var(--primary);
120
+ color: #fff;
121
+ }
122
+
123
+ .btn-primary:hover {
124
+ background-color: var(--primary-hover);
125
+ }
126
+
127
+ .grid {
128
+ display: grid;
129
+ grid-template-columns: 1fr;
130
+ gap: 1.5rem;
131
+ margin-bottom: 2rem;
132
+ }
133
+
134
+ @media (min-width: 768px) {
135
+ .grid {
136
+ grid-template-columns: 1fr 1fr;
137
+ }
138
+ }
139
+
140
+ .card {
141
+ background-color: var(--card-bg);
142
+ border: 1px solid var(--border-color);
143
+ border-radius: 12px;
144
+ padding: 1.5rem;
145
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
146
+ }
147
+
148
+ .card-title {
149
+ font-size: 1.1rem;
150
+ font-weight: 600;
151
+ margin-bottom: 1.25rem;
152
+ color: var(--text-main);
153
+ display: flex;
154
+ justify-content: space-between;
155
+ align-items: center;
156
+ }
157
+
158
+ .footer {
159
+ text-align: center;
160
+ margin-top: 4rem;
161
+ color: var(--text-muted);
162
+ font-size: 0.875rem;
163
+ }
164
+
165
+ .footer a {
166
+ color: var(--primary);
167
+ text-decoration: none;
168
+ }
169
+
170
+ .toast {
171
+ position: fixed;
172
+ bottom: 2rem;
173
+ right: 2rem;
174
+ padding: 1rem 1.5rem;
175
+ border-radius: 8px;
176
+ background-color: var(--card-bg);
177
+ border: 1px solid var(--border-color);
178
+ color: var(--text-main);
179
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
180
+ display: none;
181
+ align-items: center;
182
+ gap: 0.75rem;
183
+ z-index: 50;
184
+ animation: slideIn 0.3s ease;
185
+ }
186
+
187
+ @keyframes slideIn {
188
+ from { transform: translateY(1rem); opacity: 0; }
189
+ to { transform: translateY(0); opacity: 1; }
190
+ }
191
+ </style>
192
+ <%= csrf_meta_tags %>
193
+ </head>
194
+ <body>
195
+ <div class="container">
196
+ <%= yield %>
197
+ </div>
198
+ </body>
199
+ </html>
@@ -0,0 +1,175 @@
1
+ <header>
2
+ <div class="brand">
3
+ <div class="logo-icon">V</div>
4
+ <div>
5
+ <h1>Vindi Integration Dashboard</h1>
6
+ <p style="color: var(--text-muted); font-size: 0.875rem;">Configure and monitor your Vindi subscriptions engine</p>
7
+ </div>
8
+ </div>
9
+ <div>
10
+ <% if @connection_status == "Connected" %>
11
+ <span class="badge badge-success">● API Connected</span>
12
+ <% elsif @connection_status == "Not Configured" %>
13
+ <span class="badge badge-warning">● Configuration Missing</span>
14
+ <% else %>
15
+ <span class="badge badge-danger" title="<%= @connection_status %>">● API Connection Error</span>
16
+ <% end %>
17
+ </div>
18
+ </header>
19
+
20
+ <div class="grid">
21
+ <!-- Config Card -->
22
+ <div class="card">
23
+ <div class="card-title">SDK Configuration</div>
24
+ <div style="display: flex; flex-direction: column; gap: 0.75rem;">
25
+ <div style="display: flex; justify-content: space-between; border-bottom: 1px solid var(--border-color); padding-bottom: 0.5rem;">
26
+ <span style="color: var(--text-muted); font-size: 0.9rem;">API Endpoint</span>
27
+ <span style="font-family: monospace; font-size: 0.875rem;"><%= @api_url || 'Not Set' %></span>
28
+ </div>
29
+ <div style="display: flex; justify-content: space-between; border-bottom: 1px solid var(--border-color); padding-bottom: 0.5rem;">
30
+ <span style="color: var(--text-muted); font-size: 0.9rem;">API Key</span>
31
+ <span style="font-family: monospace; font-size: 0.875rem;">
32
+ <%= @api_key ? "#{@api_key[0...4]}••••••••#{@api_key[-4..-1] || ''}" : 'Not Set' %>
33
+ </span>
34
+ </div>
35
+ <div style="display: flex; justify-content: space-between; border-bottom: 1px solid var(--border-color); padding-bottom: 0.5rem;">
36
+ <span style="color: var(--text-muted); font-size: 0.9rem;">Cache Store</span>
37
+ <span>
38
+ <% if @cache_enabled %>
39
+ <span class="badge badge-success" style="font-size: 0.75rem;">Enabled</span>
40
+ <% else %>
41
+ <span class="badge badge-warning" style="font-size: 0.75rem;">Disabled</span>
42
+ <% end %>
43
+ </span>
44
+ </div>
45
+ <% if @cache_enabled %>
46
+ <div style="display: flex; justify-content: space-between; border-bottom: 1px solid var(--border-color); padding-bottom: 0.5rem;">
47
+ <span style="color: var(--text-muted); font-size: 0.9rem;">Cache TTL</span>
48
+ <span style="font-size: 0.9rem;"><%= @cache_ttl %> seconds</span>
49
+ </div>
50
+ <% end %>
51
+ </div>
52
+ </div>
53
+
54
+ <!-- Actions Card -->
55
+ <div class="card">
56
+ <div class="card-title">Diagnostics & Tools</div>
57
+ <p style="color: var(--text-muted); font-size: 0.9rem; margin-bottom: 1.5rem;">
58
+ Test the connectivity of your credentials to the Vindi API endpoints in real-time.
59
+ </p>
60
+ <div>
61
+ <button class="btn btn-primary" id="btn-test-conn" onclick="runDiagnostics()">
62
+ Verify Connectivity
63
+ </button>
64
+ </div>
65
+ </div>
66
+ </div>
67
+
68
+ <!-- Plans Section -->
69
+ <div class="card" style="margin-bottom: 2rem;">
70
+ <div class="card-title">
71
+ Vindi Active Plans
72
+ <span style="font-size: 0.8rem; font-weight: normal; color: var(--text-muted);">Showing last 5 plans</span>
73
+ </div>
74
+
75
+ <% if @plans && @plans.any? %>
76
+ <div style="overflow-x: auto;">
77
+ <table style="width: 100%; border-collapse: collapse; text-align: left;">
78
+ <thead>
79
+ <tr style="border-bottom: 2px solid var(--border-color); color: var(--text-muted); font-size: 0.875rem;">
80
+ <th style="padding: 0.75rem 0.5rem;">ID</th>
81
+ <th style="padding: 0.75rem 0.5rem;">Plan Name</th>
82
+ <th style="padding: 0.75rem 0.5rem;">Code</th>
83
+ <th style="padding: 0.75rem 0.5rem;">Interval</th>
84
+ <th style="padding: 0.75rem 0.5rem;">Status</th>
85
+ </tr>
86
+ </thead>
87
+ <tbody>
88
+ <% @plans.each do |plan| %>
89
+ <tr style="border-bottom: 1px solid var(--border-color); font-size: 0.9rem;">
90
+ <td style="padding: 0.75rem 0.5rem; font-family: monospace;"><%= plan.id %></td>
91
+ <td style="padding: 0.75rem 0.5rem; font-weight: 500;"><%= plan.name %></td>
92
+ <td style="padding: 0.75rem 0.5rem; font-family: monospace; color: var(--text-muted);"><%= plan.code %></td>
93
+ <td style="padding: 0.75rem 0.5rem;"><%= plan.interval_count %> <%= plan.interval %></td>
94
+ <td style="padding: 0.75rem 0.5rem;">
95
+ <% if plan.respond_to?(:status) && plan.status == 'active' %>
96
+ <span class="badge badge-success" style="font-size: 0.75rem; padding: 0.125rem 0.5rem;">Active</span>
97
+ <% else %>
98
+ <span class="badge badge-warning" style="font-size: 0.75rem; padding: 0.125rem 0.5rem;"><%= plan.respond_to?(:status) ? plan.status : 'Active' %></span>
99
+ <% end %>
100
+ </td>
101
+ </tr>
102
+ <% end %>
103
+ </tbody>
104
+ </table>
105
+ </div>
106
+ <% else %>
107
+ <div style="text-align: center; padding: 2rem 0; color: var(--text-muted);">
108
+ <% if @connection_status == "Connected" %>
109
+ No plans found on this merchant account.
110
+ <% else %>
111
+ Unable to load plans. Check configuration details or connection status.
112
+ <% end %>
113
+ </div>
114
+ <% end %>
115
+ </div>
116
+
117
+ <div class="footer">
118
+ Powered by <a href="https://github.com/wesleyskap/vindi-rails" target="_blank">vindi-rails-engines v<%= Vindi::Engines::VERSION %></a>
119
+ </div>
120
+
121
+ <!-- Toast Container -->
122
+ <div id="diagnostics-toast" class="toast">
123
+ <span id="toast-icon" style="font-size: 1.25rem;"></span>
124
+ <span id="toast-message">Testing...</span>
125
+ </div>
126
+
127
+ <script>
128
+ function runDiagnostics() {
129
+ const btn = document.getElementById('btn-test-conn');
130
+ const toast = document.getElementById('diagnostics-toast');
131
+ const msg = document.getElementById('toast-message');
132
+ const icon = document.getElementById('toast-icon');
133
+
134
+ btn.disabled = true;
135
+ btn.innerText = 'Verifying...';
136
+
137
+ // Show toast loader
138
+ msg.innerText = 'Testing connection to Vindi API...';
139
+ icon.innerText = '🔄';
140
+ toast.style.display = 'flex';
141
+ toast.style.borderColor = 'var(--border-color)';
142
+
143
+ fetch('<%= test_connection_path %>', {
144
+ method: 'POST',
145
+ headers: {
146
+ 'Content-Type': 'application/json',
147
+ 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
148
+ }
149
+ })
150
+ .then(response => response.json())
151
+ .then(data => {
152
+ if (data.status === 'success') {
153
+ icon.innerText = '✅';
154
+ toast.style.borderColor = 'var(--success)';
155
+ msg.innerText = data.message;
156
+ } else {
157
+ icon.innerText = '❌';
158
+ toast.style.borderColor = 'var(--danger)';
159
+ msg.innerText = 'Failed: ' + data.message;
160
+ }
161
+ })
162
+ .catch(error => {
163
+ icon.innerText = '❌';
164
+ toast.style.borderColor = 'var(--danger)';
165
+ msg.innerText = 'Connection Error: ' + error.message;
166
+ })
167
+ .finally(() => {
168
+ btn.disabled = false;
169
+ btn.innerText = 'Verify Connectivity';
170
+ setTimeout(() => {
171
+ toast.style.display = 'none';
172
+ }, 4000);
173
+ });
174
+ }
175
+ </script>
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ Vindi::Engine.routes.draw do
4
+ get "/", to: "dashboard#index", as: :dashboard
5
+ post "/test_connection", to: "dashboard#test_connection"
6
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Vindi
4
4
  module Engines
5
- VERSION = "0.1.1"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vindi-rails-engines
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wesley Lima
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-10 00:00:00.000000000 Z
11
+ date: 2026-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: vindi-rails
@@ -75,6 +75,10 @@ extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
77
  - README.md
78
+ - app/controllers/vindi/dashboard_controller.rb
79
+ - app/views/layouts/vindi/application.html.erb
80
+ - app/views/vindi/dashboard/index.html.erb
81
+ - config/routes.rb
78
82
  - lib/generators/vindi/checkout_generator.rb
79
83
  - lib/generators/vindi/templates/_form.html.erb
80
84
  - lib/generators/vindi/templates/checkout_controller.js