django-cfg 1.2.27__py3-none-any.whl → 1.2.31__py3-none-any.whl

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.
Files changed (138) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/payments/admin/__init__.py +3 -2
  3. django_cfg/apps/payments/admin/balance_admin.py +18 -18
  4. django_cfg/apps/payments/admin/currencies_admin.py +319 -131
  5. django_cfg/apps/payments/admin/payments_admin.py +15 -4
  6. django_cfg/apps/payments/config/module.py +2 -2
  7. django_cfg/apps/payments/config/utils.py +2 -2
  8. django_cfg/apps/payments/decorators.py +2 -2
  9. django_cfg/apps/payments/management/commands/README.md +95 -127
  10. django_cfg/apps/payments/management/commands/currency_stats.py +5 -24
  11. django_cfg/apps/payments/management/commands/manage_currencies.py +229 -0
  12. django_cfg/apps/payments/management/commands/manage_providers.py +235 -0
  13. django_cfg/apps/payments/managers/__init__.py +3 -2
  14. django_cfg/apps/payments/managers/balance_manager.py +2 -2
  15. django_cfg/apps/payments/managers/currency_manager.py +272 -49
  16. django_cfg/apps/payments/managers/payment_manager.py +161 -13
  17. django_cfg/apps/payments/middleware/api_access.py +2 -2
  18. django_cfg/apps/payments/middleware/rate_limiting.py +8 -18
  19. django_cfg/apps/payments/middleware/usage_tracking.py +20 -17
  20. django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +241 -0
  21. django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +30 -0
  22. django_cfg/apps/payments/models/__init__.py +3 -2
  23. django_cfg/apps/payments/models/currencies.py +187 -71
  24. django_cfg/apps/payments/models/payments.py +3 -2
  25. django_cfg/apps/payments/serializers/__init__.py +3 -2
  26. django_cfg/apps/payments/serializers/currencies.py +20 -12
  27. django_cfg/apps/payments/services/cache/simple_cache.py +2 -2
  28. django_cfg/apps/payments/services/core/balance_service.py +2 -2
  29. django_cfg/apps/payments/services/core/fallback_service.py +2 -2
  30. django_cfg/apps/payments/services/core/payment_service.py +3 -6
  31. django_cfg/apps/payments/services/core/subscription_service.py +4 -7
  32. django_cfg/apps/payments/services/internal_types.py +171 -7
  33. django_cfg/apps/payments/services/monitoring/api_schemas.py +58 -204
  34. django_cfg/apps/payments/services/monitoring/provider_health.py +2 -2
  35. django_cfg/apps/payments/services/providers/base.py +144 -43
  36. django_cfg/apps/payments/services/providers/cryptapi/__init__.py +4 -0
  37. django_cfg/apps/payments/services/providers/cryptapi/config.py +8 -0
  38. django_cfg/apps/payments/services/providers/cryptapi/models.py +192 -0
  39. django_cfg/apps/payments/services/providers/cryptapi/provider.py +439 -0
  40. django_cfg/apps/payments/services/providers/cryptomus/__init__.py +4 -0
  41. django_cfg/apps/payments/services/providers/cryptomus/models.py +176 -0
  42. django_cfg/apps/payments/services/providers/cryptomus/provider.py +429 -0
  43. django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +564 -0
  44. django_cfg/apps/payments/services/providers/models/__init__.py +34 -0
  45. django_cfg/apps/payments/services/providers/models/currencies.py +190 -0
  46. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +4 -0
  47. django_cfg/apps/payments/services/providers/nowpayments/models.py +196 -0
  48. django_cfg/apps/payments/services/providers/nowpayments/provider.py +380 -0
  49. django_cfg/apps/payments/services/providers/registry.py +294 -11
  50. django_cfg/apps/payments/services/providers/stripe/__init__.py +4 -0
  51. django_cfg/apps/payments/services/providers/stripe/models.py +184 -0
  52. django_cfg/apps/payments/services/providers/stripe/provider.py +109 -0
  53. django_cfg/apps/payments/services/security/error_handler.py +6 -8
  54. django_cfg/apps/payments/services/security/payment_notifications.py +2 -2
  55. django_cfg/apps/payments/services/security/webhook_validator.py +3 -4
  56. django_cfg/apps/payments/signals/api_key_signals.py +2 -2
  57. django_cfg/apps/payments/signals/payment_signals.py +11 -5
  58. django_cfg/apps/payments/signals/subscription_signals.py +2 -2
  59. django_cfg/apps/payments/static/payments/css/payments.css +340 -0
  60. django_cfg/apps/payments/static/payments/js/notifications.js +202 -0
  61. django_cfg/apps/payments/static/payments/js/payment-utils.js +318 -0
  62. django_cfg/apps/payments/static/payments/js/theme.js +86 -0
  63. django_cfg/apps/payments/tasks/webhook_processing.py +2 -2
  64. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +50 -0
  65. django_cfg/apps/payments/templates/payments/base.html +182 -0
  66. django_cfg/apps/payments/templates/payments/components/payment_card.html +201 -0
  67. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +109 -0
  68. django_cfg/apps/payments/templates/payments/components/progress_bar.html +43 -0
  69. django_cfg/apps/payments/templates/payments/components/provider_stats.html +40 -0
  70. django_cfg/apps/payments/templates/payments/components/status_badge.html +34 -0
  71. django_cfg/apps/payments/templates/payments/components/status_overview.html +148 -0
  72. django_cfg/apps/payments/templates/payments/dashboard.html +258 -0
  73. django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +35 -0
  74. django_cfg/apps/payments/templates/payments/payment_create.html +579 -0
  75. django_cfg/apps/payments/templates/payments/payment_detail.html +373 -0
  76. django_cfg/apps/payments/templates/payments/payment_list.html +354 -0
  77. django_cfg/apps/payments/templates/payments/stats.html +261 -0
  78. django_cfg/apps/payments/templates/payments/test.html +213 -0
  79. django_cfg/apps/payments/templatetags/__init__.py +1 -0
  80. django_cfg/apps/payments/templatetags/payments_tags.py +315 -0
  81. django_cfg/apps/payments/urls.py +3 -1
  82. django_cfg/apps/payments/urls_admin.py +58 -0
  83. django_cfg/apps/payments/utils/__init__.py +1 -3
  84. django_cfg/apps/payments/utils/billing_utils.py +2 -2
  85. django_cfg/apps/payments/utils/config_utils.py +2 -8
  86. django_cfg/apps/payments/utils/validation_utils.py +2 -2
  87. django_cfg/apps/payments/views/__init__.py +3 -2
  88. django_cfg/apps/payments/views/currency_views.py +31 -20
  89. django_cfg/apps/payments/views/payment_views.py +2 -2
  90. django_cfg/apps/payments/views/templates/__init__.py +25 -0
  91. django_cfg/apps/payments/views/templates/ajax.py +451 -0
  92. django_cfg/apps/payments/views/templates/base.py +212 -0
  93. django_cfg/apps/payments/views/templates/dashboard.py +60 -0
  94. django_cfg/apps/payments/views/templates/payment_detail.py +102 -0
  95. django_cfg/apps/payments/views/templates/payment_management.py +158 -0
  96. django_cfg/apps/payments/views/templates/qr_code.py +174 -0
  97. django_cfg/apps/payments/views/templates/stats.py +244 -0
  98. django_cfg/apps/payments/views/templates/utils.py +181 -0
  99. django_cfg/apps/payments/views/webhook_views.py +2 -2
  100. django_cfg/apps/payments/viewsets.py +3 -2
  101. django_cfg/apps/tasks/urls.py +0 -2
  102. django_cfg/apps/tasks/urls_admin.py +14 -0
  103. django_cfg/apps/urls.py +6 -3
  104. django_cfg/core/config.py +35 -0
  105. django_cfg/models/payments.py +2 -8
  106. django_cfg/modules/django_currency/__init__.py +16 -11
  107. django_cfg/modules/django_currency/clients/__init__.py +4 -4
  108. django_cfg/modules/django_currency/clients/coinpaprika_client.py +289 -0
  109. django_cfg/modules/django_currency/clients/yahoo_client.py +157 -0
  110. django_cfg/modules/django_currency/core/__init__.py +1 -7
  111. django_cfg/modules/django_currency/core/converter.py +18 -23
  112. django_cfg/modules/django_currency/core/models.py +122 -11
  113. django_cfg/modules/django_currency/database/__init__.py +4 -4
  114. django_cfg/modules/django_currency/database/database_loader.py +190 -309
  115. django_cfg/modules/django_unfold/dashboard.py +7 -2
  116. django_cfg/registry/core.py +1 -0
  117. django_cfg/template_archive/.gitignore +1 -0
  118. django_cfg/template_archive/django_sample.zip +0 -0
  119. django_cfg/templates/admin/components/action_grid.html +9 -9
  120. django_cfg/templates/admin/components/metric_card.html +5 -5
  121. django_cfg/templates/admin/components/status_badge.html +2 -2
  122. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +152 -24
  123. django_cfg/templates/admin/snippets/components/quick_actions.html +3 -3
  124. django_cfg/templates/admin/snippets/components/system_health.html +1 -1
  125. django_cfg/templates/admin/snippets/tabs/overview_tab.html +49 -52
  126. {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/METADATA +13 -18
  127. {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/RECORD +130 -83
  128. django_cfg/apps/payments/management/commands/populate_currencies.py +0 -246
  129. django_cfg/apps/payments/management/commands/update_currencies.py +0 -336
  130. django_cfg/apps/payments/services/providers/cryptapi.py +0 -273
  131. django_cfg/apps/payments/services/providers/cryptomus.py +0 -310
  132. django_cfg/apps/payments/services/providers/nowpayments.py +0 -293
  133. django_cfg/apps/payments/services/validators/__init__.py +0 -8
  134. django_cfg/modules/django_currency/clients/coingecko_client.py +0 -257
  135. django_cfg/modules/django_currency/clients/yfinance_client.py +0 -246
  136. {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/WHEEL +0 -0
  137. {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/entry_points.txt +0 -0
  138. {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/licenses/LICENSE +0 -0
@@ -3,14 +3,14 @@ Payment System Notification Service
3
3
  Uses existing django_telegram and django_email modules for admin notifications.
4
4
  """
5
5
 
6
- import logging
6
+ from django_cfg.modules.django_logger import get_logger
7
7
  from typing import Dict, Any, Optional
8
8
  from django.utils import timezone
9
9
  from django_cfg.modules.django_telegram import DjangoTelegram
10
10
  from django_cfg.modules.django_email import DjangoEmailService
11
11
  from django_cfg.core.config import get_current_config
12
12
 
13
- logger = logging.getLogger(__name__)
13
+ logger = get_logger("payment_notifications")
14
14
  config = get_current_config()
15
15
 
16
16
 
@@ -6,7 +6,7 @@ Critical Foundation Security Component.
6
6
  import json
7
7
  import hmac
8
8
  import hashlib
9
- import logging
9
+ from django_cfg.modules.django_logger import get_logger
10
10
  import time
11
11
  from typing import Dict, Any, Optional, Tuple
12
12
  from datetime import datetime, timedelta
@@ -16,8 +16,9 @@ from django.conf import settings
16
16
 
17
17
  from django_cfg.apps.payments.config import get_payments_config
18
18
  from django_cfg.apps.payments.models.events import PaymentEvent
19
+ from ...models.payments import UniversalPayment
19
20
 
20
- logger = logging.getLogger(__name__)
21
+ logger = get_logger("webhook_validator")
21
22
 
22
23
 
23
24
  class WebhookValidator:
@@ -400,8 +401,6 @@ class WebhookValidator:
400
401
 
401
402
  CRITICAL: Prevents webhooks for unknown addresses.
402
403
  """
403
- from ..models.payments import UniversalPayment
404
-
405
404
  try:
406
405
  # Check if address exists in our payments
407
406
  return UniversalPayment.objects.filter(
@@ -10,12 +10,12 @@ from django.dispatch import receiver
10
10
  from django.contrib.auth import get_user_model
11
11
  from django.db import transaction
12
12
  from django.utils import timezone
13
- import logging
13
+ from django_cfg.modules.django_logger import get_logger
14
14
 
15
15
  from ..models import APIKey
16
16
 
17
17
  User = get_user_model()
18
- logger = logging.getLogger(__name__)
18
+ logger = get_logger("api_key_signals")
19
19
 
20
20
 
21
21
  @receiver(post_save, sender=User)
@@ -8,13 +8,13 @@ from django.db.models.signals import post_save, pre_save
8
8
  from django.dispatch import receiver
9
9
  from django.db import transaction
10
10
  from django.utils import timezone
11
- import logging
11
+ from django_cfg.modules.django_logger import get_logger
12
12
 
13
13
  from ..models import UniversalPayment, UserBalance, Transaction
14
14
  from ..services.cache import SimpleCache
15
- from django_cfg.core.redis import RedisService
15
+ from django.core.cache import cache
16
16
 
17
- logger = logging.getLogger(__name__)
17
+ logger = get_logger("payment_signals")
18
18
 
19
19
 
20
20
  @receiver(pre_save, sender=UniversalPayment)
@@ -92,8 +92,14 @@ def _process_completed_payment(payment: UniversalPayment):
92
92
 
93
93
  # Clear Redis cache for user
94
94
  try:
95
- redis_service = RedisService()
96
- redis_service.invalidate_user_cache(payment.user.id)
95
+ # Invalidate user cache using Django cache
96
+ user_cache_pattern = f"payments:user:{payment.user.id}:*"
97
+ # Note: Django cache doesn't support pattern deletion, so we clear specific keys
98
+ cache.delete_many([
99
+ f"payments:user:{payment.user.id}:balance",
100
+ f"payments:user:{payment.user.id}:api_keys",
101
+ f"payments:user:{payment.user.id}:subscriptions"
102
+ ])
97
103
  except Exception as e:
98
104
  logger.warning(f"Failed to clear Redis cache for user {payment.user.id}: {e}")
99
105
 
@@ -9,12 +9,12 @@ from django.dispatch import receiver
9
9
  from django.db import transaction
10
10
  from django.utils import timezone
11
11
  from datetime import timedelta
12
- import logging
12
+ from django_cfg.modules.django_logger import get_logger
13
13
 
14
14
  from ..models import Subscription, EndpointGroup, UserBalance, Transaction
15
15
  from ..services.cache import SimpleCache
16
16
 
17
- logger = logging.getLogger(__name__)
17
+ logger = get_logger("subscription_signals")
18
18
 
19
19
 
20
20
  @receiver(pre_save, sender=Subscription)
@@ -0,0 +1,340 @@
1
+ /* Payment System Styles */
2
+
3
+ /* Payment Status Colors */
4
+ .payment-status-pending { @apply bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200; }
5
+ .payment-status-confirming { @apply bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200; }
6
+ .payment-status-confirmed { @apply bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200; }
7
+ .payment-status-completed { @apply bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200; }
8
+ .payment-status-failed { @apply bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200; }
9
+ .payment-status-expired { @apply bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200; }
10
+ .payment-status-cancelled { @apply bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200; }
11
+ .payment-status-refunded { @apply bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200; }
12
+
13
+ /* Payment Card Animations */
14
+ .payment-card {
15
+ @apply transition-all duration-200 hover:shadow-lg hover:-translate-y-1;
16
+ }
17
+
18
+ .payment-card:hover {
19
+ @apply ring-2 ring-blue-500 ring-opacity-50;
20
+ }
21
+
22
+ .payment-card.compact {
23
+ @apply p-4;
24
+ }
25
+
26
+ /* Progress Bar Styles */
27
+ .progress-bar {
28
+ @apply w-full bg-gray-200 rounded-full h-2 dark:bg-gray-700 overflow-hidden;
29
+ }
30
+
31
+ .progress-fill {
32
+ @apply bg-blue-600 h-2 rounded-full transition-all duration-500 ease-out;
33
+ }
34
+
35
+ .progress-fill.success {
36
+ @apply bg-green-600;
37
+ }
38
+
39
+ .progress-fill.warning {
40
+ @apply bg-yellow-600;
41
+ }
42
+
43
+ .progress-fill.danger {
44
+ @apply bg-red-600;
45
+ }
46
+
47
+ /* Progress Steps */
48
+ .progress-steps {
49
+ @apply flex justify-between items-center mb-4;
50
+ }
51
+
52
+ .progress-step {
53
+ @apply flex flex-col items-center text-center;
54
+ }
55
+
56
+ .progress-step.completed .step-icon {
57
+ @apply text-green-500;
58
+ }
59
+
60
+ .progress-step.active .step-icon {
61
+ @apply text-blue-500;
62
+ }
63
+
64
+ .step-label {
65
+ @apply text-xs text-gray-500 dark:text-gray-400 mt-1;
66
+ }
67
+
68
+ .step-icon {
69
+ @apply w-8 h-8 flex items-center justify-center rounded-full border-2 border-gray-300 dark:border-gray-600 mb-2;
70
+ }
71
+
72
+ .step-icon.completed {
73
+ @apply border-green-500 bg-green-500 text-white;
74
+ }
75
+
76
+ .step-icon.active {
77
+ @apply border-blue-500 bg-blue-500 text-white;
78
+ }
79
+
80
+ /* Real-time indicators */
81
+ .payment-live-indicator {
82
+ @apply inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800;
83
+ }
84
+
85
+ .payment-live-indicator::before {
86
+ content: '';
87
+ @apply w-2 h-2 bg-green-500 rounded-full mr-2 animate-pulse;
88
+ }
89
+
90
+ /* Status Overview Cards */
91
+ .status-overview {
92
+ @apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8;
93
+ }
94
+
95
+ .status-card {
96
+ @apply bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-6 transition-all duration-200 hover:shadow-md;
97
+ }
98
+
99
+ .status-card:hover {
100
+ @apply transform scale-105;
101
+ }
102
+
103
+ /* Payment Table Styles */
104
+ .payments-table {
105
+ @apply min-w-full divide-y divide-gray-200 dark:divide-gray-700;
106
+ }
107
+
108
+ .payments-table th {
109
+ @apply px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider;
110
+ }
111
+
112
+ .payments-table td {
113
+ @apply px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white;
114
+ }
115
+
116
+ .payments-table tr:hover {
117
+ @apply bg-gray-50 dark:bg-gray-800;
118
+ }
119
+
120
+ /* Provider Icons */
121
+ .provider-icon {
122
+ @apply w-6 h-6 rounded;
123
+ }
124
+
125
+ .provider-icon.nowpayments {
126
+ @apply bg-orange-500;
127
+ }
128
+
129
+ .provider-icon.cryptapi {
130
+ @apply bg-blue-500;
131
+ }
132
+
133
+ .provider-icon.cryptomus {
134
+ @apply bg-purple-500;
135
+ }
136
+
137
+ .provider-icon.stripe {
138
+ @apply bg-indigo-500;
139
+ }
140
+
141
+ .provider-icon.internal {
142
+ @apply bg-gray-500;
143
+ }
144
+
145
+ /* QR Code Styles */
146
+ .qr-code-container {
147
+ @apply flex flex-col items-center space-y-2 p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700;
148
+ }
149
+
150
+ .qr-code {
151
+ @apply w-32 h-32 bg-gray-100 dark:bg-gray-700 rounded flex items-center justify-center;
152
+ }
153
+
154
+ /* Filter Styles */
155
+ .payment-filters {
156
+ @apply bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-6 mb-6;
157
+ }
158
+
159
+ .filter-group {
160
+ @apply flex flex-wrap gap-4 items-center;
161
+ }
162
+
163
+ .filter-input {
164
+ @apply min-w-0 flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white;
165
+ }
166
+
167
+ .filter-select {
168
+ @apply px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white;
169
+ }
170
+
171
+ /* Button Styles */
172
+ .btn {
173
+ @apply inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md transition-colors duration-200;
174
+ }
175
+
176
+ .btn-primary {
177
+ @apply bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2;
178
+ }
179
+
180
+ .btn-secondary {
181
+ @apply bg-gray-600 text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2;
182
+ }
183
+
184
+ .btn-success {
185
+ @apply bg-green-600 text-white hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2;
186
+ }
187
+
188
+ .btn-danger {
189
+ @apply bg-red-600 text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2;
190
+ }
191
+
192
+ .btn-outline {
193
+ @apply border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600;
194
+ }
195
+
196
+ .btn-sm {
197
+ @apply px-3 py-1.5 text-xs;
198
+ }
199
+
200
+ .btn-lg {
201
+ @apply px-6 py-3 text-base;
202
+ }
203
+
204
+ /* Modal Styles */
205
+ .modal-overlay {
206
+ @apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50;
207
+ }
208
+
209
+ .modal-content {
210
+ @apply bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full mx-4 max-h-screen overflow-y-auto;
211
+ }
212
+
213
+ .modal-header {
214
+ @apply px-6 py-4 border-b border-gray-200 dark:border-gray-700;
215
+ }
216
+
217
+ .modal-body {
218
+ @apply px-6 py-4;
219
+ }
220
+
221
+ .modal-footer {
222
+ @apply px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end space-x-3;
223
+ }
224
+
225
+ /* Notification Styles */
226
+ .notification {
227
+ @apply max-w-sm w-full bg-white dark:bg-gray-800 shadow-lg rounded-lg pointer-events-auto ring-1 ring-black ring-opacity-5 overflow-hidden;
228
+ }
229
+
230
+ .notification.success {
231
+ @apply border-l-4 border-green-500;
232
+ }
233
+
234
+ .notification.error {
235
+ @apply border-l-4 border-red-500;
236
+ }
237
+
238
+ .notification.warning {
239
+ @apply border-l-4 border-yellow-500;
240
+ }
241
+
242
+ .notification.info {
243
+ @apply border-l-4 border-blue-500;
244
+ }
245
+
246
+ /* Responsive improvements */
247
+ @media (max-width: 768px) {
248
+ .payment-card {
249
+ @apply p-4;
250
+ }
251
+
252
+ .status-overview {
253
+ @apply grid-cols-2 gap-4;
254
+ }
255
+
256
+ .progress-steps {
257
+ @apply hidden;
258
+ }
259
+
260
+ .filter-group {
261
+ @apply flex-col items-stretch;
262
+ }
263
+
264
+ .payments-table {
265
+ @apply text-xs;
266
+ }
267
+
268
+ .payments-table th,
269
+ .payments-table td {
270
+ @apply px-3 py-2;
271
+ }
272
+ }
273
+
274
+ @media (max-width: 480px) {
275
+ .status-overview {
276
+ @apply grid-cols-1;
277
+ }
278
+ }
279
+
280
+ /* Loading animations */
281
+ .skeleton {
282
+ @apply animate-pulse bg-gray-200 dark:bg-gray-700 rounded;
283
+ }
284
+
285
+ .skeleton-text {
286
+ @apply h-4 bg-gray-200 dark:bg-gray-700 rounded;
287
+ }
288
+
289
+ .skeleton-text.w-1/4 {
290
+ @apply w-1/4;
291
+ }
292
+
293
+ .skeleton-text.w-1/2 {
294
+ @apply w-1/2;
295
+ }
296
+
297
+ .skeleton-text.w-3/4 {
298
+ @apply w-3/4;
299
+ }
300
+
301
+ /* Chart styles */
302
+ .chart-container {
303
+ @apply bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-6;
304
+ }
305
+
306
+ .chart-legend {
307
+ @apply flex justify-center space-x-6 mt-4;
308
+ }
309
+
310
+ .chart-legend-item {
311
+ @apply flex items-center space-x-2;
312
+ }
313
+
314
+ .chart-legend-color {
315
+ @apply w-3 h-3 rounded-full;
316
+ }
317
+
318
+ /* Dark mode adjustments */
319
+ @media (prefers-color-scheme: dark) {
320
+ .material-icons {
321
+ color: inherit;
322
+ }
323
+ }
324
+
325
+ /* Custom scrollbar */
326
+ .custom-scrollbar::-webkit-scrollbar {
327
+ width: 6px;
328
+ }
329
+
330
+ .custom-scrollbar::-webkit-scrollbar-track {
331
+ @apply bg-gray-100 dark:bg-gray-800;
332
+ }
333
+
334
+ .custom-scrollbar::-webkit-scrollbar-thumb {
335
+ @apply bg-gray-400 dark:bg-gray-600 rounded-full;
336
+ }
337
+
338
+ .custom-scrollbar::-webkit-scrollbar-thumb:hover {
339
+ @apply bg-gray-500 dark:bg-gray-500;
340
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Notification System for Payment Dashboard
3
+ * Handles toast notifications with auto-dismiss and styling
4
+ */
5
+
6
+ class NotificationManager {
7
+ constructor() {
8
+ this.container = this.getOrCreateContainer();
9
+ this.notifications = new Map();
10
+ this.defaultDuration = 5000; // 5 seconds
11
+ }
12
+
13
+ getOrCreateContainer() {
14
+ let container = document.getElementById('notification-container');
15
+ if (!container) {
16
+ container = document.createElement('div');
17
+ container.id = 'notification-container';
18
+ container.className = 'fixed top-4 left-1/2 transform -translate-x-1/2 z-50 space-y-2';
19
+ document.body.appendChild(container);
20
+ }
21
+ return container;
22
+ }
23
+
24
+ show(message, type = 'info', options = {}) {
25
+ const id = this.generateId();
26
+ const duration = options.duration || this.defaultDuration;
27
+ const persistent = options.persistent || false;
28
+
29
+ const notification = this.createNotificationElement(id, message, type, persistent);
30
+ this.container.appendChild(notification);
31
+ this.notifications.set(id, notification);
32
+
33
+ // Animate in
34
+ requestAnimationFrame(() => {
35
+ notification.classList.add('animate-in');
36
+ });
37
+
38
+ // Auto-dismiss if not persistent
39
+ if (!persistent) {
40
+ setTimeout(() => {
41
+ this.dismiss(id);
42
+ }, duration);
43
+ }
44
+
45
+ return id;
46
+ }
47
+
48
+ createNotificationElement(id, message, type, persistent) {
49
+ const notification = document.createElement('div');
50
+ notification.id = `notification-${id}`;
51
+ notification.className = `notification ${type} transform transition-all duration-300 translate-y-2 opacity-0`;
52
+
53
+ const typeIcons = {
54
+ success: 'check_circle',
55
+ error: 'error',
56
+ warning: 'warning',
57
+ info: 'info'
58
+ };
59
+
60
+ const typeColors = {
61
+ success: 'text-green-600',
62
+ error: 'text-red-600',
63
+ warning: 'text-yellow-600',
64
+ info: 'text-blue-600'
65
+ };
66
+
67
+ notification.innerHTML = `
68
+ <div class="p-4">
69
+ <div class="flex">
70
+ <div class="flex-shrink-0">
71
+ <span class="material-icons ${typeColors[type]}">${typeIcons[type]}</span>
72
+ </div>
73
+ <div class="ml-3 w-0 flex-1">
74
+ <p class="text-sm font-medium text-gray-900 dark:text-white">
75
+ ${this.escapeHtml(message)}
76
+ </p>
77
+ </div>
78
+ ${!persistent ? `
79
+ <div class="ml-4 flex-shrink-0 flex">
80
+ <button class="dismiss-btn bg-white dark:bg-gray-800 rounded-md inline-flex text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" onclick="window.notificationManager.dismiss('${id}')">
81
+ <span class="sr-only">Close</span>
82
+ <span class="material-icons text-sm">close</span>
83
+ </button>
84
+ </div>
85
+ ` : ''}
86
+ </div>
87
+ </div>
88
+ `;
89
+
90
+ // Add CSS class for animation
91
+ notification.style.setProperty('--tw-translate-y', '0.5rem');
92
+
93
+ return notification;
94
+ }
95
+
96
+ dismiss(id) {
97
+ const notification = this.notifications.get(id);
98
+ if (!notification) return;
99
+
100
+ // Animate out
101
+ notification.classList.add('animate-out');
102
+ notification.style.setProperty('--tw-translate-y', '-0.5rem');
103
+ notification.style.opacity = '0';
104
+
105
+ setTimeout(() => {
106
+ if (notification.parentNode) {
107
+ notification.parentNode.removeChild(notification);
108
+ }
109
+ this.notifications.delete(id);
110
+ }, 300);
111
+ }
112
+
113
+ dismissAll() {
114
+ this.notifications.forEach((notification, id) => {
115
+ this.dismiss(id);
116
+ });
117
+ }
118
+
119
+ // Convenience methods
120
+ success(message, options = {}) {
121
+ return this.show(message, 'success', options);
122
+ }
123
+
124
+ error(message, options = {}) {
125
+ return this.show(message, 'error', options);
126
+ }
127
+
128
+ warning(message, options = {}) {
129
+ return this.show(message, 'warning', options);
130
+ }
131
+
132
+ info(message, options = {}) {
133
+ return this.show(message, 'info', options);
134
+ }
135
+
136
+ // Payment-specific notifications
137
+ paymentCreated(paymentId) {
138
+ return this.success(`Payment #${paymentId} created successfully`);
139
+ }
140
+
141
+ paymentCompleted(paymentId) {
142
+ return this.success(`Payment #${paymentId} completed!`);
143
+ }
144
+
145
+ paymentFailed(paymentId, reason = '') {
146
+ const message = `Payment #${paymentId} failed${reason ? ': ' + reason : ''}`;
147
+ return this.error(message);
148
+ }
149
+
150
+ paymentCancelled(paymentId) {
151
+ return this.warning(`Payment #${paymentId} cancelled`);
152
+ }
153
+
154
+ connectionStatus(connected) {
155
+ if (connected) {
156
+ return this.success('Connected to payment system', { duration: 3000 });
157
+ } else {
158
+ return this.error('Connection lost', { persistent: true });
159
+ }
160
+ }
161
+
162
+ // Utility methods
163
+ generateId() {
164
+ return Math.random().toString(36).substr(2, 9);
165
+ }
166
+
167
+ escapeHtml(text) {
168
+ const map = {
169
+ '&': '&amp;',
170
+ '<': '&lt;',
171
+ '>': '&gt;',
172
+ '"': '&quot;',
173
+ "'": '&#039;'
174
+ };
175
+ return text.replace(/[&<>"']/g, (m) => map[m]);
176
+ }
177
+ }
178
+
179
+ // Add CSS animations dynamically
180
+ const style = document.createElement('style');
181
+ style.textContent = `
182
+ .notification.animate-in {
183
+ transform: translateY(0);
184
+ opacity: 1;
185
+ }
186
+
187
+ .notification.animate-out {
188
+ transform: translateY(-0.5rem);
189
+ opacity: 0;
190
+ }
191
+ `;
192
+ document.head.appendChild(style);
193
+
194
+ // Initialize notification manager when DOM is loaded
195
+ document.addEventListener('DOMContentLoaded', () => {
196
+ window.notificationManager = new NotificationManager();
197
+ });
198
+
199
+ // Export for use in other modules
200
+ if (typeof module !== 'undefined' && module.exports) {
201
+ module.exports = NotificationManager;
202
+ }