eid-salami 1.0.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.
Files changed (65) hide show
  1. package/DEPLOY.md +199 -0
  2. package/README.md +133 -0
  3. package/backend/.env.example +25 -0
  4. package/backend/.keystone_temp/admin/next.config.js +14 -0
  5. package/backend/.keystone_temp/admin/pages/_app.js +22 -0
  6. package/backend/.keystone_temp/admin/pages/index.js +1 -0
  7. package/backend/.keystone_temp/admin/pages/init.js +5 -0
  8. package/backend/.keystone_temp/admin/pages/no-access.js +3 -0
  9. package/backend/.keystone_temp/admin/pages/orders/[id].js +3 -0
  10. package/backend/.keystone_temp/admin/pages/orders/create.js +3 -0
  11. package/backend/.keystone_temp/admin/pages/orders/index.js +3 -0
  12. package/backend/.keystone_temp/admin/pages/salami-packages/[id].js +3 -0
  13. package/backend/.keystone_temp/admin/pages/salami-packages/create.js +3 -0
  14. package/backend/.keystone_temp/admin/pages/salami-packages/index.js +3 -0
  15. package/backend/.keystone_temp/admin/pages/signin.js +3 -0
  16. package/backend/.keystone_temp/admin/pages/users/[id].js +3 -0
  17. package/backend/.keystone_temp/admin/pages/users/create.js +3 -0
  18. package/backend/.keystone_temp/admin/pages/users/index.js +3 -0
  19. package/backend/.keystone_temp/admin/public/favicon.ico +0 -0
  20. package/backend/.keystone_temp/config.js +369 -0
  21. package/backend/.keystone_temp/config.js.map +7 -0
  22. package/backend/bkash/bkash.service.ts +184 -0
  23. package/backend/keystone/routes.ts +193 -0
  24. package/backend/keystone/schema.ts +143 -0
  25. package/backend/keystone.ts +54 -0
  26. package/backend/package.json +23 -0
  27. package/backend/schema.graphql +530 -0
  28. package/backend/schema.prisma +55 -0
  29. package/backend/seed.ts +53 -0
  30. package/backend/tsconfig.json +15 -0
  31. package/frontend/.env.example +6 -0
  32. package/frontend/index.html +16 -0
  33. package/frontend/package.json +24 -0
  34. package/frontend/src/App.js +11 -0
  35. package/frontend/src/App.tsx +22 -0
  36. package/frontend/src/api/client.js +11 -0
  37. package/frontend/src/api/client.ts +57 -0
  38. package/frontend/src/components/Footer.js +5 -0
  39. package/frontend/src/components/Footer.module.css +27 -0
  40. package/frontend/src/components/Footer.tsx +13 -0
  41. package/frontend/src/components/Navbar.js +6 -0
  42. package/frontend/src/components/Navbar.module.css +54 -0
  43. package/frontend/src/components/Navbar.tsx +16 -0
  44. package/frontend/src/components/PackageCard.js +5 -0
  45. package/frontend/src/components/PackageCard.module.css +64 -0
  46. package/frontend/src/components/PackageCard.tsx +24 -0
  47. package/frontend/src/main.js +7 -0
  48. package/frontend/src/main.tsx +13 -0
  49. package/frontend/src/pages/HomePage.js +31 -0
  50. package/frontend/src/pages/HomePage.module.css +416 -0
  51. package/frontend/src/pages/HomePage.tsx +146 -0
  52. package/frontend/src/pages/OrderPage.js +98 -0
  53. package/frontend/src/pages/OrderPage.module.css +624 -0
  54. package/frontend/src/pages/OrderPage.tsx +221 -0
  55. package/frontend/src/pages/PaymentCallbackPage.js +25 -0
  56. package/frontend/src/pages/PaymentCallbackPage.module.css +38 -0
  57. package/frontend/src/pages/PaymentCallbackPage.tsx +37 -0
  58. package/frontend/src/pages/PaymentResultPage.js +28 -0
  59. package/frontend/src/pages/PaymentResultPage.module.css +182 -0
  60. package/frontend/src/pages/PaymentResultPage.tsx +92 -0
  61. package/frontend/src/styles/global.css +66 -0
  62. package/frontend/src/vite-env.d.ts +5 -0
  63. package/frontend/tsconfig.json +15 -0
  64. package/frontend/vite.config.ts +15 -0
  65. package/package.json +14 -0
@@ -0,0 +1,624 @@
1
+ .page {
2
+ min-height: calc(100vh - 68px);
3
+ background: linear-gradient(180deg, #f5f0e8 0%, var(--cream) 60%);
4
+ padding: 3rem clamp(1rem, 5vw, 4rem) 5rem;
5
+ }
6
+
7
+ .container {
8
+ max-width: 860px;
9
+ margin: 0 auto;
10
+ }
11
+
12
+ .title {
13
+ font-family: var(--font-bengali);
14
+ font-size: clamp(1.8rem, 3vw, 2.4rem);
15
+ color: var(--emerald);
16
+ font-weight: 700;
17
+ text-align: center;
18
+ margin-bottom: 2.5rem;
19
+ }
20
+
21
+ /* Progress */
22
+ .progress {
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ gap: 0;
27
+ margin-bottom: 2.5rem;
28
+ }
29
+
30
+ .progressItem {
31
+ display: flex;
32
+ align-items: center;
33
+ gap: 0.5rem;
34
+ opacity: 0.4;
35
+ transition: opacity 0.3s;
36
+ }
37
+
38
+ .progressItem.active { opacity: 1; }
39
+
40
+ .progressDot {
41
+ width: 32px;
42
+ height: 32px;
43
+ border-radius: 50%;
44
+ border: 2px solid var(--gold);
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ font-size: 0.8rem;
49
+ font-weight: 700;
50
+ color: var(--gold);
51
+ background: var(--white);
52
+ transition: all 0.3s;
53
+ }
54
+
55
+ .progressItem.active .progressDot {
56
+ background: var(--gold);
57
+ color: var(--white);
58
+ }
59
+
60
+ .progressLabel {
61
+ font-family: var(--font-bengali);
62
+ font-size: 0.85rem;
63
+ font-weight: 600;
64
+ color: var(--emerald);
65
+ white-space: nowrap;
66
+ }
67
+
68
+ .progressLine {
69
+ width: 60px;
70
+ height: 2px;
71
+ background: rgba(200,153,26,0.2);
72
+ margin: 0 0.5rem;
73
+ transition: background 0.3s;
74
+ }
75
+
76
+ .progressLine.lineDone { background: var(--gold); }
77
+
78
+ /* Panel */
79
+ .stepPanel {
80
+ background: var(--white);
81
+ border-radius: 20px;
82
+ padding: clamp(1.5rem, 4vw, 2.5rem);
83
+ box-shadow: 0 4px 40px rgba(0,0,0,0.07);
84
+ animation: fadeUp 0.35s ease;
85
+ }
86
+
87
+ @keyframes fadeUp {
88
+ from { opacity: 0; transform: translateY(16px); }
89
+ to { opacity: 1; transform: translateY(0); }
90
+ }
91
+
92
+ .stepHeading {
93
+ font-family: var(--font-bengali);
94
+ font-size: 1.4rem;
95
+ color: var(--emerald);
96
+ font-weight: 700;
97
+ margin-bottom: 1.8rem;
98
+ }
99
+
100
+ /* Packages grid */
101
+ .packagesGrid {
102
+ display: grid;
103
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
104
+ gap: 1rem;
105
+ margin-bottom: 2rem;
106
+ }
107
+
108
+ /* Form */
109
+ .formGrid {
110
+ display: grid;
111
+ grid-template-columns: 1fr 1fr;
112
+ gap: 2rem;
113
+ margin-bottom: 1.5rem;
114
+ }
115
+
116
+ @media (max-width: 620px) {
117
+ .formGrid { grid-template-columns: 1fr; }
118
+ .progressLine { width: 30px; }
119
+ }
120
+
121
+ .formSection {
122
+ display: flex;
123
+ flex-direction: column;
124
+ gap: 1rem;
125
+ }
126
+
127
+ .formSectionTitle {
128
+ font-family: var(--font-bengali);
129
+ font-size: 1rem;
130
+ font-weight: 700;
131
+ color: var(--emerald);
132
+ padding-bottom: 0.5rem;
133
+ border-bottom: 2px solid rgba(200,153,26,0.15);
134
+ }
135
+
136
+ .label {
137
+ display: flex;
138
+ flex-direction: column;
139
+ gap: 0.4rem;
140
+ font-family: var(--font-bengali);
141
+ font-size: 0.88rem;
142
+ font-weight: 600;
143
+ color: var(--text-mid);
144
+ }
145
+
146
+ .input,
147
+ .textarea {
148
+ padding: 0.7rem 1rem;
149
+ border: 1.5px solid rgba(0,0,0,0.1);
150
+ border-radius: var(--radius-sm);
151
+ font-size: 0.95rem;
152
+ transition: border-color 0.2s, box-shadow 0.2s;
153
+ background: #fafaf8;
154
+ width: 100%;
155
+ }
156
+
157
+ .input:focus,
158
+ .textarea:focus {
159
+ border-color: var(--gold);
160
+ box-shadow: 0 0 0 3px rgba(200,153,26,0.12);
161
+ }
162
+
163
+ .textarea { resize: vertical; font-family: var(--font-bengali); }
164
+
165
+ /* Confirm card */
166
+ .confirmCard {
167
+ border: 1.5px solid rgba(200,153,26,0.2);
168
+ border-radius: var(--radius);
169
+ overflow: hidden;
170
+ margin-bottom: 1.5rem;
171
+ }
172
+
173
+ .confirmHeader {
174
+ display: flex;
175
+ align-items: center;
176
+ gap: 1rem;
177
+ padding: 1.2rem 1.5rem;
178
+ background: linear-gradient(135deg, var(--emerald), var(--emerald-light));
179
+ }
180
+
181
+ .confirmEmoji { font-size: 2.5rem; }
182
+
183
+ .confirmPackageName {
184
+ font-family: var(--font-bengali);
185
+ font-size: 1rem;
186
+ color: var(--gold-pale);
187
+ font-weight: 600;
188
+ }
189
+
190
+ .confirmAmount {
191
+ font-family: var(--font-display);
192
+ font-size: 1.8rem;
193
+ font-weight: 700;
194
+ color: var(--gold-bright);
195
+ }
196
+
197
+ .confirmDetails {
198
+ padding: 1.2rem 1.5rem;
199
+ display: flex;
200
+ flex-direction: column;
201
+ gap: 0.8rem;
202
+ }
203
+
204
+ .confirmRow {
205
+ display: flex;
206
+ justify-content: space-between;
207
+ align-items: flex-start;
208
+ gap: 1rem;
209
+ font-size: 0.9rem;
210
+ color: var(--text-mid);
211
+ padding-bottom: 0.8rem;
212
+ border-bottom: 1px solid rgba(0,0,0,0.05);
213
+ }
214
+
215
+ .confirmRow strong {
216
+ color: var(--text-dark);
217
+ text-align: right;
218
+ font-family: var(--font-bengali);
219
+ }
220
+
221
+ .total {
222
+ font-weight: 700;
223
+ font-size: 1rem;
224
+ color: var(--emerald) !important;
225
+ border-bottom: none !important;
226
+ }
227
+
228
+ .total strong { color: var(--gold) !important; font-size: 1.1rem; }
229
+
230
+ .bkashBadge {
231
+ padding: 0.9rem 1.5rem;
232
+ background: #f0faf4;
233
+ border-top: 1px solid rgba(0,153,68,0.15);
234
+ font-family: var(--font-bengali);
235
+ font-size: 0.9rem;
236
+ font-weight: 600;
237
+ color: #007a40;
238
+ display: flex;
239
+ align-items: center;
240
+ gap: 0.5rem;
241
+ }
242
+
243
+ /* Navigation buttons */
244
+ .navBtns {
245
+ display: flex;
246
+ justify-content: space-between;
247
+ gap: 1rem;
248
+ margin-top: 1.5rem;
249
+ }
250
+
251
+ .btnNext,
252
+ .btnPay {
253
+ font-family: var(--font-bengali);
254
+ font-size: 1rem;
255
+ font-weight: 700;
256
+ padding: 0.85rem 2rem;
257
+ border-radius: 100px;
258
+ transition: all 0.2s;
259
+ }
260
+
261
+ .btnNext {
262
+ color: var(--white);
263
+ background: linear-gradient(135deg, var(--emerald-light), var(--emerald));
264
+ box-shadow: 0 4px 16px rgba(13,59,46,0.3);
265
+ margin-left: auto;
266
+ }
267
+
268
+ .btnNext:hover:not(:disabled) {
269
+ transform: translateY(-2px);
270
+ box-shadow: 0 8px 24px rgba(13,59,46,0.35);
271
+ }
272
+
273
+ .btnNext:disabled {
274
+ opacity: 0.4;
275
+ cursor: not-allowed;
276
+ }
277
+
278
+ .btnPay {
279
+ color: var(--white);
280
+ background: linear-gradient(135deg, #009944, #00c55a);
281
+ box-shadow: 0 4px 16px rgba(0,153,68,0.35);
282
+ flex: 1;
283
+ }
284
+
285
+ .btnPay:hover:not(:disabled) {
286
+ transform: translateY(-2px);
287
+ box-shadow: 0 8px 24px rgba(0,153,68,0.45);
288
+ }
289
+
290
+ .btnPay:disabled { opacity: 0.6; cursor: not-allowed; }
291
+
292
+ .btnBack {
293
+ font-family: var(--font-bengali);
294
+ font-size: 0.95rem;
295
+ color: var(--text-light);
296
+ background: none;
297
+ padding: 0.85rem 1.2rem;
298
+ border-radius: 100px;
299
+ transition: all 0.2s;
300
+ border: 1.5px solid rgba(0,0,0,0.1);
301
+ }
302
+
303
+ .btnBack:hover {
304
+ background: rgba(0,0,0,0.04);
305
+ color: var(--text-dark);
306
+ }
307
+
308
+ .secureNote {
309
+ text-align: center;
310
+ font-size: 0.8rem;
311
+ color: var(--text-light);
312
+ margin-top: 1rem;
313
+ }
314
+
315
+ .error {
316
+ color: var(--rose);
317
+ font-family: var(--font-bengali);
318
+ font-size: 0.88rem;
319
+ background: #fef2f2;
320
+ border: 1px solid #fecaca;
321
+ border-radius: var(--radius-sm);
322
+ padding: 0.6rem 1rem;
323
+ margin-top: 0.5rem;
324
+ }
325
+
326
+ .loader {
327
+ font-family: var(--font-bengali);
328
+ text-align: center;
329
+ color: var(--text-light);
330
+ padding: 3rem;
331
+ }
332
+
333
+ /* ── bKash Instructions Card ─────────────────────────────────────────────── */
334
+ .bkashInstructions {
335
+ background: linear-gradient(135deg, #f0faf4, #e8f7ef);
336
+ border: 1.5px solid rgba(0, 153, 68, 0.2);
337
+ border-radius: var(--radius);
338
+ overflow: hidden;
339
+ margin-bottom: 1.5rem;
340
+ }
341
+
342
+ .bkashHeader {
343
+ display: flex;
344
+ align-items: center;
345
+ gap: 1rem;
346
+ padding: 1rem 1.5rem;
347
+ background: linear-gradient(135deg, #007a40, #00a352);
348
+ border-bottom: 1px solid rgba(0,153,68,0.15);
349
+ }
350
+
351
+ .bkashLogo { font-size: 1.8rem; }
352
+
353
+ .bkashTitle {
354
+ font-family: var(--font-bengali);
355
+ font-size: 1rem;
356
+ font-weight: 700;
357
+ color: #ffffff;
358
+ }
359
+
360
+ .bkashSub {
361
+ font-family: var(--font-bengali);
362
+ font-size: 0.8rem;
363
+ color: rgba(255,255,255,0.75);
364
+ }
365
+
366
+ .bkashNumberRow {
367
+ display: flex;
368
+ align-items: center;
369
+ justify-content: space-between;
370
+ padding: 1rem 1.5rem;
371
+ border-bottom: 1px solid rgba(0,153,68,0.1);
372
+ gap: 1rem;
373
+ }
374
+
375
+ .bkashLabel {
376
+ font-size: 0.75rem;
377
+ font-weight: 600;
378
+ text-transform: uppercase;
379
+ letter-spacing: 0.05em;
380
+ color: #007a40;
381
+ display: block;
382
+ margin-bottom: 0.25rem;
383
+ }
384
+
385
+ .bkashNumber {
386
+ font-size: 1.6rem;
387
+ font-weight: 700;
388
+ color: #00582d;
389
+ letter-spacing: 0.06em;
390
+ font-family: var(--font-display);
391
+ }
392
+
393
+ .copyBtn {
394
+ font-family: var(--font-bengali);
395
+ font-size: 0.82rem;
396
+ font-weight: 700;
397
+ padding: 0.5rem 1rem;
398
+ border-radius: 100px;
399
+ background: #007a40;
400
+ color: white;
401
+ border: none;
402
+ cursor: pointer;
403
+ transition: all 0.2s;
404
+ white-space: nowrap;
405
+ flex-shrink: 0;
406
+ }
407
+
408
+ .copyBtn:hover { background: #005c30; transform: scale(1.03); }
409
+ .copied { background: #065f46 !important; }
410
+
411
+ .bkashAmountRow,
412
+ .bkashRefRow {
413
+ display: flex;
414
+ justify-content: space-between;
415
+ align-items: center;
416
+ padding: 0.8rem 1.5rem;
417
+ border-bottom: 1px solid rgba(0,153,68,0.08);
418
+ }
419
+
420
+ .bkashAmount {
421
+ font-family: var(--font-display);
422
+ font-size: 1.5rem;
423
+ font-weight: 700;
424
+ color: #00582d;
425
+ }
426
+
427
+ .bkashRef {
428
+ font-size: 0.85rem;
429
+ font-weight: 700;
430
+ color: #007a40;
431
+ font-family: monospace;
432
+ background: rgba(0,153,68,0.08);
433
+ padding: 0.2rem 0.6rem;
434
+ border-radius: 4px;
435
+ }
436
+
437
+ .bkashSteps {
438
+ padding: 1rem 1.5rem 1.2rem;
439
+ }
440
+
441
+ .bkashStepsTitle {
442
+ font-family: var(--font-bengali);
443
+ font-size: 0.85rem;
444
+ font-weight: 700;
445
+ color: #007a40;
446
+ margin-bottom: 0.6rem;
447
+ }
448
+
449
+ .bkashStepsList {
450
+ list-style: none;
451
+ display: flex;
452
+ flex-direction: column;
453
+ gap: 0.35rem;
454
+ counter-reset: step;
455
+ padding: 0;
456
+ }
457
+
458
+ .bkashStepsList li {
459
+ font-family: var(--font-bengali);
460
+ font-size: 0.85rem;
461
+ color: #00582d;
462
+ display: flex;
463
+ align-items: flex-start;
464
+ gap: 0.5rem;
465
+ counter-increment: step;
466
+ }
467
+
468
+ .bkashStepsList li::before {
469
+ content: counter(step);
470
+ background: #007a40;
471
+ color: white;
472
+ width: 18px;
473
+ height: 18px;
474
+ border-radius: 50%;
475
+ font-size: 0.65rem;
476
+ font-weight: 700;
477
+ display: flex;
478
+ align-items: center;
479
+ justify-content: center;
480
+ flex-shrink: 0;
481
+ margin-top: 2px;
482
+ }
483
+
484
+ /* ── TrxID Section ─────────────────────────────────────────────────────────── */
485
+ .trxSection {
486
+ margin-bottom: 1rem;
487
+ }
488
+
489
+ .trxInputRow {
490
+ display: flex;
491
+ gap: 0.8rem;
492
+ align-items: center;
493
+ }
494
+
495
+ .trxInput {
496
+ font-family: monospace !important;
497
+ font-size: 1.1rem !important;
498
+ font-weight: 700 !important;
499
+ letter-spacing: 0.1em !important;
500
+ text-transform: uppercase;
501
+ }
502
+
503
+ .trxHint {
504
+ font-size: 0.78rem;
505
+ color: var(--text-light);
506
+ margin-top: 0.3rem;
507
+ display: block;
508
+ font-family: var(--font-bengali);
509
+ }
510
+
511
+ .btnSubmitTrx {
512
+ font-family: var(--font-bengali);
513
+ font-size: 1rem;
514
+ font-weight: 700;
515
+ padding: 0.85rem 2rem;
516
+ border-radius: 100px;
517
+ color: white;
518
+ background: linear-gradient(135deg, #007a40, #00a352);
519
+ box-shadow: 0 4px 16px rgba(0,153,68,0.35);
520
+ transition: all 0.2s;
521
+ border: none;
522
+ cursor: pointer;
523
+ }
524
+
525
+ .btnSubmitTrx:hover:not(:disabled) {
526
+ transform: translateY(-2px);
527
+ box-shadow: 0 8px 24px rgba(0,153,68,0.45);
528
+ }
529
+
530
+ .btnSubmitTrx:disabled { opacity: 0.5; cursor: not-allowed; }
531
+
532
+ /* ── Submitted success ─────────────────────────────────────────────────────── */
533
+ .successWrap {
534
+ display: flex;
535
+ flex-direction: column;
536
+ align-items: center;
537
+ gap: 1rem;
538
+ text-align: center;
539
+ }
540
+
541
+ .successIcon {
542
+ width: 80px;
543
+ height: 80px;
544
+ border-radius: 50%;
545
+ background: linear-gradient(135deg, var(--emerald), var(--emerald-light));
546
+ display: flex;
547
+ align-items: center;
548
+ justify-content: center;
549
+ font-size: 2.4rem;
550
+ box-shadow: 0 8px 28px rgba(13,59,46,0.28);
551
+ animation: pop 0.5s cubic-bezier(0.175,0.885,0.32,1.275);
552
+ }
553
+
554
+ @keyframes pop {
555
+ from { opacity: 0; transform: scale(0.7); }
556
+ to { opacity: 1; transform: scale(1); }
557
+ }
558
+
559
+ .successTitle {
560
+ font-family: var(--font-bengali);
561
+ font-size: 1.6rem;
562
+ font-weight: 700;
563
+ color: var(--emerald);
564
+ }
565
+
566
+ .successSub {
567
+ font-family: var(--font-bengali);
568
+ font-size: 0.95rem;
569
+ color: var(--text-mid);
570
+ max-width: 400px;
571
+ }
572
+
573
+ .submittedCard {
574
+ width: 100%;
575
+ background: #f8fffe;
576
+ border: 1.5px solid rgba(0,153,68,0.15);
577
+ border-radius: var(--radius);
578
+ overflow: hidden;
579
+ margin: 0.5rem 0;
580
+ }
581
+
582
+ .submittedRow {
583
+ display: flex;
584
+ justify-content: space-between;
585
+ align-items: center;
586
+ padding: 0.75rem 1.25rem;
587
+ font-size: 0.9rem;
588
+ color: var(--text-mid);
589
+ border-bottom: 1px solid rgba(0,0,0,0.05);
590
+ font-family: var(--font-bengali);
591
+ }
592
+
593
+ .submittedRow strong { color: var(--text-dark); font-weight: 700; }
594
+
595
+ .trxBadge {
596
+ font-family: monospace !important;
597
+ font-size: 0.85rem !important;
598
+ background: #d1fae5;
599
+ color: #065f46;
600
+ padding: 0.2rem 0.6rem;
601
+ border-radius: 4px;
602
+ }
603
+
604
+ .statusBadge {
605
+ padding: 0.8rem 1.25rem;
606
+ font-family: var(--font-bengali);
607
+ font-size: 0.9rem;
608
+ font-weight: 600;
609
+ color: #92400e;
610
+ background: #fef3c7;
611
+ text-align: center;
612
+ }
613
+
614
+ .orderIdNote {
615
+ font-size: 0.75rem;
616
+ color: var(--text-light);
617
+ }
618
+
619
+ .orderIdNote code {
620
+ font-family: monospace;
621
+ background: rgba(0,0,0,0.05);
622
+ padding: 0.15rem 0.4rem;
623
+ border-radius: 3px;
624
+ }