save
This commit is contained in:
parent
a0cb5fb6b0
commit
e435d32588
|
@ -11,3 +11,6 @@ SMTP_FROM="noreply@example.com"
|
|||
# !! Choose your LN_SERVICE carefully!!
|
||||
# NOTE: The LN_SERVICE must support LUD-21 Payment Verification
|
||||
LN_ADDRESS="your@node.win"
|
||||
# Shippo API for address validation and getting live shipping rates
|
||||
# buying and printing labels
|
||||
SHIPPO_API_KEY="your-shippo.com-API-key"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"web-auth/webauthn-lib": "^5.0",
|
||||
"twig/twig": "^3.0",
|
||||
"swentel/nostr-php": "^1.5",
|
||||
"jorijn/bitcoin-bolt11": "^1.0"
|
||||
"jorijn/bitcoin-bolt11": "^1.0",
|
||||
"shippo/shippo-php": "^2.0"
|
||||
}
|
||||
}
|
||||
|
|
60
composer.lock
generated
60
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "3f3a1571b095d2550e901def5ae562ca",
|
||||
"content-hash": "d534de83ea2acfea5f56dd6efb27959e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bitwasp/bech32",
|
||||
|
@ -1709,6 +1709,64 @@
|
|||
},
|
||||
"time": "2023-03-08T19:51:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "shippo/shippo-php",
|
||||
"version": "v2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/goshippo/shippo-php-client.git",
|
||||
"reference": "7422af5b97c8b36718593dbaf5cfb757771fb907"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/goshippo/shippo-php-client/zipball/7422af5b97c8b36718593dbaf5cfb757771fb907",
|
||||
"reference": "7422af5b97c8b36718593dbaf5cfb757771fb907",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "9.5.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"lib/Shippo/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Shippo & Contributors",
|
||||
"homepage": "https://goshippo.com/"
|
||||
}
|
||||
],
|
||||
"description": "A PHP library for connecting with multiple carriers (FedEx, UPS, USPS) using Shippo.",
|
||||
"homepage": "https://goshippo.com/",
|
||||
"keywords": [
|
||||
"FedEx",
|
||||
"Uber",
|
||||
"address",
|
||||
"dhl",
|
||||
"shipping",
|
||||
"shyp",
|
||||
"tracking",
|
||||
"ups",
|
||||
"usps"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/goshippo/shippo-php-client/issues",
|
||||
"source": "https://github.com/goshippo/shippo-php-client/tree/v2.0.0"
|
||||
},
|
||||
"time": "2022-01-19T22:36:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "simplito/bigint-wrapper-php",
|
||||
"version": "1.0.0",
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
use app\app;
|
||||
use app\controllers\account;
|
||||
use app\controllers\admin;
|
||||
use app\controllers\category;
|
||||
use app\controllers\cart;
|
||||
use app\controllers\category;
|
||||
use app\controllers\checkout;
|
||||
use app\controllers\home;
|
||||
use app\controllers\lnurlp;
|
||||
|
@ -26,7 +26,7 @@ session_start();
|
|||
session_regenerate_id(true); // prevent session fixation attacks
|
||||
|
||||
// prevent session hijack
|
||||
if (!isset($_SESSION['fingerprint'])) {
|
||||
if (! isset($_SESSION['fingerprint'])) {
|
||||
$_SESSION['fingerprint'] = hash('sha256', $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
|
||||
} else {
|
||||
if ($_SESSION['fingerprint'] !== hash('sha256', $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'])) {
|
||||
|
@ -41,6 +41,7 @@ $defaults = [
|
|||
'session' => $_SESSION,
|
||||
'http_host' => $_SERVER['HTTP_HOST'],
|
||||
'env' => $_ENV,
|
||||
'is_user' => isset($_SESSION['user_id']),
|
||||
'is_admin' => isset($_SESSION['user_id']) && $_SESSION['user_id'] == 1,
|
||||
// uses cookie-js to get the client's preferred theme
|
||||
// used to conditionally deliver image assets
|
||||
|
@ -82,17 +83,19 @@ if (preg_match('/^\/(transaction|user|order|product)\/([\w-]+)$/', $route, $matc
|
|||
} else {
|
||||
$controller = match ($route) {
|
||||
'/' => home::index($defaults),
|
||||
'/account' => account::index($defaults),
|
||||
'/account/profile' => account::profile(),
|
||||
'/account/login' => account::login($defaults),
|
||||
'/account/email' => account::email(),
|
||||
'/account/logout' => account::logout(),
|
||||
'/account/returns' => account::returns($defaults),
|
||||
'/account/signup' => account::signup($defaults),
|
||||
'/account/billing' => account::billing($defaults),
|
||||
'/account/orders' => account::orders($defaults),
|
||||
'/account/shipping' => account::shipping($defaults),
|
||||
'/account/verify' => account::verify($defaults),
|
||||
'/account' => $defaults['is_user'] ? account::index($defaults) : header('Location: /account/login'),
|
||||
'/account/profile' => $defaults['is_user'] ? account::profile() : header('Location: /account/login'),
|
||||
'/account/email' => $defaults['is_user'] ? account::email() : header('Location: /account/login'),
|
||||
'/account/logout' => $defaults['is_user'] ? account::logout() : header('Location: /account/login'),
|
||||
'/account/returns' => $defaults['is_user'] ? account::returns($defaults) : header('Location: /account/login'),
|
||||
'/account/billing' => $defaults['is_user'] ? account::billing($defaults) : header('Location: /account/login'),
|
||||
'/account/orders' => $defaults['is_user'] ? account::orders($defaults) : header('Location: /account/login'),
|
||||
'/account/shipping' => $defaults['is_user'] ? account::shipping($defaults) : header('Location: /account/login'),
|
||||
'/account/address/edit' => $defaults['is_user'] ? account::address_edit($defaults) : header('Location: /account/login'),
|
||||
'/account/address/confirm' => $defaults['is_user'] ? account::address_confirm($defaults) : header('Location: /account/login'),
|
||||
'/admin' => $defaults['is_admin'] ? admin::index($defaults) : lost::index($defaults),
|
||||
'/admin/users' => $defaults['is_admin'] ? admin::users($defaults) : lost::index($defaults),
|
||||
'/admin/orders' => $defaults['is_admin'] ? admin::orders($defaults) : lost::index($defaults),
|
||||
|
@ -113,7 +116,8 @@ if (preg_match('/^\/(transaction|user|order|product)\/([\w-]+)$/', $route, $matc
|
|||
'/power-meters' => category::power_meters($defaults),
|
||||
default => lost::index($defaults)
|
||||
};
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
// Clear alerts after rendering
|
||||
foreach (['error', 'warning', 'info', 'success'] as $alert) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace app;
|
||||
// for email
|
||||
|
||||
// for email
|
||||
|
||||
class app
|
||||
{
|
||||
|
|
|
@ -4,55 +4,55 @@ return [
|
|||
'banner' => 'bg-gray-100 dark:bg-gray-600 text-gray-200 dark:text-gray-200',
|
||||
],
|
||||
'anchor' => [
|
||||
'primary' => 'text-blue-400 dark:text-blue-200'
|
||||
'primary' => 'text-blue-400 dark:text-blue-200',
|
||||
],
|
||||
'body' => 'bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-300',
|
||||
'button' => [
|
||||
'primary' => 'border-blue-400 dark:border-blue-600 dark:hover:border-blue-800 bg-blue-400 dark:bg-blue-600 hover:bg-blue-600 hover:dark:bg-blue-800 text-white dark:text-white',
|
||||
'default' => 'hover:bg-gray-50 dark:hover:bg-gray-900'
|
||||
'default' => 'hover:bg-gray-50 dark:hover:bg-gray-900',
|
||||
],
|
||||
'breadcrumb' => [
|
||||
'parent' => 'text-gray-300 dark:text-gray-400 hover:text-gray-400 dark:hover:text-gray-500',
|
||||
'seperator' => 'text-gray-200 dark:text-gray-200',
|
||||
'child' => 'text-gray-200 dark:text-gray-300'
|
||||
'child' => 'text-gray-200 dark:text-gray-300',
|
||||
],
|
||||
'dropdown' => [
|
||||
'list' => 'bg-white dark:bg-blue-900 border-gray-600 dark:border-gray-300',
|
||||
'item' => 'hover:bg-gray-200 dark:hover:bg-gray-900'
|
||||
'item' => 'hover:bg-gray-200 dark:hover:bg-gray-900',
|
||||
],
|
||||
'input' => 'text-gray-800 dark:text-gray-300 bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-500 focus:ring-blue-500',
|
||||
'error' => [
|
||||
'text' => 'text-red-600',
|
||||
'alert' => 'bg-red-100 text-gray-800 border-red-600'
|
||||
'alert' => 'bg-red-100 text-gray-800 border-red-600',
|
||||
],
|
||||
'warning' => [
|
||||
'text' => 'text-yellow-400',
|
||||
'alert' => 'bg-yellow-100 text-gray-800 border-yellow-400'
|
||||
'alert' => 'bg-yellow-100 text-gray-800 border-yellow-400',
|
||||
],
|
||||
'success' => [
|
||||
'text' => 'text-green-600',
|
||||
'alert' => 'bg-green-100 text-gray-800 border-green-600'
|
||||
'alert' => 'bg-green-100 text-gray-800 border-green-600',
|
||||
],
|
||||
'info' => [
|
||||
'text' => 'text-blue-400',
|
||||
'alert' => 'bg-blue-200 text-gray-800 border-blue-400'
|
||||
'alert' => 'bg-blue-200 text-gray-800 border-blue-400',
|
||||
],
|
||||
'modal' => [
|
||||
'content' => 'bg-white dark:bg-blue-900 border-gray-600 dark:border-gray-300',
|
||||
'shadow' => 'bg-black/70'
|
||||
'shadow' => 'bg-black/70',
|
||||
],
|
||||
'nav' => [
|
||||
'bar' => 'bg-blue-400 dark:bg-blue-600 text-gray-200 dark:text-gray-200',
|
||||
'item' => 'hover:bg-blue-600 dark:hover:bg-blue-800 hover:text-gray-200 dark:hover:text-gray-300 text-white border-blue-400 dark:border-blue-600',
|
||||
'hovercontent' => 'bg-white dark:bg-slate-700 text-gray-800 dark:text-gray-300'
|
||||
'hovercontent' => 'bg-white dark:bg-slate-700 text-gray-800 dark:text-gray-300',
|
||||
],
|
||||
'rule' => 'border-gray-400 dark:border-gray-400',
|
||||
'text' => [
|
||||
'muted' => 'text-gray-400 dark:text-gray-300'
|
||||
'muted' => 'text-gray-400 dark:text-gray-300',
|
||||
],
|
||||
'toggle' => "bg-gray-300 peer-checked:bg-green-400 after:bg-white",
|
||||
'footer' => [
|
||||
"primary" => "bg-gray-200 dark:bg-slate-600 text-gray-500 dark:text-gray-300",
|
||||
"policy" => "bg-slate-400 dark:bg-slate-800 text-gray-200 dark:text-gray-400"
|
||||
"policy" => "bg-slate-400 dark:bg-slate-800 text-gray-200 dark:text-gray-400",
|
||||
],
|
||||
];
|
||||
];
|
||||
|
|
|
@ -2,64 +2,40 @@
|
|||
namespace app\controllers;
|
||||
|
||||
use app\models\addresses;
|
||||
use app\models\users;
|
||||
use app\models\emails;
|
||||
use app\models\user_addresses;
|
||||
use app\models\magic_links;
|
||||
use app\models\users;
|
||||
|
||||
class account
|
||||
{
|
||||
public static function index($defaults): void
|
||||
{
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: /account/login');
|
||||
}
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$user = users::getById($user_id);
|
||||
$default_shipping = null;
|
||||
$default_billing = null;
|
||||
$ship_addrs = [];
|
||||
$bill_addrs = [];
|
||||
$addresses = user_addresses::getShippingByUserId($user['id']);
|
||||
foreach ($addresses as $address) {
|
||||
if ($address['id'] == $user['shipping_address_id']){
|
||||
$default_shipping = $address;
|
||||
} else {
|
||||
$ship_addrs[] = $address;
|
||||
}
|
||||
}
|
||||
$bill_addresses = user_addresses::getBillingByUserId($_SESSION['user_id']);
|
||||
foreach ($bill_addresses as $addr) {
|
||||
if ($addr['id'] == $user['billing_address_id']){
|
||||
$default_billing = $addr;
|
||||
} else {
|
||||
$bill_addrs[] = $addr;
|
||||
}
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
$user = users::getById($_SESSION['user_id']);
|
||||
$addresses = addresses::getByUserId($_SESSION['user_id']);
|
||||
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/index.twig',
|
||||
'page_title' => 'Manage Account - ' . $_ENV['APP_NAME'],
|
||||
'user' => $user,
|
||||
'shipping' => $ship_addrs,
|
||||
'billing' => $bill_addrs,
|
||||
'default_shipping' => $default_shipping,
|
||||
'default_billing' => $default_billing,
|
||||
'addresses' => $addresses,
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'My Account',
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function billing($defaults)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (!$_SESSION['user_id']) {
|
||||
http_response_code(403);
|
||||
$bill = addresses::validatePost("billing_");
|
||||
if (isset($bill['error'])) {
|
||||
header('Location: /account/billing');
|
||||
}
|
||||
$bill = addresses::validatePost("billing");
|
||||
$bill_id = addresses::add(
|
||||
$_SESSION['user_id'],
|
||||
$bill['name'],
|
||||
$bill['company'],
|
||||
$bill['addressLine1'],
|
||||
|
@ -68,51 +44,34 @@ class account
|
|||
$bill['state'],
|
||||
$bill['zip'],
|
||||
$bill['phone'],
|
||||
1,
|
||||
0
|
||||
);
|
||||
user_addresses::add(
|
||||
$_SESSION['user_id'],
|
||||
$bill_id
|
||||
$bill['hash']
|
||||
);
|
||||
$_SESSION['success'] = "Billing address saved!";
|
||||
header('Location: /account/billing');
|
||||
}
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$user = users::getById($user_id);
|
||||
$default_billing = null;
|
||||
$bill_addrs = [];
|
||||
$bill_addresses = user_addresses::getBillingByUserId($_SESSION['user_id']);
|
||||
foreach ($bill_addresses as $addr) {
|
||||
if ($addr['id'] == $user['billing_address_id']){
|
||||
$default_billing = $addr;
|
||||
} else {
|
||||
$bill_addrs[] = $addr;
|
||||
}
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
$user = users::getById($_SESSION['user_id']);
|
||||
$addresses = addresses::getByUserId($_SESSION['user_id']);
|
||||
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/billing.twig',
|
||||
'page_title' => 'Billing Information - ' . $_ENV['APP_NAME'],
|
||||
'billing' => $bill_addrs,
|
||||
'default_billing' => $default_billing,
|
||||
'user' => $user,
|
||||
'addresses' => $addresses,
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account'
|
||||
'title' => 'My Account',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Billing'
|
||||
]
|
||||
]
|
||||
'title' => 'Billing',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
public static function profile()
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (!$_SESSION['user_id']) {
|
||||
http_response_code(403);
|
||||
}
|
||||
users::updateProfileById($_SESSION['user_id'], $_POST);
|
||||
header('Location: /account');
|
||||
}
|
||||
|
@ -120,10 +79,6 @@ class account
|
|||
|
||||
public static function email()
|
||||
{
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (empty($user_id)){
|
||||
header('Location: /account/login');
|
||||
}
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$email = $_POST['email'] ?? null;
|
||||
if (empty($email)) {
|
||||
|
@ -131,6 +86,7 @@ class account
|
|||
header('Location: /account');
|
||||
exit;
|
||||
} else {
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$token = magic_links::add($email, $user_id);
|
||||
users::updateReplaceEmailTokenById($user_id, $token);
|
||||
header('Location: /account');
|
||||
|
@ -149,7 +105,7 @@ class account
|
|||
if ($user) {
|
||||
$_SESSION['user_email'] = $link['email'];
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
if (!$user['verified']) {
|
||||
if (! $user['verified']) {
|
||||
users::verify($link['email']);
|
||||
}
|
||||
header('Location: /account');
|
||||
|
@ -166,19 +122,55 @@ class account
|
|||
}
|
||||
}
|
||||
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/verify.twig',
|
||||
'page_title' => $_ENV['APP_NAME'],
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account'
|
||||
'title' => 'My Account',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Verify'
|
||||
]
|
||||
]
|
||||
'title' => 'Verify',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function address_edit($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/address/edit.twig',
|
||||
'page_title' => 'Edit Address - ' . $_ENV['APP_NAME'],
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Edit Address',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function address_confirm($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/address/confirm.twig',
|
||||
'page_title' => 'Confirm Address - ' . $_ENV['APP_NAME'],
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Confirm Address',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -199,15 +191,15 @@ class account
|
|||
if (isset($_SESSION['user_id'])) {
|
||||
header('Location: /account');
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/login.twig',
|
||||
'page_title' => 'Sign In or Create an Account!',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'My Account'
|
||||
'title' => 'My Account',
|
||||
],
|
||||
],
|
||||
]
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -220,50 +212,48 @@ class account
|
|||
|
||||
public static function orders($defaults)
|
||||
{
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: /account/login');
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/orders.twig',
|
||||
'page_title' => 'View ' . $_ENV['APP_NAME'] . ' Orders',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account'
|
||||
'title' => 'My Account',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Orders'
|
||||
]
|
||||
]
|
||||
'title' => 'Orders',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function returns($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/returns.twig',
|
||||
'page_title' => 'View ' . $_ENV['APP_NAME'] . ' Returns',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account'
|
||||
'title' => 'My Account',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Returns'
|
||||
]
|
||||
]
|
||||
'title' => 'Returns',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
public static function shipping($defaults)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
if (!$_SESSION['user_id']) {
|
||||
http_response_code(403);
|
||||
$ship = addresses::validatePost("shipping_");
|
||||
if (isset($ship['error'])) {
|
||||
header('Location: /account/shipping');
|
||||
}
|
||||
$ship = addresses::validatePost("shipping");
|
||||
$ship_id = addresses::add(
|
||||
$_SESSION['user_id'],
|
||||
$ship['name'],
|
||||
$ship['company'],
|
||||
$ship['addressLine1'],
|
||||
|
@ -272,43 +262,28 @@ class account
|
|||
$ship['state'],
|
||||
$ship['zip'],
|
||||
$ship['phone'],
|
||||
0,
|
||||
1
|
||||
);
|
||||
user_addresses::add(
|
||||
$_SESSION['user_id'],
|
||||
$ship_id
|
||||
$ship['hash']
|
||||
);
|
||||
$_SESSION['success'] = "Shipping address saved!";
|
||||
header('Location: /account/shipping');
|
||||
}
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$user = users::getById($user_id);
|
||||
$addresses = user_addresses::getShippingByUserId($user['id']);
|
||||
$default_shipping = null;
|
||||
$ship_addrs = [];
|
||||
foreach ($addresses as $addr) {
|
||||
if ($addr['id'] == $user['shipping_address_id']){
|
||||
$default_shipping = $addr;
|
||||
} else {
|
||||
$ship_addrs[] = $addr;
|
||||
}
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
$user = users::getById($_SESSION['user_id']);
|
||||
$addresses = addresses::getByUserId($_SESSION['user_id']);
|
||||
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/shipping.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Shipping',
|
||||
'shipping' => $ship_addrs,
|
||||
'default_shipping' => $default_shipping,
|
||||
'addresses' => $addresses,
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/account',
|
||||
'title' => 'My Account'
|
||||
'title' => 'My Account',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Shipping'
|
||||
]
|
||||
]
|
||||
'title' => 'Shipping',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -327,16 +302,16 @@ class account
|
|||
exit;
|
||||
}
|
||||
$useShipping = $_POST['use_shipping'] ?? false;
|
||||
$ship = addresses::validatePost("shipping");
|
||||
if (!isset($ship['name'])){
|
||||
$_SESSION['error'] = "Shipping address verification failed. Check your entry for errors.";
|
||||
$ship = addresses::validatePost("shipping_");
|
||||
if (isset($ship['error'])) {
|
||||
$_SESSION['error'] = "Shipping address verification failed. " . $_SESSION['error'];
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
header('Location: /account/signup');
|
||||
}
|
||||
if (!$useShipping) {
|
||||
$bill = addresses::validatePost("billing");
|
||||
if (!isset($bill['name'])){
|
||||
$_SESSION['error'] = "Billing address verification failed. Check your entry for errors.";
|
||||
if (! $useShipping) {
|
||||
$bill = addresses::validatePost("billing_");
|
||||
if (isset($bill['error'])) {
|
||||
$_SESSION['error'] = "Billing address verification failed. " . $_SESSION['error'];
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
header('Location: /account/signup');
|
||||
}
|
||||
|
@ -346,6 +321,7 @@ class account
|
|||
header('Location: /account/signup');
|
||||
}
|
||||
$ship_id = addresses::add(
|
||||
null,
|
||||
$ship['name'],
|
||||
$ship['company'],
|
||||
$ship['addressLine1'],
|
||||
|
@ -354,12 +330,12 @@ class account
|
|||
$ship['state'],
|
||||
$ship['zip'],
|
||||
$ship['phone'],
|
||||
$useShipping == 'on',
|
||||
1
|
||||
$ship['hash']
|
||||
);
|
||||
$bill_id = $ship_id;
|
||||
if (!$useShipping) {
|
||||
if (! $useShipping) {
|
||||
$bill_id = addresses::add(
|
||||
null,
|
||||
$bill['name'],
|
||||
$bill['company'],
|
||||
$bill['addressLine1'],
|
||||
|
@ -368,8 +344,7 @@ class account
|
|||
$bill['state'],
|
||||
$bill['zip'],
|
||||
$bill['phone'],
|
||||
1,
|
||||
0
|
||||
$bill['hash']
|
||||
);
|
||||
}
|
||||
$opt_in_promotional = $_POST['opt_in_promotional'] ?? false;
|
||||
|
@ -384,18 +359,8 @@ class account
|
|||
$dark_theme
|
||||
);
|
||||
emails::updateUserIdByEmail($email, $user_id);
|
||||
user_addresses::add(
|
||||
user_id: $user_id,
|
||||
address_id: $ship_id
|
||||
);
|
||||
if (!$useShipping) {
|
||||
user_addresses::add(
|
||||
user_id: $user_id,
|
||||
address_id: $bill_id
|
||||
);
|
||||
}
|
||||
$_SESSION['user_id'] = $user_id;
|
||||
if (!$verified) {
|
||||
if (! $verified) {
|
||||
header("Location: /magic-link?email=$email&signup=1");
|
||||
exit;
|
||||
}
|
||||
|
@ -408,9 +373,9 @@ class account
|
|||
exit;
|
||||
}
|
||||
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'account/signup.twig',
|
||||
'page_title' => 'Create an Account - ' . $_ENV['APP_NAME']
|
||||
'page_title' => 'Create an Account - ' . $_ENV['APP_NAME'],
|
||||
]));
|
||||
}
|
||||
}
|
|
@ -1,83 +1,83 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
use app\models\transactions;
|
||||
use app\models\emails;
|
||||
use app\models\transactions;
|
||||
use app\models\users;
|
||||
|
||||
class admin
|
||||
{
|
||||
public static function index($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/index.twig',
|
||||
'page_title' => 'Dashboard',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
]
|
||||
'title' => 'Admin',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function users($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/users.twig',
|
||||
'page_title' => 'Users',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/users',
|
||||
'title' => 'Users'
|
||||
]
|
||||
'title' => 'Users',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function orders($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/orders.twig',
|
||||
'page_title' => 'Orders',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/orders',
|
||||
'title' => 'Orders'
|
||||
]
|
||||
'title' => 'Orders',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function returns($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/returns.twig',
|
||||
'page_title' => 'Returns',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/returns',
|
||||
'title' => 'Returns'
|
||||
]
|
||||
'title' => 'Returns',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function transactions($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/transactions/index.twig',
|
||||
'page_title' => 'Transactions',
|
||||
'recent_sats' => transactions::getRecent(10, 'sats'),
|
||||
|
@ -89,12 +89,12 @@ class admin
|
|||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
]
|
||||
'title' => 'Transactions',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
@ -105,23 +105,23 @@ class admin
|
|||
$amount = $_POST['amount'] ?? null;
|
||||
$currency = $_POST['currency'];
|
||||
$user_identifier = $_POST['user_identifier'] ?? null;
|
||||
if (!$amount || !$user_identifier) {
|
||||
$_SESSION['error'] = !$amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction.";
|
||||
if (! $amount || ! $user_identifier) {
|
||||
$_SESSION['error'] = ! $amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
} else {
|
||||
if (strpos($user_identifier, '@') !== false && strpos($user_identifier, '.') !== false) {
|
||||
$user = users::getByEmail($user_identifier);
|
||||
} elseif (is_numeric($user_identifier)) {
|
||||
$user = users::getById((int)$user_identifier);
|
||||
$user = users::getById((int) $user_identifier);
|
||||
} else {
|
||||
$_SESSION['error'] = "Invalid user identifier. Please enter a valid email or user ID.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
}
|
||||
if (!$user) {
|
||||
if (! $user) {
|
||||
$_SESSION['error'] = "User not found. Please enter a valid email or user ID.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
} else {
|
||||
if($_POST['confirm']){
|
||||
if ($_POST['confirm']) {
|
||||
// create the transaction
|
||||
$txid = transactions::add($user['id'], $amount > 0 ? 'CREDIT' : 'REVOKE', $currency == 'cents' ? $amount : 0, $currency == 'sats' ? $amount : 0);
|
||||
header('Location: /transaction/' . $txid);
|
||||
|
@ -135,22 +135,22 @@ class admin
|
|||
}
|
||||
}
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/transactions/add.twig',
|
||||
'page_title' => 'Add a Transaction',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
'title' => 'Transactions',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions/add',
|
||||
'title' => 'Add'
|
||||
]
|
||||
'title' => 'Add',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
@ -158,19 +158,19 @@ class admin
|
|||
public static function emails($defaults)
|
||||
{
|
||||
$recent_emails = emails::getRecent(20);
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/emails.twig',
|
||||
'page_title' => 'Emails',
|
||||
'recent_emails' => $recent_emails,
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/emails',
|
||||
'title' => 'Emails'
|
||||
]
|
||||
'title' => 'Emails',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
class cart
|
||||
{
|
||||
public static function index($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'cart.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Cart',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Cart'
|
||||
]
|
||||
'title' => 'Cart',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
class category
|
||||
{
|
||||
public static function power_meters($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', context: array_merge($defaults, [
|
||||
'child_template' => 'lib/page/category.twig',
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', context: array_merge($defaults, [
|
||||
'child_template' => 'lib/pages/category.twig',
|
||||
'page_title' => 'Power Meters - ' . $_ENV['APP_NAME'],
|
||||
'product_category' => 'power_meters',
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
class checkout
|
||||
{
|
||||
public static function shipping_billing($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/flow.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/flow.twig', array_merge($defaults, [
|
||||
'child_template' => 'checkout/shipping_billing.twig',
|
||||
'page_title' => 'Checkout with ' . $_ENV['APP_NAME'],
|
||||
]));
|
||||
}
|
||||
public static function review_pay($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/flow.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/flow.twig', array_merge($defaults, [
|
||||
'child_template' => 'checkout/review_pay.twig',
|
||||
'page_title' => 'Review & Payment | ' . $_ENV['APP_NAME']
|
||||
'page_title' => 'Review & Payment | ' . $_ENV['APP_NAME'],
|
||||
]));
|
||||
}
|
||||
public static function confirmed($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/flow.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/flow.twig', array_merge($defaults, [
|
||||
'child_template' => 'checkout/confirmed.twig',
|
||||
'page_title' => 'Order Recieved! - Thank You'
|
||||
'page_title' => 'Order Recieved! - Thank You',
|
||||
]));
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
class home
|
||||
{
|
||||
public static function index($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render(name: 'lib/page/index.twig', context: array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render(name: 'lib/pages/index.twig', context: array_merge($defaults, [
|
||||
'child_template' => 'home.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ": Specialty Hardware"
|
||||
'page_title' => $_ENV['APP_NAME'] . ": Specialty Hardware",
|
||||
]));
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace app\controllers;
|
||||
|
||||
use app\app;
|
||||
use app\models\invoices;
|
||||
$invoice = 'lnbc234340n1pnm5uh2pp5pwekmjzj3hgadahfeprtc6f2ppmhnqjzh556q4fvve8z953v3t0sdqqcqzysxqrrsssp5uq25yjnmvdpnglmv42nf64wk0pugrynq549f3wgghgtkfapwdfhq9qxpqysgqyjq2ewqkm6s2dlhuruuc4k9md22wraz829tlhfeuxrsnwmephfkjz8e9g7j6373989mfccajy3cxexac8xu6yen4qfs4947fkrg9ynsq7x72ze';
|
||||
use Jorijn\Bitcoin\Bolt11\Encoder\PaymentRequestDecoder;
|
||||
use Jorijn\Bitcoin\Bolt11\Model\Tag;
|
||||
use Jorijn\Bitcoin\Bolt11\Normalizer\PaymentRequestDenormalizer;
|
||||
|
||||
class lnurlp
|
||||
|
@ -39,10 +38,10 @@ class lnurlp
|
|||
}
|
||||
// for when the user is not registered
|
||||
$user = users::getByNpub($username);
|
||||
if (!$user){
|
||||
if (! $user) {
|
||||
returnJson([
|
||||
'status' => 'ERROR',
|
||||
'reason' => "@$username is not registered"
|
||||
'reason' => "@$username is not registered",
|
||||
]);
|
||||
}
|
||||
// for when the client makes it's first call (querying the lightning address)
|
||||
|
@ -72,7 +71,7 @@ class lnurlp
|
|||
}
|
||||
$res = json_decode(file_get_contents($proxy_url), true);
|
||||
|
||||
if ($res['status'] === 'OK'){
|
||||
if ($res['status'] === 'OK') {
|
||||
// subscribe to this invoice by adding to our db
|
||||
$invoice = $res['pr'];
|
||||
$decoder = new PaymentRequestDecoder();
|
||||
|
@ -92,7 +91,7 @@ class lnurlp
|
|||
'status' => 'OK',
|
||||
'pr' => $invoice,
|
||||
'routes' => $res['routes'],
|
||||
'verify' => "https://$host/lnurlp?verify=$proxy_verify"
|
||||
'verify' => "https://$host/lnurlp?verify=$proxy_verify",
|
||||
]);
|
||||
} else {
|
||||
returnJson($res);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
class lost
|
||||
{
|
||||
public static function index($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => '404.twig',
|
||||
'page_title' => 'Not Found - ' . $_ENV['APP_NAME'],
|
||||
]));
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
use app\app;
|
||||
use app\models\users;
|
||||
use app\models\magic_links;
|
||||
use app\models\users;
|
||||
|
||||
class magic_link
|
||||
{
|
||||
public static function index()
|
||||
{
|
||||
$token = $_GET['token'] ?? null;
|
||||
if (!$token) {
|
||||
if (! $token) {
|
||||
$_SESSION['error'] = "Invalid or expired link.";
|
||||
header('Location: /account/login');
|
||||
exit;
|
||||
} else {
|
||||
$link = magic_links::validateToken(token: $token);
|
||||
if (!$link) {
|
||||
if (! $link) {
|
||||
$_SESSION['error'] = "Invalid or expired link.";
|
||||
header('Location: /account/login');
|
||||
exit;
|
||||
|
@ -24,7 +25,7 @@ class magic_link
|
|||
if ($user) { // user with this email exists, log them in
|
||||
$_SESSION['user_email'] = $link['email'];
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
if (!$user['verified']) {
|
||||
if (! $user['verified']) {
|
||||
users::verify($link['email']);
|
||||
}
|
||||
header('Location: /account');
|
||||
|
@ -36,7 +37,7 @@ class magic_link
|
|||
users::updateEmailById($user_id, $link['email']);
|
||||
$_SESSION['user_email'] = $link['email'];
|
||||
$_SESSION['user_id'] = $user_id;
|
||||
if (!$user['verified']) {
|
||||
if (! $user['verified']) {
|
||||
users::verify($link['email']);
|
||||
}
|
||||
header('Location: /account');
|
||||
|
|
|
@ -1,34 +1,35 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
class support
|
||||
{
|
||||
public static function index($defaults)
|
||||
{
|
||||
$GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
$GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'support/ask.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ': Frequently Asked Questions',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Support'
|
||||
]
|
||||
]
|
||||
'title' => 'Support',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
public static function bitcoin($defaults)
|
||||
{
|
||||
$GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
$GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'support/bitcoin.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Bitcoin Accepted',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/support/ask',
|
||||
'title' => 'Support'
|
||||
'title' => 'Support',
|
||||
],
|
||||
[
|
||||
'url' => null,
|
||||
'title' => 'Bitcoin'
|
||||
]
|
||||
'title' => 'Bitcoin',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
<?php
|
||||
namespace app\controllers;
|
||||
|
||||
use app\controllers\lost;
|
||||
use app\models\transactions;
|
||||
use app\models\users;
|
||||
|
||||
use app\controllers\lost;
|
||||
|
||||
class transaction
|
||||
{
|
||||
public static function view($defaults, $txid)
|
||||
{
|
||||
$tx = transactions::getById($txid);
|
||||
if (!$tx) {
|
||||
if (! $tx) {
|
||||
lost::index($defaults);
|
||||
}
|
||||
$user = users::getById($tx['user_id']);
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'transaction.twig',
|
||||
'page_title' => 'Transaction Reciept #' . $txid,
|
||||
'tx' => $tx,
|
||||
|
@ -23,69 +22,69 @@ class transaction
|
|||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => "/transaction/" . $txid,
|
||||
'title' => 'Transaction Reciept'
|
||||
]
|
||||
'title' => 'Transaction Reciept',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function users($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/users.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Users',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/users',
|
||||
'title' => 'Users'
|
||||
]
|
||||
'title' => 'Users',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function orders($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/orders.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Orders',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/orders',
|
||||
'title' => 'Orders'
|
||||
]
|
||||
'title' => 'Orders',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function returns($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/returns.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Returns',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/returns',
|
||||
'title' => 'Returns'
|
||||
]
|
||||
'title' => 'Returns',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public static function transactions($defaults)
|
||||
{
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/transactions/index.twig',
|
||||
'page_title' => $_ENV['APP_NAME'] . ' Transactions',
|
||||
'recent_sats' => transactions::getRecent(10, 'sats'),
|
||||
|
@ -97,12 +96,12 @@ class transaction
|
|||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
]
|
||||
'title' => 'Transactions',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
@ -113,23 +112,23 @@ class transaction
|
|||
$amount = $_POST['amount'] ?? null;
|
||||
$currency = $_POST['currency'];
|
||||
$user_identifier = $_POST['user_identifier'] ?? null;
|
||||
if (!$amount || !$user_identifier) {
|
||||
$_SESSION['error'] = !$amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction.";
|
||||
if (! $amount || ! $user_identifier) {
|
||||
$_SESSION['error'] = ! $amount ? "Please enter an amount for the transaction." : "Please enter a user email or id for the transaction.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
} else {
|
||||
if (strpos($user_identifier, '@') !== false && strpos($user_identifier, '.') !== false) {
|
||||
$user = users::getByEmail($user_identifier);
|
||||
} elseif (is_numeric($user_identifier)) {
|
||||
$user = users::getById((int)$user_identifier);
|
||||
$user = users::getById((int) $user_identifier);
|
||||
} else {
|
||||
$_SESSION['error'] = "Invalid user identifier. Please enter a valid email or user ID.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
}
|
||||
if (!$user) {
|
||||
if (! $user) {
|
||||
$_SESSION['error'] = "User not found. Please enter a valid email or user ID.";
|
||||
$_SESSION['last_post'] = $_POST;
|
||||
} else {
|
||||
if($_POST['confirm']){
|
||||
if ($_POST['confirm']) {
|
||||
// create the transaction
|
||||
$txid = transactions::add($user['id'], 'CREDIT', $currency == 'cents' ? $amount : 0, $currency == 'sats' ? $amount : 0);
|
||||
header('Location: /transaction/' . $txid);
|
||||
|
@ -143,22 +142,22 @@ class transaction
|
|||
}
|
||||
}
|
||||
}
|
||||
echo $GLOBALS['twig']->render('lib/page/index.twig', array_merge($defaults, [
|
||||
echo $GLOBALS['twig']->render('lib/pages/index.twig', array_merge($defaults, [
|
||||
'child_template' => 'admin/transactions/add.twig',
|
||||
'page_title' => 'Add a Transaction',
|
||||
'breadcrumbs' => [
|
||||
[
|
||||
'url' => '/admin',
|
||||
'title' => 'Admin'
|
||||
'title' => 'Admin',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions',
|
||||
'title' => 'Transactions'
|
||||
'title' => 'Transactions',
|
||||
],
|
||||
[
|
||||
'url' => '/admin/transactions/add',
|
||||
'title' => 'Add'
|
||||
]
|
||||
'title' => 'Add',
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
namespace app\models;
|
||||
|
||||
use app\app;
|
||||
|
||||
class addresses
|
||||
{
|
||||
public static function init()
|
||||
{
|
||||
app::$db->exec("CREATE TABLE IF NOT EXISTS addresses (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER,
|
||||
name TEXT NOT NULL,
|
||||
company TEXT,
|
||||
addressLine1 TEXT NOT NULL,
|
||||
|
@ -16,57 +18,131 @@ class addresses
|
|||
state TEXT NOT NULL,
|
||||
zip TEXT NOT NULL,
|
||||
phone TEXT,
|
||||
billing BOOLEAN NOT NULL,
|
||||
shipping BOOLEAN NOT NULL
|
||||
hash TEXT NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
)");
|
||||
}
|
||||
|
||||
public static function validatePost($type)
|
||||
public static function validatePost($type = "")
|
||||
{
|
||||
$name = $_POST["{$type}_name"];
|
||||
$company = $_POST["{$type}_company"] ?? null;
|
||||
$addressLine2 = $_POST["{$type}_addressLine2"] ?? null;
|
||||
$addressLine1 = $_POST["{$type}_addressLine1"];
|
||||
$city = $_POST["{$type}_city"];
|
||||
$state = $_POST["{$type}_state"];
|
||||
$zip = $_POST["{$type}_zip"];
|
||||
$phone = $_POST["{$type}_phone"];
|
||||
$name = $_POST["{$type}name"];
|
||||
$company = $_POST["{$type}company"] ?? null;
|
||||
$addressLine2 = $_POST["{$type}addressLine2"] ?? null;
|
||||
$addressLine1 = $_POST["{$type}addressLine1"];
|
||||
$city = $_POST["{$type}city"];
|
||||
$state = $_POST["{$type}state"];
|
||||
$zip = $_POST["{$type}zip"];
|
||||
$phone = $_POST["{$type}phone"];
|
||||
$email = $_POST["{$type}email"] ?? null; // Assuming email is part of the form
|
||||
|
||||
// check all required fields are set
|
||||
if (empty($name) || empty($addressLine1) || empty($city) || empty($state) || empty($zip) || empty($phone)) {
|
||||
$_SESSION['error'] = "Missing required {$type} information.";
|
||||
}
|
||||
$url = "https://nominatim.openstreetmap.org/search?" . http_build_query([
|
||||
"q" => implode(" ", array_filter([$addressLine1, $addressLine2, $city, $state, $zip])),
|
||||
"format" => "json",
|
||||
"addressdetails" => 1,
|
||||
"limit" => 1
|
||||
]);
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, "AddressValidator/1.0");
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$data = json_decode($response, true);
|
||||
if (empty($data)) {
|
||||
return ["error" => "Address not found"];
|
||||
}
|
||||
$addressDetails = $data[0]['address'];
|
||||
return [
|
||||
'name' => $name,
|
||||
'company' => $company,
|
||||
"addressLine1" => ($addressDetails['house_number'] ?? '') . ' ' . ($addressDetails['building'] ?? '') . ' ' . ($addressDetails['road'] ?? ''),
|
||||
"addressLine2" => $addressLine2,
|
||||
"city" => $addressDetails['city'] ?? $addressDetails['town'] ?? $addressDetails['village'] ?? '',
|
||||
"state" => $addressDetails['state_code'] ?? ($addressDetails['state'] ?? ''),
|
||||
"zip" => $addressDetails['postcode'] ?? '',
|
||||
'phone' => $phone
|
||||
];
|
||||
return ["error" => "Missing required {$type} information."];
|
||||
}
|
||||
|
||||
public static function add($name, $company, $addressLine1, $addressLine2, $city, $state, $zip, $phone, $billing, $shipping)
|
||||
// Set up the cURL request
|
||||
$ch = curl_init();
|
||||
|
||||
// Set the Shippo API endpoint for address validation
|
||||
$url = sprintf(
|
||||
'https://api.goshippo.com/v2/addresses/validate?address_line_1=%s&city_locality=%s&state_province=%s&postal_code=%s&country_code=US&organization=%s',
|
||||
urlencode($addressLine1),
|
||||
urlencode($city),
|
||||
urlencode($state),
|
||||
urlencode($zip),
|
||||
urlencode($company)
|
||||
);
|
||||
|
||||
// Set the cURL options
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Authorization: ShippoToken ' . $_ENV['SHIPPO_API_KEY'],
|
||||
]);
|
||||
|
||||
// Execute the cURL request
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$validated_address = json_decode($response, true);
|
||||
// print_r($response);
|
||||
// Check the status of the validation
|
||||
if (isset($validated_address['analysis']['validation_result']['value']) && $validated_address['analysis']['validation_result']['value'] === 'valid') {
|
||||
$result = [
|
||||
'name' => $name,
|
||||
'company' => $company,
|
||||
"addressLine1" => $addressLine1,
|
||||
"addressLine2" => $addressLine2,
|
||||
"city" => $city,
|
||||
"state" => $state,
|
||||
"zip" => $zip,
|
||||
'phone' => $phone,
|
||||
];
|
||||
} elseif (isset($validated_address['recommended_address']['confidence_result']['score']) && $validated_address['recommended_address']['confidence_result']['score'] === 'high') {
|
||||
$recommended = $validated_address['recommended_address'];
|
||||
$result = [
|
||||
'name' => $name,
|
||||
'company' => $company,
|
||||
"addressLine1" => $recommended['address_line_1'],
|
||||
"addressLine2" => $addressLine2,
|
||||
"city" => $recommended['city_locality'],
|
||||
"state" => $recommended['state_province'],
|
||||
"zip" => $recommended['postal_code'],
|
||||
'phone' => $phone,
|
||||
];
|
||||
} else {
|
||||
$error_message = "Address is invalid.";
|
||||
if (isset($validated_address['analysis']['validation_result']['reasons'])) {
|
||||
foreach ($validated_address['analysis']['validation_result']['reasons'] as $reason) {
|
||||
if ($reason['type'] === 'error') {
|
||||
$error_message = $reason['description'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$_SESSION['error'] = $error_message;
|
||||
return ["error" => $error_message];
|
||||
}
|
||||
$result['hash'] = hash("sha256", json_encode($result));
|
||||
$existing = self::getByHash($result['hash']);
|
||||
if ($existing) {
|
||||
$_SESSION['error'] = "The address already exists.";
|
||||
return ["error" => $_SESSION['error']];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function updateUserIdById($bill_id, $user_id)
|
||||
{
|
||||
$query = "UPDATE addresses SET user_id = :user_id WHERE id = :bill_id";
|
||||
$stmt = app::$db->prepare($query);
|
||||
$stmt->bindParam(':user_id', $user_id);
|
||||
$stmt->bindParam(':bill_id', $bill_id);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
public static function getByHash($hash)
|
||||
{
|
||||
$query = "SELECT * FROM addresses WHERE hash = :hash";
|
||||
$stmt = app::$db->prepare($query);
|
||||
$stmt->bindParam(':hash', $hash);
|
||||
$stmt->execute();
|
||||
return $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
public static function getByUserId($user_id)
|
||||
{
|
||||
$query = "SELECT * FROM addresses WHERE user_id = :user_id";
|
||||
$stmt = app::$db->prepare($query);
|
||||
$stmt->bindParam(':user_id', $user_id);
|
||||
$stmt->execute();
|
||||
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
public static function add($user_id, $name, $company, $addressLine1, $addressLine2, $city, $state, $zip, $phone, $hash)
|
||||
{
|
||||
$query = "INSERT INTO addresses (
|
||||
user_id,
|
||||
name,
|
||||
company,
|
||||
addressLine1,
|
||||
|
@ -75,9 +151,9 @@ class addresses
|
|||
state,
|
||||
zip,
|
||||
phone,
|
||||
billing,
|
||||
shipping
|
||||
hash
|
||||
) VALUES (
|
||||
:user_id,
|
||||
:name,
|
||||
:company,
|
||||
:addressLine1,
|
||||
|
@ -86,10 +162,10 @@ class addresses
|
|||
:state,
|
||||
:zip,
|
||||
:phone,
|
||||
:billing,
|
||||
:shipping
|
||||
:hash
|
||||
)";
|
||||
$stmt = app::$db->prepare($query);
|
||||
$stmt->bindParam(':user_id', $user_id);
|
||||
$stmt->bindParam(':name', $name);
|
||||
$stmt->bindParam(':company', $company);
|
||||
$stmt->bindParam(':addressLine1', $addressLine1);
|
||||
|
@ -98,8 +174,7 @@ class addresses
|
|||
$stmt->bindParam(':state', $state);
|
||||
$stmt->bindParam(':zip', $zip);
|
||||
$stmt->bindParam(':phone', $phone);
|
||||
$stmt->bindParam(':billing', $billing);
|
||||
$stmt->bindParam(':shipping', $shipping);
|
||||
$stmt->bindParam(':hash', $hash);
|
||||
$stmt->execute();
|
||||
return app::$db->lastInsertId();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class cart_items
|
|||
$stmt->execute([
|
||||
'cart_id' => $cartId,
|
||||
'product_id' => $productId,
|
||||
'quantity' => $quantity
|
||||
'quantity' => $quantity,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ class cart_items
|
|||
$stmt = app::$db->prepare("UPDATE cart_items SET quantity = :quantity WHERE cart_item_id = :cart_item_id");
|
||||
$stmt->execute([
|
||||
'cart_item_id' => $cartItemId,
|
||||
'quantity' => $quantity
|
||||
'quantity' => $quantity,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
namespace app\models;
|
||||
|
||||
use app\app;
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
class emails
|
||||
{
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<?php
|
||||
namespace app\models;
|
||||
use app\models\transactions;
|
||||
|
||||
use app\app;
|
||||
use app\models\transactions;
|
||||
|
||||
class invoices
|
||||
{
|
||||
|
@ -93,4 +94,3 @@ class invoices
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class order_items
|
|||
$stmt->execute([
|
||||
'order_id' => $orderId,
|
||||
'product_id' => $productId,
|
||||
'quantity' => $quantity
|
||||
'quantity' => $quantity,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ class order_items
|
|||
$stmt = app::$db->prepare("UPDATE order_items SET quantity = :quantity WHERE order_item_id = :order_item_id");
|
||||
$stmt->execute([
|
||||
'order_item_id' => $orderItemId,
|
||||
'quantity' => $quantity
|
||||
'quantity' => $quantity,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ class orders
|
|||
{
|
||||
const STATUSES = [
|
||||
'SHIPPED', 'PENDING', 'HOLD', 'PARTIAL',
|
||||
'BACKORDER', 'FAILED', 'CANCELED', 'PROCESSING'
|
||||
'BACKORDER', 'FAILED', 'CANCELED', 'PROCESSING',
|
||||
];
|
||||
|
||||
public static function init()
|
||||
|
@ -33,7 +33,7 @@ class orders
|
|||
'user_id' => $userId,
|
||||
'value_sats' => $valueSats,
|
||||
'value_cents' => $valueCents,
|
||||
'status' => $status
|
||||
'status' => $status,
|
||||
]);
|
||||
|
||||
return app::$db->lastInsertId();
|
||||
|
@ -46,7 +46,7 @@ class orders
|
|||
$stmt = app::$db->prepare("UPDATE orders SET status = :status WHERE order_id = :order_id");
|
||||
$stmt->execute([
|
||||
'order_id' => $orderId,
|
||||
'status' => $status
|
||||
'status' => $status,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ class orders
|
|||
|
||||
private static function validateStatus(string $status)
|
||||
{
|
||||
if (!in_array($status, self::STATUSES, true)) {
|
||||
if (! in_array($status, self::STATUSES, true)) {
|
||||
throw new \InvalidArgumentException("Invalid order status: $status");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class products
|
|||
':image_url_8' => $images[8] ?? null,
|
||||
':image_url_9' => $images[9] ?? null,
|
||||
':image_url_10' => $images[10] ?? null,
|
||||
':image_url_11' => $images[11] ?? null
|
||||
':image_url_11' => $images[11] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class quote_items
|
|||
'quote_id' => $quoteId,
|
||||
'product_id' => $productId,
|
||||
'quantity' => $quantity,
|
||||
'price' => $price
|
||||
'price' => $price,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ class quote_items
|
|||
$stmt->execute([
|
||||
'quote_item_id' => $quoteItemId,
|
||||
'quantity' => $quantity,
|
||||
'price' => $price
|
||||
'price' => $price,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ class quotes
|
|||
{
|
||||
private const STATUSES = [
|
||||
'DRAFT', 'PUBLISHED', 'SENT', 'PURCHASED',
|
||||
'EXPIRED', 'CANCELED'
|
||||
'EXPIRED', 'CANCELED',
|
||||
];
|
||||
|
||||
public static function init()
|
||||
|
@ -29,7 +29,7 @@ class quotes
|
|||
VALUES (:user_id, :status)");
|
||||
$stmt->execute([
|
||||
'user_id' => $userId,
|
||||
'status' => $status
|
||||
'status' => $status,
|
||||
]);
|
||||
|
||||
return app::$db->lastInsertId();
|
||||
|
@ -42,7 +42,7 @@ class quotes
|
|||
$stmt = app::$db->prepare("UPDATE quotes SET status = :status WHERE quote_id = :quote_id");
|
||||
$stmt->execute([
|
||||
'quote_id' => $quoteId,
|
||||
'status' => $status
|
||||
'status' => $status,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ class quotes
|
|||
|
||||
private static function validateStatus(string $status)
|
||||
{
|
||||
if (!in_array($status, self::STATUSES, true)) {
|
||||
if (! in_array($status, self::STATUSES, true)) {
|
||||
throw new \InvalidArgumentException("Invalid quote status: $status");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ use app\app;
|
|||
class subscriptions
|
||||
{
|
||||
const STATES = [
|
||||
'TRIAL', 'START', 'RENEWAL'
|
||||
'TRIAL', 'START', 'RENEWAL',
|
||||
];
|
||||
|
||||
const STATUS = [
|
||||
'COMPLETED', 'CANCELED'
|
||||
'COMPLETED', 'CANCELED',
|
||||
];
|
||||
|
||||
public static function init()
|
||||
|
@ -29,7 +29,7 @@ class subscriptions
|
|||
);");
|
||||
}
|
||||
|
||||
public static function createSubscription( $userId, $productId, $state, $startDate, $renewAt, $invoiceDate)
|
||||
public static function createSubscription($userId, $productId, $state, $startDate, $renewAt, $invoiceDate)
|
||||
{
|
||||
self::validateState($state);
|
||||
self::validateStatus($status);
|
||||
|
@ -43,7 +43,7 @@ class subscriptions
|
|||
'status' => $status,
|
||||
'start_date' => $startDate,
|
||||
'renews_at' => $renewAt,
|
||||
'invoice_date' => $invoiceDate
|
||||
'invoice_date' => $invoiceDate,
|
||||
]);
|
||||
|
||||
return app::$db->lastInsertId();
|
||||
|
@ -56,7 +56,7 @@ class subscriptions
|
|||
$stmt = app::$db->prepare("UPDATE subscriptions SET state = :state WHERE subscription_id = :subscription_id");
|
||||
$stmt->execute([
|
||||
'subscription_id' => $subscriptionId,
|
||||
'state' => $state
|
||||
'state' => $state,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ class subscriptions
|
|||
$stmt = app::$db->prepare("UPDATE subscriptions SET status = :status WHERE subscription_id = :subscription_id");
|
||||
$stmt->execute([
|
||||
'subscription_id' => $subscriptionId,
|
||||
'status' => $status
|
||||
'status' => $status,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -87,14 +87,14 @@ class subscriptions
|
|||
|
||||
private static function validateState(string $state)
|
||||
{
|
||||
if (!in_array($state, self::STATES, true)) {
|
||||
if (! in_array($state, self::STATES, true)) {
|
||||
throw new \InvalidArgumentException("Invalid subscription state: $state");
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateStatus(string $status)
|
||||
{
|
||||
if (!in_array($status, self::STATUS, true)) {
|
||||
if (! in_array($status, self::STATUS, true)) {
|
||||
throw new \InvalidArgumentException("Invalid subscription status: $status");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class transactions
|
|||
|
||||
public static function add($user_id, $transaction_type, $cents, $sats)
|
||||
{
|
||||
if (!in_array($transaction_type, self::TYPES)) {
|
||||
if (! in_array($transaction_type, self::TYPES)) {
|
||||
throw new \Exception("Invalid transaction type.");
|
||||
}
|
||||
if ($cents < 0 || $sats < 0) {
|
||||
|
@ -72,7 +72,7 @@ class transactions
|
|||
|
||||
public static function getWhales($n, $currency)
|
||||
{
|
||||
if (!in_array($currency, ['cents', 'sats'])) {
|
||||
if (! in_array($currency, ['cents', 'sats'])) {
|
||||
throw new \Exception("Invalid currency type.");
|
||||
}
|
||||
$query = "SELECT user_id, COALESCE(SUM($currency), 0) AS total FROM transactions GROUP BY user_id ORDER BY total DESC LIMIT :n";
|
||||
|
@ -84,7 +84,7 @@ class transactions
|
|||
|
||||
public static function getLiabilities($currency)
|
||||
{
|
||||
if (!in_array($currency, ['cents', 'sats'])) {
|
||||
if (! in_array($currency, ['cents', 'sats'])) {
|
||||
throw new \Exception("Invalid currency type.");
|
||||
}
|
||||
$query = "SELECT COALESCE(SUM($currency), 0) AS total FROM transactions";
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
namespace app\models;
|
||||
|
||||
use app\app;
|
||||
use PDO; // Added PDO class import
|
||||
|
||||
class user_addresses
|
||||
{
|
||||
public static function init()
|
||||
{
|
||||
app::$db->exec("CREATE TABLE IF NOT EXISTS user_addresses (
|
||||
user_id INTEGER NOT NULL,
|
||||
address_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (user_id, address_id),
|
||||
FOREIGN KEY (address_id) REFERENCES addresses(id)
|
||||
)");
|
||||
}
|
||||
|
||||
public static function getShippingByUserId($id)
|
||||
{
|
||||
$query = "SELECT a.* FROM users u
|
||||
JOIN user_addresses ua ON u.id = ua.user_id
|
||||
JOIN addresses a ON ua.address_id = a.id
|
||||
WHERE u.id = :id AND a.shipping = 1";
|
||||
$stmt = app::$db->prepare($query);
|
||||
$stmt->bindParam(':id', $id);
|
||||
$stmt->execute();
|
||||
$addrs = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
return [$addrs];
|
||||
}
|
||||
|
||||
public static function getBillingByUserId($id)
|
||||
{
|
||||
$query = "SELECT a.* FROM users u
|
||||
JOIN user_addresses ua ON u.id = ua.user_id
|
||||
JOIN addresses a ON ua.address_id = a.id
|
||||
WHERE u.id = :id AND a.billing = 1";
|
||||
$stmt = app::$db->prepare($query);
|
||||
$stmt->bindParam(':id', $id);
|
||||
$stmt->execute();
|
||||
$addrs = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
return [$addrs];
|
||||
}
|
||||
|
||||
public static function add($user_id, $address_id)
|
||||
{
|
||||
$query = "INSERT INTO user_addresses (
|
||||
user_id,
|
||||
address_id
|
||||
) VALUES (
|
||||
:user_id,
|
||||
:address_id
|
||||
)";
|
||||
$stmt = app::$db->prepare($query);
|
||||
$stmt->bindParam(':user_id', $user_id);
|
||||
$stmt->bindParam(':address_id', $address_id);
|
||||
$stmt->execute();
|
||||
return app::$db->lastInsertId();
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
namespace app\models;
|
||||
|
||||
use app\app;
|
||||
use app\models\addresses;
|
||||
use swentel\nostr\Key\Key;
|
||||
|
||||
class users
|
||||
|
@ -113,7 +114,12 @@ class users
|
|||
$stmt->bindParam(':nsec', $nsec);
|
||||
$stmt->bindParam(':npub', $npub);
|
||||
$stmt->execute();
|
||||
return app::$db->lastInsertId();
|
||||
$user_id = app::$db->lastInsertId();
|
||||
addresses::updateUserIdById($ship_id, $user_id);
|
||||
if ($ship_id != $bill_id) {
|
||||
addresses::updateUserIdById($bill_id, $user_id);
|
||||
}
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
public static function verify($email)
|
||||
|
|
|
@ -22,4 +22,3 @@ use app\models\invoices;
|
|||
|
||||
app::init_db();
|
||||
invoices::checkAll();
|
||||
|
||||
|
|
|
@ -13,48 +13,33 @@ Dotenv\Dotenv::createImmutable(__DIR__ . '/../../')->load();
|
|||
use app\app;
|
||||
app::init_db();
|
||||
|
||||
// db models go brrr...
|
||||
use app\models\addresses;
|
||||
addresses::init();
|
||||
|
||||
use app\models\cart_items;
|
||||
cart_items::init();
|
||||
|
||||
use app\models\carts;
|
||||
carts::init();
|
||||
|
||||
use app\models\cart_items;
|
||||
use app\models\emails;
|
||||
emails::init();
|
||||
|
||||
use app\models\invoices;
|
||||
invoices::init();
|
||||
|
||||
use app\models\magic_links;
|
||||
magic_links::init();
|
||||
|
||||
use app\models\order_items;
|
||||
order_items::init();
|
||||
|
||||
use app\models\orders;
|
||||
orders::init();
|
||||
|
||||
use app\models\order_items;
|
||||
use app\models\products;
|
||||
products::init();
|
||||
|
||||
use app\models\quote_items;
|
||||
quote_items::init();
|
||||
|
||||
use app\models\quotes;
|
||||
quotes::init();
|
||||
|
||||
use app\models\quote_items;
|
||||
use app\models\subscriptions;
|
||||
subscriptions::init();
|
||||
|
||||
use app\models\transactions;
|
||||
transactions::init();
|
||||
|
||||
use app\models\user_addresses;
|
||||
user_addresses::init();
|
||||
|
||||
use app\models\users;
|
||||
|
||||
// db models go brrr...
|
||||
addresses::init();
|
||||
carts::init();
|
||||
cart_items::init();
|
||||
emails::init();
|
||||
invoices::init();
|
||||
magic_links::init();
|
||||
order_items::init();
|
||||
orders::init();
|
||||
products::init();
|
||||
quote_items::init();
|
||||
quotes::init();
|
||||
subscriptions::init();
|
||||
transactions::init();
|
||||
users::init();
|
||||
|
|
1
src/views/account/address/confirm.twig
Normal file
1
src/views/account/address/confirm.twig
Normal file
|
@ -0,0 +1 @@
|
|||
confirm the address
|
1
src/views/account/address/edit.twig
Normal file
1
src/views/account/address/edit.twig
Normal file
|
@ -0,0 +1 @@
|
|||
edit the address
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Payment Methods</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Payment Methods
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
{% include 'lib/empty.twig' with {
|
||||
|
@ -11,20 +13,25 @@
|
|||
subtitle: 'Add a payment method'
|
||||
} %}
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Billing Address</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Billing Address
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
<p class="text-xs">Your billing information must match the information associatied with the credit card making the purchase.</p>
|
||||
<div class='flex flex-col'>
|
||||
<span>{{ default_billing.name }}</span>
|
||||
<span>{{ default_billing.company }}</span>
|
||||
<span>{{ default_billing.addressLine1 }}</span>
|
||||
<span>{{ default_billing.addressLine2 }}</span>
|
||||
<span>{{ default_billing.city }}, {{ default_billing.state }} {{ default_billing.zip }}</span>
|
||||
<span>{{ default_billing.phone }}</span>
|
||||
</div>
|
||||
<p class="text-xs">
|
||||
Your billing information must match the information associatied with the credit card making the purchase.
|
||||
</p>
|
||||
{% for address in addresses %}
|
||||
{% if address.id == user.billing_address_id %}
|
||||
{% include 'lib/address.twig' with {
|
||||
address: address,
|
||||
edit_url: '/account/billing/edit/' ~ address.id,
|
||||
delete_url: '/account/billing/delete/' ~ address.id
|
||||
} %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<form action="/account/billing" method="post" class="flex flex-col gap-2">
|
||||
{% include 'lib/form/address.twig' with {
|
||||
{% include 'lib/forms/address.twig' with {
|
||||
action: 'billing'
|
||||
} %}
|
||||
{% include 'lib/button.twig' with {
|
||||
|
@ -32,9 +39,17 @@
|
|||
onclick: 'this.parentNode.submit()',
|
||||
} %}
|
||||
</form>
|
||||
{% if addresses|length > 1 %}
|
||||
{% include 'lib/rule.twig' with {
|
||||
text: 'OR'
|
||||
} %}
|
||||
<span>Use saved address</span>
|
||||
{% for address in addresses %}
|
||||
{% include 'lib/address.twig' with {
|
||||
address: address,
|
||||
edit_url: '/account/billing/edit/' ~ address.id,
|
||||
delete_url: '/account/billing/delete/' ~ address.id
|
||||
} %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
|
@ -1,10 +1,12 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
{% include 'lib/alert.twig' %}
|
||||
<h3 class="text-2xl font-semibold">Profile</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Profile
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
<form action="/account/profile" method="post">
|
||||
{% include 'lib/form/profile.twig' with {
|
||||
{% include 'lib/forms/profile.twig' with {
|
||||
name: user.name,
|
||||
company_name: user.company_name,
|
||||
company_type: user.company_type,
|
||||
|
@ -17,14 +19,19 @@
|
|||
</form>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Email</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Email
|
||||
</h3>
|
||||
<form action="/account/email" method="post">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: 'email',
|
||||
value: user.email
|
||||
} %}
|
||||
<h4 class="font-semibold">Verified: {{ user.verified ? 'Yes' : 'No' }}</h4>
|
||||
<h4 class="font-semibold">
|
||||
Verified:
|
||||
{{ user.verified ? 'Yes' : 'No' }}
|
||||
</h4>
|
||||
{% include 'lib/button.twig' with {
|
||||
label: 'Save Email',
|
||||
onclick: 'this.parentNode.submit()',
|
||||
|
@ -33,66 +40,102 @@
|
|||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-2xl font-semibold">Shipping</h3>
|
||||
<a href="/account/shipping">Edit</a>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Shipping
|
||||
</h3>
|
||||
<a href="/account/shipping">
|
||||
Edit
|
||||
</a>
|
||||
</div>
|
||||
{% include 'lib/rule.twig' %}
|
||||
<div class="flex flex-col gap-1">
|
||||
<h4 class="font-semibold">{{ default_shipping.name }}</h4>
|
||||
<h4 class="font-semibold">{{ default_shipping.company }}</h4>
|
||||
<h4 class="font-semibold">{{ default_shipping.addressLine1 }}</h4>
|
||||
<h4 class="font-semibold">{{ default_billing.addressLine2 }}</h4>
|
||||
<h4 class="font-semibold">{{ default_shipping.city }}, {{ default_shipping.state }}, {{ default_shipping.zip }}</h4>
|
||||
<h4 class="font-semibold">{{ default_shipping.phone }}</h4>
|
||||
</div>
|
||||
{% for address in addresses %}
|
||||
{% if address.id == user.shipping_address_id %}
|
||||
{% include 'lib/address.twig' with {
|
||||
address: address,
|
||||
edit_url: '/account/shipping/edit/' ~ address.id,
|
||||
delete_url: '/account/shipping/delete/' ~ address.id
|
||||
} %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-2xl font-semibold">Billing</h3>
|
||||
<a href="/account/billing">Edit</a>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Billing
|
||||
</h3>
|
||||
<a href="/account/billing">
|
||||
Edit
|
||||
</a>
|
||||
</div>
|
||||
{% include 'lib/rule.twig' %}
|
||||
<div class="flex flex-col gap-1">
|
||||
<h4 class="font-semibold">{{ default_billing.name }}</h4>
|
||||
<h4 class="font-semibold">{{ default_billing.company }}</h4>
|
||||
<h4 class="font-semibold">{{ default_billing.addressLine1 }}</h4>
|
||||
<h4 class="font-semibold">{{ default_billing.addressLine2 }}</h4>
|
||||
<h4 class="font-semibold">{{ default_billing.city }}, {{ default_billing.state }}, {{ default_billing.zip }}</h4>
|
||||
<h4 class="font-semibold">{{ default_billing.phone }}</h4>
|
||||
</div>
|
||||
{% for address in addresses %}
|
||||
{% if address.id == user.billing_address_id %}
|
||||
{% include 'lib/address.twig' with {
|
||||
address: address,
|
||||
edit_url: '/account/billing/edit/' ~ address.id,
|
||||
delete_url: '/account/billing/delete/' ~ address.id
|
||||
} %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-2xl font-semibold">Credit Card</h3>
|
||||
<a href="/account/billing">Edit</a>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Credit Card
|
||||
</h3>
|
||||
<a href="/account/billing">
|
||||
Edit
|
||||
</a>
|
||||
</div>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="text-2xl font-semibold">Store Credit</h3>
|
||||
<a href='#store-credit'><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg></a>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Store Credit
|
||||
</h3>
|
||||
<a href='#store-credit'>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M12 16v-4" />
|
||||
<path d="M12 8h.01" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<span>$0.00</span>
|
||||
<span>
|
||||
$0.00
|
||||
</span>
|
||||
</div>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="text-2xl font-semibold">Sats</h3>
|
||||
<a href='#sats'><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg></a>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Sats
|
||||
</h3>
|
||||
<a href='#sats'>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M12 16v-4" />
|
||||
<path d="M12 8h.01" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<span>0</span>
|
||||
<span>
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Marketing</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Marketing
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
<form action="/account/promotionals" method="post" class="flex flex-col gap-4">
|
||||
{% include 'lib/toggle.twig' with {
|
||||
{% include 'lib/inputs/toggle.twig' with {
|
||||
label: 'Recieve coupons & more',
|
||||
name: 'opt_in_promotional',
|
||||
on: user.opt_in_promotional
|
||||
|
@ -106,9 +149,9 @@
|
|||
</section>
|
||||
{% include 'lib/modal.twig' with {
|
||||
id: 'store-credit',
|
||||
content: 'lib/policy/credit.twig'
|
||||
content: 'lib/modals/credit.twig'
|
||||
} %}
|
||||
{% include 'lib/modal.twig' with {
|
||||
id: 'sats',
|
||||
content: 'lib/policy/sats.twig'
|
||||
content: 'lib/modals/sats.twig'
|
||||
} %}
|
|
@ -1,12 +1,14 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col gap-1 mb-4">
|
||||
<h3 class="text-2xl font-semibold">Login</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Login
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
{% include 'lib/alert.twig' %}
|
||||
<form action="/account/login" method="post" class="flex flex-col gap-4">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'email',
|
||||
name: 'email',
|
||||
label: 'Email link',
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<section>
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Order History</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Order History
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
{% include 'lib/empty.twig' with {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<section>
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Returns</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Returns
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
{% include 'lib/empty.twig' with {
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
<div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Saved Shipping Address</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Saved Shipping Address
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
<p class="text-xs">This is your default shipping address for orders at checkout.</p>
|
||||
</div>
|
||||
<div class='flex flex-col'>
|
||||
<span>{{ default_shipping.name }}</span>
|
||||
<span>{{ default_shipping.company }}</span>
|
||||
<span>{{ default_shipping.addressLine1 }}</span>
|
||||
<span>{{ default_shipping.addressLine2 }}</span>
|
||||
<span>{{ default_shipping.city }}, {{ default_shipping.state }} {{ default_shipping.zip }}</span>
|
||||
<span>{{ default_shipping.phone }}</span>
|
||||
<p class="text-xs">
|
||||
This is your default shipping address for orders at checkout.
|
||||
</p>
|
||||
</div>
|
||||
{% for address in addresses %}
|
||||
{% if address.id == user.shipping_address_id %}
|
||||
{% include 'lib/address.twig' with {
|
||||
address: address,
|
||||
edit_url: '/account/shipping/edit/' ~ address.id,
|
||||
delete_url: '/account/shipping/delete/' ~ address.id
|
||||
} %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<form action="/account/shipping" method="post" class="flex flex-col gap-2">
|
||||
{% include 'lib/form/address.twig' with {
|
||||
{% include 'lib/forms/address.twig' with {
|
||||
action: 'shipping'
|
||||
} %}
|
||||
{% include 'lib/button.twig' with {
|
||||
|
@ -23,9 +28,17 @@
|
|||
onclick: 'this.parentNode.submit()'
|
||||
} %}
|
||||
</form>
|
||||
{% if addresses|length > 1 %}
|
||||
{% include 'lib/rule.twig' with {
|
||||
text: 'OR'
|
||||
} %}
|
||||
<span>Use a saved address</span>
|
||||
{% for address in addresses %}
|
||||
{% include 'lib/address.twig' with {
|
||||
address: address,
|
||||
edit_url: '/account/billing/edit/' ~ address.id,
|
||||
delete_url: '/account/billing/delete/' ~ address.id
|
||||
} %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
</section>
|
|
@ -1,26 +1,34 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col">
|
||||
<h3 class="font-semibold text-4xl">Create an Account</h3>
|
||||
<span class="text-sm">You can manage all your orders, addresses, and payment cards in one place!</span>
|
||||
<h3 class="font-semibold text-4xl">
|
||||
Create an Account
|
||||
</h3>
|
||||
<span class="text-sm">
|
||||
You can manage all your orders, addresses, and payment cards in one place!
|
||||
</span>
|
||||
</div>
|
||||
{% include 'lib/alert.twig' %}
|
||||
<form action="/account/signup" method="post" class="flex flex-col gap-4">
|
||||
{% include 'lib/rule.twig' with { text: 'STEP 1' } %}
|
||||
<div class="flex flex-col">
|
||||
<h4 class="font-semibold text-2xl">Email Address</h4>
|
||||
<span class="text-sm">Recieve login link to verify. Order and account updates will be sent here.</span>
|
||||
<h4 class="font-semibold text-2xl">
|
||||
Email Address
|
||||
</h4>
|
||||
<span class="text-sm">
|
||||
Recieve login link to verify. Order and account updates will be sent here.
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-full flex items-center justify-between gap-4">
|
||||
<div class="w-3/5">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: 'email',
|
||||
value: session.user_email is defined ? session.user_email : null,
|
||||
readonly: session.user_email is defined ? true : null
|
||||
} %}
|
||||
</div>
|
||||
{% include 'lib/toggle.twig' with {
|
||||
{% include 'lib/inputs/toggle.twig' with {
|
||||
label: 'Recieve coupons & more',
|
||||
name: 'opt_in_promotional',
|
||||
on: true
|
||||
|
@ -28,10 +36,14 @@
|
|||
</div>
|
||||
{% include 'lib/rule.twig' with { text: 'STEP 2' } %}
|
||||
<div class="flex flex-col">
|
||||
<h4 class="font-semibold text-2xl">Shipping Address</h4>
|
||||
<span class="text-sm">Your orders will ship to this address (USA only).</span>
|
||||
<h4 class="font-semibold text-2xl">
|
||||
Shipping Address
|
||||
</h4>
|
||||
<span class="text-sm">
|
||||
Your orders will ship to this address (USA only).
|
||||
</span>
|
||||
</div>
|
||||
{% include 'lib/form/address.twig' with {
|
||||
{% include 'lib/forms/address.twig' with {
|
||||
action: 'shipping',
|
||||
name: session.last_post.shipping_name,
|
||||
addressLine1: session.last_post.shipping_addressLine1,
|
||||
|
@ -45,18 +57,22 @@
|
|||
{% include 'lib/rule.twig' with { text: 'STEP 3' } %}
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-col">
|
||||
<h4 class="font-semibold text-2xl">Billing Address</h4>
|
||||
<span class="text-sm">Info must match the credit card making the purchase. </span>
|
||||
<h4 class="font-semibold text-2xl">
|
||||
Billing Address
|
||||
</h4>
|
||||
<span class="text-sm">
|
||||
Info must match the credit card making the purchase.
|
||||
</span>
|
||||
</div>
|
||||
</h4>
|
||||
{% include 'lib/toggle.twig' with {
|
||||
{% include 'lib/inputs/toggle.twig' with {
|
||||
label: 'Same as shipping',
|
||||
name: 'use_shipping',
|
||||
on: true
|
||||
} %}
|
||||
</div>
|
||||
<div id="billing-address" style="display: none;">
|
||||
{% include 'lib/form/address.twig' with {
|
||||
{% include 'lib/forms/address.twig' with {
|
||||
action: 'billing',
|
||||
name: session.last_post.billing_name,
|
||||
addressLine1: session.last_post.billing_addressLine1,
|
||||
|
@ -75,8 +91,8 @@
|
|||
captcha: true
|
||||
} %}
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
</div>
|
||||
<script>
|
||||
// this bit-of-script handles show/hide the billing address form fields
|
||||
const useShippingCheckbox = document.getElementById('use_shipping');
|
||||
const billingAddress = document.getElementById('billing-address');
|
||||
|
@ -88,5 +104,4 @@
|
|||
billingAddress.style.display = 'flex';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</section>
|
||||
</script></section>
|
|
@ -1,8 +1,12 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col gap-1 mb-4">
|
||||
<h3 class="text-2xl font-semibold">Check Your Email</h3>
|
||||
<p>We have sent a verification code to your email.</p>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Check Your Email
|
||||
</h3>
|
||||
<p>
|
||||
We have sent a verification code to your email.
|
||||
</p>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
{% include 'lib/alert.twig' %}
|
||||
|
@ -67,4 +71,5 @@
|
|||
} %}
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -1,25 +1,45 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
<h3 class="text-2xl font-semibold">Recently Sent Emails</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Recently Sent Emails
|
||||
</h3>
|
||||
<table class="min-w-full bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="py-2">To</th>
|
||||
<th class="py-2">From</th>
|
||||
<th class="py-2">Subject</th>
|
||||
<th class="py-2">Created At</th>
|
||||
<th class="py-2">
|
||||
To
|
||||
</th>
|
||||
<th class="py-2">
|
||||
From
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Subject
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Created At
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for email in recent_emails %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2">{{ email.to_email }}</td>
|
||||
<td class="border px-4 py-2">{{ email.from_email }}</td>
|
||||
<td class="border px-4 py-2">{{ email.subject }}</td>
|
||||
<td class="border px-4 py-2">{{ email.created_at }}</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ email.to_email }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ email.from_email }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ email.subject }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ email.created_at }}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2" colspan="4">No recent emails found.</td>
|
||||
<td class="border px-4 py-2" colspan="4">
|
||||
No recent emails found.
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
<a href="/admin">Dashboard</a>
|
||||
<a href="/admin/users">Users</a>
|
||||
<a href="/admin/orders">Orders</a>
|
||||
<a href="/admin/returns">Returns</a>
|
||||
<a href="/admin/emails">Emails</a>
|
||||
<a href="/admin/transactions">Transactions</a>
|
||||
<a href="/admin">
|
||||
Dashboard
|
||||
</a>
|
||||
<a href="/admin/users">
|
||||
Users
|
||||
</a>
|
||||
<a href="/admin/orders">
|
||||
Orders
|
||||
</a>
|
||||
<a href="/admin/returns">
|
||||
Returns
|
||||
</a>
|
||||
<a href="/admin/emails">
|
||||
Emails
|
||||
</a>
|
||||
<a href="/admin/transactions">
|
||||
Transactions
|
||||
</a>
|
||||
|
||||
INDEX
|
||||
</section>
|
|
@ -6,10 +6,12 @@
|
|||
<input type="hidden" name="confirm" id="confirm" value="{{ session.last_post.confirm }}">
|
||||
{% endif %}
|
||||
{% if session.last_post.amount is defined %}
|
||||
{{ session.last_post.amount }} {{ session.last_post.currency }}
|
||||
<input type="hidden" name="amount" id="amount" value="{{ session.last_post.amount }}">
|
||||
{{ session.last_post.amount }}
|
||||
{{ session.last_post.currency }}
|
||||
<input
|
||||
type="hidden" name="amount" id="amount" value="{{ session.last_post.amount }}" />
|
||||
{% else %}
|
||||
{% include 'lib/number_input.twig' with {
|
||||
{% include 'lib/inputs/number.twig' with {
|
||||
id: 'amount',
|
||||
name: 'amount',
|
||||
label: 'Amount',
|
||||
|
@ -18,10 +20,11 @@
|
|||
required: true
|
||||
} %}
|
||||
{% endif %}
|
||||
{% if session.last_post.currency is defined %}
|
||||
<input type="hidden" name="currency" id="currency" value="{{ session.last_post.currency }}">
|
||||
{% if session.last_post.currency %}
|
||||
<input
|
||||
type="hidden" name="currency" id="currency" value="{{ session.last_post.currency }}" />
|
||||
{% else %}
|
||||
{% include 'lib/select.twig' with {
|
||||
{% include 'lib/inputs/select.twig' with {
|
||||
id: 'currency',
|
||||
name: 'currency',
|
||||
label: 'Currency',
|
||||
|
@ -35,11 +38,13 @@
|
|||
{% endif %}
|
||||
{% if session.last_post.user_identifier is defined %}
|
||||
{% if session.last_post.email is defined %}
|
||||
{{ session.last_post.id }} {{ session.last_post.email }}
|
||||
{{ session.last_post.id }}
|
||||
{{ session.last_post.email }}
|
||||
{% endif %}
|
||||
<input type="hidden" name="user_identifier" id="user_identifier" value="{{ session.last_post.user_identifier }}">
|
||||
<input
|
||||
type="hidden" name="user_identifier" id="user_identifier" value="{{ session.last_post.user_identifier }}" />
|
||||
{% else %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: 'user_identifier',
|
||||
label: 'User Identifier',
|
||||
|
@ -58,4 +63,5 @@
|
|||
href: '/admin/transactions/reset'
|
||||
} %}
|
||||
{% endif %}
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
{% include 'lib/alert.twig' %}
|
||||
<form action="/admin/transactions/add" method="post" class="flex flex-col gap-4">
|
||||
{% include 'lib/number_input.twig' with {
|
||||
{% include 'lib/inputs/number.twig' with {
|
||||
id: 'amount',
|
||||
name: 'amount',
|
||||
label: 'Amount',
|
||||
required: true
|
||||
} %}
|
||||
{% include 'lib/select.twig' with {
|
||||
{% include 'lib/inputs/select.twig' with {
|
||||
id: 'currency',
|
||||
name: 'currency',
|
||||
label: 'Currency',
|
||||
|
@ -23,120 +23,190 @@
|
|||
} %}
|
||||
</form>
|
||||
|
||||
<h3 class="text-2xl font-semibold">Liabilities</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Liabilities
|
||||
</h3>
|
||||
<table class="min-w-full bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="py-2">Currency</th>
|
||||
<th class="py-2">Total Liability</th>
|
||||
<th class="py-2">
|
||||
Currency
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Total Liability
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="border px-4 py-2">Sats</td>
|
||||
<td class="border px-4 py-2">{{ sats_liability }}</td>
|
||||
<td class="border px-4 py-2">
|
||||
Sats
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ sats_liability }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border px-4 py-2">Cents</td>
|
||||
<td class="border px-4 py-2">{{ cents_liability }}</td>
|
||||
<td class="border px-4 py-2">
|
||||
Cents
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ cents_liability }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 class="text-2xl font-semibold">Sats Transactions</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Sats Transactions
|
||||
</h3>
|
||||
<table class="min-w-full bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="py-2">Type</th>
|
||||
<th class="py-2">Amount (Sats)</th>
|
||||
<th class="py-2">Date</th>
|
||||
<th class="py-2">
|
||||
Type
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Amount (Sats)
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Date
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if recent_sats is not empty %}
|
||||
{% for transaction in recent_sats %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2">{{ transaction.type }}</td>
|
||||
<td class="border px-4 py-2">{{ transaction.sats }}</td>
|
||||
<td class="border px-4 py-2">{{ transaction.date }}</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ transaction.type }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ transaction.sats }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ transaction.date }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2" colspan="3">No Sats transactions available.</td>
|
||||
<td class="border px-4 py-2" colspan="3">
|
||||
No Sats transactions available.
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3 class="text-2xl font-semibold">Cents Transactions</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Cents Transactions
|
||||
</h3>
|
||||
<table class="min-w-full bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="py-2">Type</th>
|
||||
<th class="py-2">Amount (Cents)</th>
|
||||
<th class="py-2">Date</th>
|
||||
<th class="py-2">
|
||||
Type
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Amount (Cents)
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Date
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if recent_cents is not empty %}
|
||||
{% for transaction in recent_cents %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2">{{ transaction.type }}</td>
|
||||
<td class="border px-4 py-2">{{ transaction.cents }}</td>
|
||||
<td class="border px-4 py-2">{{ transaction.date }}</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ transaction.type }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ transaction.cents }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ transaction.date }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2" colspan="3">No Cents transactions available.</td>
|
||||
<td class="border px-4 py-2" colspan="3">
|
||||
No Cents transactions available.
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3 class="text-2xl font-semibold">Whales Sats</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Whales Sats
|
||||
</h3>
|
||||
<table class="min-w-full bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="py-2">User ID</th>
|
||||
<th class="py-2">Total Sats</th>
|
||||
<th class="py-2">
|
||||
User ID
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Total Sats
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if whales_sats is not empty %}
|
||||
{% for whale in whales_sats %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2">{{ whale.user_id }}</td>
|
||||
<td class="border px-4 py-2">{{ whale.total }}</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ whale.user_id }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ whale.total }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2" colspan="2">No Sats whales available.</td>
|
||||
<td class="border px-4 py-2" colspan="2">
|
||||
No Sats whales available.
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3 class="text-2xl font-semibold">Whales Cents</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Whales Cents
|
||||
</h3>
|
||||
<table class="min-w-full bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="py-2">User ID</th>
|
||||
<th class="py-2">Total Cents</th>
|
||||
<th class="py-2">
|
||||
User ID
|
||||
</th>
|
||||
<th class="py-2">
|
||||
Total Cents
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if whales_cents is not empty %}
|
||||
{% for whale in whales_cents %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2">{{ whale.user_id }}</td>
|
||||
<td class="border px-4 py-2">{{ whale.total }}</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ whale.user_id }}
|
||||
</td>
|
||||
<td class="border px-4 py-2">
|
||||
{{ whale.total }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td class="border px-4 py-2" colspan="2">No Cents whales available.</td>
|
||||
<td class="border px-4 py-2" colspan="2">
|
||||
No Cents whales available.
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<section>
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="text-2xl font-semibold">Cart</h3>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
Cart
|
||||
</h3>
|
||||
{% include 'lib/rule.twig' %}
|
||||
</div>
|
||||
{% include 'lib/empty.twig' with {
|
||||
|
|
|
@ -47,13 +47,31 @@
|
|||
</div>
|
||||
<div class="{{ colors.footer.policy }} flex justify-center w-full py-4">
|
||||
<div class="flex justify-between text-xs w-4/5">
|
||||
<div>© {{ copyright_year }} BuysForLife - All Rights Reserved.</div>
|
||||
<div>
|
||||
©
|
||||
{{ copyright_year }}
|
||||
BuysForLife - All Rights Reserved.
|
||||
</div>
|
||||
<div class='text-right'>
|
||||
<a href="/policy#terms-of-sale" class="hover:underline">Terms of Sale</a> |
|
||||
<a href="/policy#privacy-policy" class="hover:underline">Privacy Policy</a> |
|
||||
<a href="/policy#terms-of-use" class="hover:underline">Terms of Use</a> |
|
||||
<a href="/policy#accessibility-policy" class="hover:underline">Accessibility Policy</a> |
|
||||
<a href="/policy#do-not-sell-my-personal-information" class="hover:underline">Do Not Sell My Personal Information</a>
|
||||
<a href="/policy#terms-of-sale" class="hover:underline">
|
||||
Terms of Sale
|
||||
</a>
|
||||
|
|
||||
<a href="/policy#privacy-policy" class="hover:underline">
|
||||
Privacy Policy
|
||||
</a>
|
||||
|
|
||||
<a href="/policy#terms-of-use" class="hover:underline">
|
||||
Terms of Use
|
||||
</a>
|
||||
|
|
||||
<a href="/policy#accessibility-policy" class="hover:underline">
|
||||
Accessibility Policy
|
||||
</a>
|
||||
|
|
||||
<a href="/policy#do-not-sell-my-personal-information" class="hover:underline">
|
||||
Do Not Sell My Personal Information
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="robots" content="noindex">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<title>{{ page_title }}</title>
|
||||
<link rel="icon" href="/img/icon.png">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<title>
|
||||
{{ page_title }}
|
||||
</title>
|
||||
<link rel="icon" href="/img/icon.png" />
|
||||
<script>/*! js-cookie v3.0.5 | MIT */
|
||||
!function (e, t) { "object" == typeof exports && "undefined" != typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define(t) : (e = "undefined" != typeof globalThis ? globalThis : e || self, function () { var n = e.Cookies, o = e.Cookies = t(); o.noConflict = function () { return e.Cookies = n, o } }()) }(this, (function () { "use strict"; function e(e) { for (var t = 1; t < arguments.length; t++) { var n = arguments[t]; for (var o in n) e[o] = n[o] } return e } var t = function t(n, o) { function r(t, r, i) { if ("undefined" != typeof document) { "number" == typeof (i = e({}, o, i)).expires && (i.expires = new Date(Date.now() + 864e5 * i.expires)), i.expires && (i.expires = i.expires.toUTCString()), t = encodeURIComponent(t).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape); var c = ""; for (var u in i) i[u] && (c += "; " + u, !0 !== i[u] && (c += "=" + i[u].split(";")[0])); return document.cookie = t + "=" + n.write(r, t) + c } } return Object.create({ set: r, get: function (e) { if ("undefined" != typeof document && (!arguments.length || e)) { for (var t = document.cookie ? document.cookie.split("; ") : [], o = {}, r = 0; r < t.length; r++) { var i = t[r].split("="), c = i.slice(1).join("="); try { var u = decodeURIComponent(i[0]); if (o[u] = n.read(c, u), e === u) break } catch (e) { } } return e ? o[e] : o } }, remove: function (t, n) { r(t, "", e({}, n, { expires: -1 })) }, withAttributes: function (n) { return t(this.converter, e({}, this.attributes, n)) }, withConverter: function (n) { return t(e({}, this.converter, n), this.attributes) } }, { attributes: { value: Object.freeze(o) }, converter: { value: Object.freeze(n) } }) }({ read: function (e) { return '"' === e[0] && (e = e.slice(1, -1)), e.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent) }, write: function (e) { return encodeURIComponent(e).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent) } }, { path: "/" }); return t }));</script>
|
||||
<script>
|
||||
|
|
|
@ -29,8 +29,15 @@
|
|||
<header class="flex flex-col items-center w-full gap-3 mb-8">
|
||||
<div class="{{ colors.header.banner }} py-1 text-sm flex w-full justify-center">
|
||||
<div class="w-[97%] lg:w-[90%] xl:w-4/5 flex justify-between">
|
||||
<a href="/support/ask">Help Center</a>
|
||||
<span>Save 5% when you pay with Bitcoin</span><a href="/support/bitcoin">Learn More</a>
|
||||
<a href="/support/ask">
|
||||
Help Center
|
||||
</a>
|
||||
<span>
|
||||
Save 5% when you pay with Bitcoin
|
||||
</span>
|
||||
<a href="/support/bitcoin">
|
||||
Learn More
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -42,7 +49,7 @@
|
|||
</a>
|
||||
</div>
|
||||
<form action="/search" method="post" class="flex-grow max-w-[900px]">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
name: 'search',
|
||||
type: 'search',
|
||||
placeholder: 'What are you looking for?',
|
||||
|
@ -56,11 +63,8 @@
|
|||
<!-- Hidden checkbox to control the dropdown -->
|
||||
<input type="checkbox" id="dropdown-toggle" class="hidden peer">
|
||||
<!-- Dropdown button -->
|
||||
<label for="dropdown-toggle"
|
||||
class="{{ colors.button.default }} flex gap-1 items-center cursor-pointer p-1 py-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="lucide lucide-user-round">
|
||||
<label for="dropdown-toggle" class="{{ colors.button.default }} flex gap-1 items-center cursor-pointer p-1 py-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user-round">
|
||||
<circle cx="12" cy="8" r="5" />
|
||||
<path d="M20 21a8 8 0 0 0-16 0" />
|
||||
</svg>
|
||||
|
@ -73,32 +77,55 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div class="flex items-center gap-[1px]">
|
||||
<div class="text-sm font-semibold leading-none">Account</div> <svg
|
||||
xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="lucide lucide-chevron-down">
|
||||
<div class="text-sm font-semibold leading-none">
|
||||
Account
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down">
|
||||
<path d="m6 9 6 6 6-6" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<div
|
||||
class="absolute mt-2 {{ colors.dropdown.list }} border rounded-md shadow-md w-48 hidden peer-checked:block z-50">
|
||||
<div class="absolute mt-2 {{ colors.dropdown.list }} border rounded-md shadow-md w-48 hidden peer-checked:block z-50">
|
||||
<ul class="py-2">
|
||||
{% if session.user_id is defined %}
|
||||
<li><a href="/account" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Account</a></li>
|
||||
<li><a href="/account/orders" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Orders</a></li>
|
||||
<li><a href="/account/returns" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Returns</a>
|
||||
<li>
|
||||
<a href="/account" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Account
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="/account/shipping" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Shipping</a>
|
||||
<li>
|
||||
<a href="/account/orders" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Orders
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="/account/billing" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Billing</a>
|
||||
<li>
|
||||
<a href="/account/returns" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Returns
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/account/shipping" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Shipping
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/account/billing" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Billing
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li><a href="/account/login" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Sign In</a></li>
|
||||
<li><a href="/account/signup" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Create an
|
||||
Account</a>
|
||||
<li>
|
||||
<a href="/account/login" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Sign In
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/account/signup" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Create an
|
||||
Account
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
|
@ -106,13 +133,21 @@
|
|||
{% if is_admin %}
|
||||
{% include 'lib/rule.twig' %}
|
||||
<ul class="py-2">
|
||||
<li><a href="/admin" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Admin</a></li>
|
||||
<li>
|
||||
<a href="/admin" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Admin
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if session.user_id is defined %}
|
||||
{% include 'lib/rule.twig' %}
|
||||
<ul class="py-2">
|
||||
<li><a href="/account/logout" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">Logout</a></li>
|
||||
<li>
|
||||
<a href="/account/logout" class="block px-4 py-2 m-1 rounded-lg {{ colors.dropdown.item }}">
|
||||
Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -124,39 +159,34 @@
|
|||
}
|
||||
});
|
||||
</script>
|
||||
<a href="/account/orders"
|
||||
class="{{ colors.button.default }} flex items-center gap-1 p-1 py-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-box">
|
||||
<path
|
||||
d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" />
|
||||
<a href="/account/orders" class="{{ colors.button.default }} flex items-center gap-1 p-1 py-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-box">
|
||||
<path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" />
|
||||
<path d="m3.3 7 8.7 5 8.7-5" />
|
||||
<path d="M12 22V12" />
|
||||
</svg>
|
||||
<div>
|
||||
<div class="text-xs whitespace-nowrap leading-none">Returns &</div>
|
||||
<div class="text-sm font-semibold leading-none">Orders</div>
|
||||
<div class="text-xs whitespace-nowrap leading-none">
|
||||
Returns &
|
||||
</div>
|
||||
<div class="text-sm font-semibold leading-none">
|
||||
Orders
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<a href="/cart">
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
class="{{ colors.button.primary }} h-[42px] flex items-center border p-2 rounded-tl-lg rounded-bl-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="lucide lucide-shopping-cart lucide-icon">
|
||||
<div class="{{ colors.button.primary }} h-[42px] flex items-center border p-2 rounded-tl-lg rounded-bl-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-shopping-cart lucide-icon">
|
||||
<circle cx="8" cy="21" r="1"></circle>
|
||||
<circle cx="19" cy="21" r="1"></circle>
|
||||
<path
|
||||
d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12">
|
||||
</path>
|
||||
<path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="{{ colors.input }} flex h-[42px] font-semibold justify-center items-center rounded-tr-lg rounded-br-lg border border-l-0 px-3 py-2">
|
||||
7</div>
|
||||
<div class="{{ colors.input }} flex h-[42px] font-semibold justify-center items-center rounded-tr-lg rounded-br-lg border border-l-0 px-3 py-2">
|
||||
7
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -165,18 +195,22 @@
|
|||
<nav class="w-full relative rounded-lg {{ colors.nav.bar }}">
|
||||
<div class="flex">
|
||||
<ul class="flex">
|
||||
<li
|
||||
class="hoverable rounded-xl border-[5px] {{ colors.nav.item }}">
|
||||
<a href="/power-meters" class="relative p-1 rounded-xl block text-sm font-bold">220V
|
||||
Power Meters</a>
|
||||
<li class="hoverable rounded-xl border-[5px] {{ colors.nav.item }}">
|
||||
<a href="/power-meters" class="relative p-1 rounded-xl block text-sm font-bold">
|
||||
220V
|
||||
Power Meters
|
||||
</a>
|
||||
<div class="mega-menu">
|
||||
<div class="bg-transparent h-[3px]">
|
||||
<!-- invisible content to keep menu shown when cursor is b/t the item and the content -->
|
||||
<div class="bg-transparent h-[3px]"><!-- invisible content to keep menu shown when cursor is b/t the item and the content -->
|
||||
</div>
|
||||
<div class="p-6 mb-16 rounded-b shadow-lg {{ colors.nav.hovercontent }}">
|
||||
<div class='flex gap-3 items-baseline'>
|
||||
<h4 class="text-xl font-semibold">220V Power Meters</h4>
|
||||
<a href="/power-meters" class="hover:underline font-semibold text-xs {{ colors.anchor.primary }}">Shop All</a>
|
||||
<h4 class="text-xl font-semibold">
|
||||
220V Power Meters
|
||||
</h4>
|
||||
<a href="/power-meters" class="hover:underline font-semibold text-xs {{ colors.anchor.primary }}">
|
||||
Shop All
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -191,17 +225,23 @@
|
|||
<a href="/" class="hover:underline {{ colors.breadcrumb.parent }}">
|
||||
{{ env.APP_NAME }}
|
||||
</a>
|
||||
<span class="{{ colors.breadcrumb.seperator }}">></span>
|
||||
<span class="{{ colors.breadcrumb.seperator }}">
|
||||
>
|
||||
</span>
|
||||
{% for crumb in breadcrumbs %}
|
||||
{% if crumb.url is null %}
|
||||
<span class="font-bold {{ colors.breadcrumb.child }}">{{ crumb.title }}</span>
|
||||
<span class="font-bold {{ colors.breadcrumb.child }}">
|
||||
{{ crumb.title }}
|
||||
</span>
|
||||
{% else %}
|
||||
<a href="{{ crumb.url }}" class="hover:underline {{ colors.breadcrumb.parent }}">
|
||||
{{ crumb.title }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if loop.index < breadcrumbs|length %}
|
||||
<span class="{{ colors.breadcrumb.seperator }}">></span>
|
||||
<span class="{{ colors.breadcrumb.seperator }}">
|
||||
>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
@ -209,4 +249,5 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</header>
|
||||
</header>
|
||||
|
42
src/views/lib/address.twig
Normal file
42
src/views/lib/address.twig
Normal file
|
@ -0,0 +1,42 @@
|
|||
<div class="flex flex-col gap-1">
|
||||
<span>
|
||||
{{ address.name }}
|
||||
</span>
|
||||
<span>
|
||||
{{ address.company }}
|
||||
</span>
|
||||
<span>
|
||||
{{ address.addressLine1 }}
|
||||
</span>
|
||||
<span>
|
||||
{{ address.addressLine2 }}
|
||||
</span>
|
||||
<span>
|
||||
{{ address.city }}
|
||||
,
|
||||
{{ address.state }}
|
||||
{{ address.zip }}
|
||||
</span>
|
||||
<span>
|
||||
{{ address.phone }}
|
||||
</span>
|
||||
{% if edit_url is not null %}
|
||||
<a href="{{ edit_url }}" onclick="event.preventDefault(); document.getElementById('edit-form-{{ address.id }}').submit();">
|
||||
Edit
|
||||
</a>
|
||||
<form id="edit-form-{{ address.id }}" action="{{ edit_url }}" method="post" style="display: none;">
|
||||
<input type="hidden" name="address_id" value="{{ address.id }}" />
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if delete_url is not null %}
|
||||
<a href="#delete-modal-{{ address.id }}">
|
||||
Delete
|
||||
</a>
|
||||
{% include 'lib/modal.twig' with {
|
||||
id: 'delete-modal-' ~ address.id,
|
||||
content: 'lib/modals/confirm_delete_address.twig',
|
||||
} %}
|
||||
<form id="delete-form-{{ address.id }}" action="{{ delete_url }}" method="post" style="display: none;" />
|
||||
<input type="hidden" name="address_id" value="{{ address.id }}"></form>
|
||||
{% endif %}
|
||||
</div>
|
|
@ -1,45 +1,47 @@
|
|||
{% if session.error is defined %}
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.error.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-x {{ colors.error.text }}">
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.error.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-x {{ colors.error.text }}">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="m15 9-6 6" />
|
||||
<path d="m9 9 6 6" />
|
||||
</svg>
|
||||
<p>{{ session.error }}</p>
|
||||
</div>
|
||||
<p>
|
||||
{{ session.error }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if session.warning is defined %}
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.warning.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-circle-alert {{ colors.warning.text }}">
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.warning.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-alert {{ colors.warning.text }}">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<line x1="12" x2="12" y1="8" y2="12" />
|
||||
<line x1="12" x2="12.01" y1="16" y2="16" />
|
||||
</svg>
|
||||
<p>{{ session.warning }}</p>
|
||||
</div>
|
||||
<p>
|
||||
{{ session.warning }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if session.success is defined %}
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.success.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-circle-check {{ colors.success.text }}">
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.success.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-check {{ colors.success.text }}">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>
|
||||
<p>{{ session.success }}</p>
|
||||
</div>
|
||||
<p>
|
||||
{{ session.success }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if session.info is defined %}
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.info.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info {{ colors.info.text }}">
|
||||
<div class="flex gap-3 items-center p-3 border rounded-md {{ colors.info.alert }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info {{ colors.info.text }}">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M12 16v-4" />
|
||||
<path d="M12 8h.01" />
|
||||
</svg>
|
||||
<p>{{ session.info }}</p>
|
||||
</div>
|
||||
<p>
|
||||
{{ session.info }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
|
@ -1,46 +1,49 @@
|
|||
{% if href is defined %}
|
||||
<a href="{{ href }}"
|
||||
class="cursor-pointer {{ submit is defined ? 'px-4 rounded-l-none' : 'w-full' }} {{ colors.button.primary }} rounded-lg h-[42px] flex items-center justify-center">
|
||||
{% else %}
|
||||
<div onclick="{{ onclick }}"
|
||||
class="cursor-pointer {{ submit is defined ? 'px-4 rounded-l-none' : 'w-full' }} {{ colors.button.primary }} rounded-lg h-[42px] flex items-center justify-center">
|
||||
{% endif %}
|
||||
<a
|
||||
href="{{ href }}" class="cursor-pointer {{ submit is defined ? 'px-4 rounded-l-none' : 'w-full' }} {{ colors.button.primary }} rounded-lg h-[42px] flex items-center justify-center">
|
||||
{% else %}
|
||||
<div onclick="{{ onclick }}" class="cursor-pointer {{ submit is defined ? 'px-4 rounded-l-none' : 'w-full' }} {{ colors.button.primary }} rounded-lg h-[42px] flex items-center justify-center">
|
||||
{% endif %}
|
||||
{% if label is defined %}
|
||||
<span>{{ label }}</span>
|
||||
<span>
|
||||
{{ label }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if icon is defined %}
|
||||
{% if icon == 'search' %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<path d="m21 21-4.3-4.3"></path>
|
||||
</svg>
|
||||
{% elseif icon == 'add' %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-plus">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-plus">
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
{% elseif icon == 'enter' %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-arrow-right">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-right">
|
||||
<path d="M5 12h14" />
|
||||
<path d="m12 5 7 7-7 7" />
|
||||
</svg>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if href is defined %}
|
||||
{% if href is defined %}
|
||||
</a>
|
||||
{% else %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if captcha is defined %}
|
||||
<div class="flex justify-center {{ colors.text.muted }}">
|
||||
<p class="w-[250px] text-[10px] text-center">This form is protected by reCAPTCHA and the Google
|
||||
<a class="underline" href="https://policies.google.com/privacy">Privacy Policy</a> and <a class="underline"
|
||||
href="https://policies.google.com/terms">Terms of Service</a> apply.
|
||||
<p class="w-[250px] text-[10px] text-center">
|
||||
This form is protected by reCAPTCHA and the Google
|
||||
<a class="underline" href="https://policies.google.com/privacy">
|
||||
Privacy Policy
|
||||
</a>
|
||||
and
|
||||
<a class="underline" href="https://policies.google.com/terms">
|
||||
Terms of Service
|
||||
</a>
|
||||
apply.
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
|
@ -1,8 +1,7 @@
|
|||
<table align="center" class="x_225906249wrapper x_225906249wrapper-callout x_225906249wrapper-without-padding-top" border="0" cellpadding="0" cellspacing="0" style="background: rgb(251, 251, 251); background-color: rgb(251, 251, 251); width: 100%">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="background: rgb(251, 251, 251); background-color: rgb(251, 251, 251); width: 100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<div style="margin: 0px auto; max-width: 648px">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="width: 100%">
|
||||
<tbody>
|
||||
|
@ -15,41 +14,51 @@
|
|||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding: 0; text-align: center">
|
||||
|
||||
<div class="x_225906249mj-column-per-100 x_225906249mj-outlook-group-fix" style="font-size: 0px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%">
|
||||
<div style="font-size: 0px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="vertical-align: top" width="100%">
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td align="left" class="x_225906249text x_225906249text-surtitle" style="font-size: 0px; padding: 0 24px; padding-bottom: 12px">
|
||||
<div style="font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; letter-spacing: 0.12em; line-height: 24px; text-align: left; text-transform: uppercase; color: rgb(49, 89, 128)">Your Account</div>
|
||||
<td align="left" style="font-size: 0px; padding: 0 24px; padding-bottom: 12px">
|
||||
<div style="font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; letter-spacing: 0.12em; line-height: 24px; text-align: left; text-transform: uppercase; color: rgb(49, 89, 128)">
|
||||
Your Account
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" class="x_225906249text x_225906249text-header-title" style="font-size: 0px; padding: 0 24px; padding-bottom: 24px">
|
||||
<div style="font-family: "Source Serif Pro", Georgia, Cambria, "Times New Roman", Times, serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 41px; font-weight: 600; line-height: 48px; text-align: left; color: rgb(0, 9, 19)">One-Time Passcode</div>
|
||||
<td align="left" style="font-size: 0px; padding: 0 24px; padding-bottom: 24px">
|
||||
<div style="font-family: "Source Serif Pro", Georgia, Cambria, "Times New Roman", Times, serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 41px; font-weight: 600; line-height: 48px; text-align: left; color: rgb(0, 9, 19)">
|
||||
One-Time Passcode
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" class="x_225906249text" style="font-size: 0px; padding: 0 24px">
|
||||
<div style="font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; line-height: 24px; text-align: left; color: rgb(0, 9, 19)">Click the button below to access your secure login form, then enter your one-time passcode.</div>
|
||||
<td align="left" style="font-size: 0px; padding: 0 24px">
|
||||
<div style="font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; line-height: 24px; text-align: left; color: rgb(0, 9, 19)">
|
||||
Click the button below to access your secure login form, then enter your one-time passcode.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" class="x_225906249text x_225906249text-code" style="font-size: 0px; padding: 0 24px; padding-top: 24px">
|
||||
<div style="font-family: "Source Code Pro", "ui-monospace", Menlo, Consolas, "Roboto Mono", "Ubuntu Monospace", "Noto Mono", "Oxygen Mono", "Liberation Mono", monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !important; font-size: 41px; font-weight: bold; letter-spacing: 0.12em; line-height: 48px; text-align: left; color: rgb(0, 48, 94)">{{ code }}</div>
|
||||
<td align="left" style="font-size: 0px; padding: 0 24px; padding-top: 24px">
|
||||
<div style="font-family: "Source Code Pro", "ui-monospace", Menlo, Consolas, "Roboto Mono", "Ubuntu Monospace", "Noto Mono", "Oxygen Mono", "Liberation Mono", monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !important; font-size: 41px; font-weight: bold; letter-spacing: 0.12em; line-height: 48px; text-align: left; color: rgb(0, 48, 94)">
|
||||
{{ code }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" class="x_225906249button" style="font-size: 0px; padding: 24px 24px">
|
||||
<td align="left" style="font-size: 0px; padding: 24px 24px">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; line-height: 100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" bgcolor="#FCC800" style="border: none; border-radius: 6px; cursor: auto; background: rgb(252, 200, 0)" valign="middle">
|
||||
<a href="{{ link }}" style="display: inline-block; background: rgb(252, 200, 0); color: rgb(0, 48, 94); font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; font-weight: bold; line-height: 24px; margin: 0; text-decoration: none; text-transform: none; padding: 18px 24px; border-radius: 6px" target="_blank"> Log in → </a>
|
||||
<a href="{{ link }}" style="display: inline-block; background: rgb(252, 200, 0); color: rgb(0, 48, 94); font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; font-weight: bold; line-height: 24px; margin: 0; text-decoration: none; text-transform: none; padding: 18px 24px; border-radius: 6px" target="_blank">
|
||||
Log in
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -58,8 +67,10 @@
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" class="x_225906249text" style="font-size: 0px; padding: 0 24px">
|
||||
<div style="font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; font-weight: bold; line-height: 24px; text-align: left">BuysForLife agents will never ask you for this code. Do not share this passcode with anyone for any reason.</div>
|
||||
<td align="left" style="font-size: 0px; padding: 0 24px">
|
||||
<div style="font-family: Greycliff, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; font-weight: bold; line-height: 24px; text-align: left">
|
||||
BuysForLife associates will never ask you for this code. Do not share this passcode with anyone for any reason.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -82,7 +93,6 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<div class="text-center flex flex-col items-center mb-24 mt-20">
|
||||
<div class="text-center flex flex-col items-center mb-24 mt-20">
|
||||
<img src="/img/empty/{{ type }}-{{ theme }}.svg" width="200px" />
|
||||
<h3 class="text-2xl font-semibold">{{ title }}</h3>
|
||||
<p class="w-[300px] text-sm">{{ subtitle }}</p>
|
||||
<h3 class="text-2xl font-semibold">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<p class="w-[300px] text-sm">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
|
@ -1,24 +1,24 @@
|
|||
<div class="flex flex-col gap-4 mb-4">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_name',
|
||||
label: 'Name',
|
||||
value: name
|
||||
} %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_company',
|
||||
label: 'Company',
|
||||
optional: true,
|
||||
value: company
|
||||
} %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_addressLine1',
|
||||
label: 'Address Line 1',
|
||||
value: addressLine1
|
||||
} %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_addressLine2',
|
||||
label: 'Address Line 2',
|
||||
|
@ -26,26 +26,26 @@
|
|||
value: addressLine2
|
||||
} %}
|
||||
<div class="flex gap-4">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_city',
|
||||
label: 'City',
|
||||
value: city
|
||||
} %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_state',
|
||||
label: 'State',
|
||||
value: state
|
||||
} %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_zip',
|
||||
label: 'Zip',
|
||||
value: zip
|
||||
} %}
|
||||
</div>
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: action ~ '_phone',
|
||||
label: 'Phone',
|
|
@ -1,31 +1,31 @@
|
|||
<div class="flex flex-col gap-4 my-4">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
value: user.name
|
||||
} %}
|
||||
<div class="flex gap-4">
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: 'company_name',
|
||||
label: 'Company Name',
|
||||
value: user.company_name
|
||||
} %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: 'company_type',
|
||||
label: 'Company Type',
|
||||
value: user.company_type
|
||||
} %}
|
||||
{% include 'lib/input.twig' with {
|
||||
{% include 'lib/inputs/text.twig' with {
|
||||
type: 'text',
|
||||
name: 'company_size',
|
||||
label: 'Company Size',
|
||||
value: user.company_size
|
||||
} %}
|
||||
</div>
|
||||
{% include 'lib/toggle.twig' with {
|
||||
{% include 'lib/inputs/toggle.twig' with {
|
||||
name: 'dark_theme',
|
||||
label: 'Use dark theme',
|
||||
on: user.dark_theme
|
|
@ -1,48 +0,0 @@
|
|||
<div class="flex flex-col gap-4">
|
||||
{% if label is defined %}
|
||||
<label for="{{ name }}" class="flex flex-col gap-2">
|
||||
<span class="font-semibold">
|
||||
{{ label }}
|
||||
{% if required is defined %}
|
||||
<span class="{{ colors.error.text }} ml-4">*</span>
|
||||
{% endif %}
|
||||
{% if optional is defined %}
|
||||
<span class="text-sm font-normal {{ colors.text.muted }}"> - (optional)</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if subtext is defined %}
|
||||
<span class="text-sm {{ colors.text.muted }}">{{ subtext }}</span>
|
||||
{% endif %}
|
||||
</label>
|
||||
{% endif %}
|
||||
{% if submit is defined %}
|
||||
<div class="flex items-center">
|
||||
{% endif %}
|
||||
<input type="{{ type }}" name="{{ name }}"
|
||||
{% if placeholder is defined %}
|
||||
placeholder="{{ placeholder }}"
|
||||
{% endif %}
|
||||
{% if value is not null %}
|
||||
value="{{ value }}"
|
||||
{% endif %}
|
||||
{% if readonly is not null %}
|
||||
readonly
|
||||
{% endif %}
|
||||
{% if type == 'number' %}
|
||||
{% if min is defined %}
|
||||
min="{{ min }}"
|
||||
{% endif %}
|
||||
{% if max is defined %}
|
||||
max="{{ max }}"
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
class="{{ colors.input }} {{ submit is defined ? 'rounded-l-lg border-r-0' : 'rounded-lg' }} w-full p-3 h-[42px] border focus:ring-1 focus:outline-none">
|
||||
{% if submit is defined %}
|
||||
{% include 'lib/button.twig' with {
|
||||
icon: 'search'
|
||||
} %}
|
||||
{% endif %}
|
||||
{% if submit is defined %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
11
src/views/lib/inputs/number.twig
Normal file
11
src/views/lib/inputs/number.twig
Normal file
|
@ -0,0 +1,11 @@
|
|||
<label for="{{ id }}" class="block text-sm font-medium text-gray-700 mt-2">
|
||||
{{ label }}
|
||||
</label>
|
||||
<input type="number" id="{{ id }}" name="{{ name }}" class="border rounded-lg p-2 w-full" {% if required %} required {% endif %} {% if min is defined %} min="{{ min }}" {% endif %} {% if max is defined %} max="{{ max }}" {% endif %} {% if step is defined %} step="{{ step }}" {% endif %} {% if value is defined %} value="{{ value }}" {% endif %} placeholder="{{ placeholder | default('Enter a number') }}">
|
||||
|
||||
{% if subtext is defined %}
|
||||
<p class="text-xs text-gray-500">
|
||||
{{ subtext }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
37
src/views/lib/inputs/text.twig
Normal file
37
src/views/lib/inputs/text.twig
Normal file
|
@ -0,0 +1,37 @@
|
|||
<div class="flex flex-col gap-4">
|
||||
{% if label is defined %}
|
||||
<label for="{{ name }}" class="flex flex-col gap-2">
|
||||
<span class="font-semibold">
|
||||
{{ label }}
|
||||
{% if required is defined %}
|
||||
<span class="{{ colors.error.text }} ml-4">
|
||||
*
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if optional is defined %}
|
||||
<span class="text-sm font-normal {{ colors.text.muted }}">
|
||||
- (optional)
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if subtext is defined %}
|
||||
<span class="text-sm {{ colors.text.muted }}">
|
||||
{{ subtext }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</label>
|
||||
{% endif %}
|
||||
{% if submit is defined %}
|
||||
<div class="flex items-center">
|
||||
{% endif %}
|
||||
<input type="{{ type }}" name="{{ name }}" {% if placeholder %} placeholder="{{ placeholder }}" {% endif %} {% if value is not null %} value="{{ value }}" {% endif %} {% if readonly is not null %} readonly {% endif %} {% if type == 'number' %} {% if min is defined %} min="{{ min }}" {% endif %} {% if max is defined %} max="{{ max }}" {% endif %} {% endif %} class="{{ colors.input }} {{ submit is defined ? 'rounded-l-lg border-r-0' : 'rounded-lg' }} w-full p-3 h-[42px] border focus:ring-1 focus:outline-none">
|
||||
{% if submit is defined %}
|
||||
{% include 'lib/button.twig' with {
|
||||
icon: 'search'
|
||||
} %}
|
||||
{% endif %}
|
||||
{% if submit is defined %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -8,7 +8,12 @@
|
|||
<div id="hide-{{ id }}">
|
||||
<div class="{{ colors.modal.content }} p-8 border rounded relative">
|
||||
{% include content %}
|
||||
<a href="#hide-{{ id }}" class="absolute top-2 right-2 no-underline"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></a>
|
||||
<a href="#hide-{{ id }}" class="absolute top-2 right-2 no-underline">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x">
|
||||
<path d="M18 6 6 18" />
|
||||
<path d="m6 6 12 12" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
3
src/views/lib/modals/confirm_delete_address.twig
Normal file
3
src/views/lib/modals/confirm_delete_address.twig
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div>
|
||||
Are you sure you want to delete this address?
|
||||
</div>
|
24
src/views/lib/modals/credit.twig
Normal file
24
src/views/lib/modals/credit.twig
Normal file
|
@ -0,0 +1,24 @@
|
|||
<div>
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
Why do I have store credit?
|
||||
</div>
|
||||
<ul class="list-disc pl-6 mb-4">
|
||||
<li>
|
||||
You may have received credit as a refund, dispute resolution, or promotional event.
|
||||
</li>
|
||||
<li>
|
||||
You can also reload your store credit by ordering gift cards.
|
||||
</li>
|
||||
</ul>
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
What can I do with store credit?
|
||||
</div>
|
||||
<ul class="list-disc pl-6">
|
||||
<li>
|
||||
You may spend store credit at checkout.
|
||||
</li>
|
||||
<li>
|
||||
Your subscriptions and recurring purchases can also be paid with store credit.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
30
src/views/lib/modals/sats.twig
Normal file
30
src/views/lib/modals/sats.twig
Normal file
|
@ -0,0 +1,30 @@
|
|||
<div>
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
Why do I have sats?
|
||||
</div>
|
||||
<ul class="list-disc pl-6 mb-4">
|
||||
<li>
|
||||
You may have received sats from a promotional event
|
||||
</li>
|
||||
<li>
|
||||
You may have recieved sats sent to your default generated Lightning Address (LNURL):
|
||||
{{ user.npub }}
|
||||
@
|
||||
{{ http_host }}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
What can I do with sats?
|
||||
</div>
|
||||
<ul class="list-disc pl-6">
|
||||
<li>
|
||||
You may spend sats at checkout
|
||||
</li>
|
||||
<li>
|
||||
Your subscriptions and recurring purchases can also be paid with sats
|
||||
</li>
|
||||
<li>
|
||||
You can configure these sats to autowithdraw by attaching a Lightning Address (LNURL)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
|
@ -1,17 +0,0 @@
|
|||
<label for="{{ id }}" class="block text-sm font-medium text-gray-700 mt-2">
|
||||
{{ label }}
|
||||
</label>
|
||||
<input type="number"
|
||||
id="{{ id }}"
|
||||
name="{{ name }}"
|
||||
class="border rounded-lg p-2 w-full"
|
||||
{% if required %} required {% endif %}
|
||||
{% if min is defined %} min="{{ min }}" {% endif %}
|
||||
{% if max is defined %} max="{{ max }}" {% endif %}
|
||||
{% if step is defined %} step="{{ step }}" {% endif %}
|
||||
{% if value is defined %} value="{{ value }}" {% endif %}
|
||||
placeholder="{{ placeholder | default('Enter a number') }}">
|
||||
|
||||
{% if subtext is defined %}
|
||||
<p class="text-xs text-gray-500">{{ subtext }}</p>
|
||||
{% endif %}
|
|
@ -1,12 +0,0 @@
|
|||
<div>
|
||||
<div class="text-lg font-semibold mb-4">Why do I have store credit?</div>
|
||||
<ul class="list-disc pl-6 mb-4">
|
||||
<li>You may have received credit as a refund, dispute resolution, or promotional event.</li>
|
||||
<li>You can also reload your store credit by ordering gift cards.</li>
|
||||
</ul>
|
||||
<div class="text-lg font-semibold mb-4">What can I do with store credit?</div>
|
||||
<ul class="list-disc pl-6">
|
||||
<li>You may spend store credit at checkout.</li>
|
||||
<li>Your subscriptions and recurring purchases can also be paid with store credit.</li>
|
||||
</ul>
|
||||
</div>
|
|
@ -1,13 +0,0 @@
|
|||
<div>
|
||||
<div class="text-lg font-semibold mb-4">Why do I have sats?</div>
|
||||
<ul class="list-disc pl-6 mb-4">
|
||||
<li>You may have received sats from a promotional event</li>
|
||||
<li>You may have recieved sats sent to your default generated Lightning Address (LNURL): {{ user.npub }}@{{ http_host }}</li>
|
||||
</ul>
|
||||
<div class="text-lg font-semibold mb-4">What can I do with sats?</div>
|
||||
<ul class="list-disc pl-6">
|
||||
<li>You may spend sats at checkout</li>
|
||||
<li>Your subscriptions and recurring purchases can also be paid with sats</li>
|
||||
<li>You can configure these sats to autowithdraw by attaching a Lightning Address (LNURL)</li>
|
||||
</ul>
|
||||
</div>
|
|
@ -1,10 +1,14 @@
|
|||
{% if text is defined %}
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 flex items-center"><span class="w-full border-t {{ colors.rule }}"></span></div>
|
||||
<div class="relative flex justify-center text-xs"><span
|
||||
class="px-2 {{ colors.body }}">{{ text }}</span>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<span class="w-full border-t {{ colors.rule }}"></span>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-xs">
|
||||
<span class="px-2 {{ colors.body }}">
|
||||
{{ text }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<hr class="{{ colors.rule }}" />
|
||||
<hr class="{{ colors.rule }}" />
|
||||
{% endif %}
|
|
@ -1,8 +1,14 @@
|
|||
<section class="flex flex-col gap-4">
|
||||
Transaction Id: {{ tx.id }}
|
||||
Date: {{ tx.date }}
|
||||
User: {{ user.email }}
|
||||
Transaction Type: {{ tx.type }}
|
||||
Sats: {{ tx.sats }}
|
||||
Cents: {{ tx.cents }}
|
||||
Transaction Id:
|
||||
{{ tx.id }}
|
||||
Date:
|
||||
{{ tx.date }}
|
||||
User:
|
||||
{{ user.email }}
|
||||
Transaction Type:
|
||||
{{ tx.type }}
|
||||
Sats:
|
||||
{{ tx.sats }}
|
||||
Cents:
|
||||
{{ tx.cents }}
|
||||
</section>
|
Loading…
Reference in a new issue