Signed-off-by: David Headrick <david@headrickconsulting.com>
This commit is contained in:
parent
fe1af7df2b
commit
488d7cbf90
@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Surge365.MassEmailReact.Server.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AuthencticationController : ControllerBase
|
||||
{
|
||||
[HttpPost]
|
||||
public bool Authenticate(string username, string password)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "MassEmailReact",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
@ -6,23 +6,26 @@ import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['dist'] },
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
"@typescript-eslint/no-explicit-any": "warn", // Changes error to warning
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
"no-unused-vars": "warn", // Changes error to warning for unused variables
|
||||
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], // Warns instead of error
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
<title>Surge365 Mass Email</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/components/pages/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
583
surge365.massemailreact.client/package-lock.json
generated
583
surge365.massemailreact.client/package-lock.json
generated
@ -8,8 +8,15 @@
|
||||
"name": "surge365.massemailreact.client",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"admin-lte": "4.0.0-beta3",
|
||||
"bootstrap": "^5.3.3",
|
||||
"font-awesome": "^4.7.0",
|
||||
"ionicons": "^7.4.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
"react-bootstrap": "^2.10.9",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-icons": "^5.3.0",
|
||||
"react-router-dom": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.19.0",
|
||||
@ -264,6 +271,18 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
|
||||
"integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.26.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
|
||||
@ -875,32 +894,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
|
||||
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.6.tgz",
|
||||
"integrity": "sha512-+0TjwR1eAUdZtvv/ir1mGX+v0tUoR3VEPB8Up0LLJC+whRW0GgBBtpbOkg/a/U4Dxa6l5a3l9AJ1aWIQVyoWJA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.10.0",
|
||||
"@eslint/core": "^0.11.0",
|
||||
"levn": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
|
||||
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
@ -1058,6 +1064,85 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-aria/ssr": {
|
||||
"version": "3.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.7.tgz",
|
||||
"integrity": "sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/hooks": {
|
||||
"version": "0.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz",
|
||||
"integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/ui": {
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz",
|
||||
"integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@react-aria/ssr": "^3.5.0",
|
||||
"@restart/hooks": "^0.5.0",
|
||||
"@types/warning": "^3.0.3",
|
||||
"dequal": "^2.0.3",
|
||||
"dom-helpers": "^5.2.0",
|
||||
"uncontrollable": "^8.0.4",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.14.0",
|
||||
"react-dom": ">=16.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/ui/node_modules/@restart/hooks": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz",
|
||||
"integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/ui/node_modules/uncontrollable": {
|
||||
"version": "8.0.4",
|
||||
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
|
||||
"integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.34.8",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
|
||||
@ -1324,6 +1409,28 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "4.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.26.0.tgz",
|
||||
"integrity": "sha512-+0Inu+dJ9/LgWSskcZwx7v17v4GILcwIYxNgD+OuK0U+D5z61WsxWw7yHkYG5OqGPBijsJMVssYRx/Tn+e7F9A==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=7.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
@ -1369,6 +1476,12 @@
|
||||
"@babel/types": "^7.20.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||
@ -1388,16 +1501,20 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
|
||||
"integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
|
||||
"integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz",
|
||||
"integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
@ -1413,18 +1530,33 @@
|
||||
"@types/react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
|
||||
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/warning": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
|
||||
"integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.0.tgz",
|
||||
"integrity": "sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz",
|
||||
"integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/type-utils": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.1",
|
||||
"@typescript-eslint/type-utils": "8.24.1",
|
||||
"@typescript-eslint/utils": "8.24.1",
|
||||
"@typescript-eslint/visitor-keys": "8.24.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
@ -1444,16 +1576,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.0.tgz",
|
||||
"integrity": "sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz",
|
||||
"integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.1",
|
||||
"@typescript-eslint/types": "8.24.1",
|
||||
"@typescript-eslint/typescript-estree": "8.24.1",
|
||||
"@typescript-eslint/visitor-keys": "8.24.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -1469,14 +1601,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz",
|
||||
"integrity": "sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz",
|
||||
"integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0"
|
||||
"@typescript-eslint/types": "8.24.1",
|
||||
"@typescript-eslint/visitor-keys": "8.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1487,14 +1619,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.0.tgz",
|
||||
"integrity": "sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz",
|
||||
"integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.1",
|
||||
"@typescript-eslint/utils": "8.24.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
@ -1511,9 +1643,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.0.tgz",
|
||||
"integrity": "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz",
|
||||
"integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -1525,14 +1657,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz",
|
||||
"integrity": "sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz",
|
||||
"integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.1",
|
||||
"@typescript-eslint/visitor-keys": "8.24.1",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -1591,16 +1723,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.0.tgz",
|
||||
"integrity": "sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz",
|
||||
"integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0"
|
||||
"@typescript-eslint/scope-manager": "8.24.1",
|
||||
"@typescript-eslint/types": "8.24.1",
|
||||
"@typescript-eslint/typescript-estree": "8.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1615,13 +1747,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz",
|
||||
"integrity": "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz",
|
||||
"integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.1",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -1675,6 +1807,12 @@
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/admin-lte": {
|
||||
"version": "4.0.0-beta3",
|
||||
"resolved": "https://registry.npmjs.org/admin-lte/-/admin-lte-4.0.0-beta3.tgz",
|
||||
"integrity": "sha512-q2VoAOu1DtZ7z41M2gQ05VMNYkFCAMxFU+j/HUMwCOlr/e3VhO+qww2SGJw4OxBw5nZQ7YV78+wK2RiB7ConzQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
@ -1722,6 +1860,25 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
|
||||
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@popperjs/core": "^2.11.8"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@ -1827,6 +1984,12 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@ -1861,6 +2024,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
|
||||
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@ -1880,7 +2052,6 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
@ -1908,10 +2079,29 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-helpers": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.101",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.101.tgz",
|
||||
"integrity": "sha512-L0ISiQrP/56Acgu4/i/kfPwWSgrzYZUnQrC0+QPFuhqlLP1Ir7qzPPDVS9BcKIyWTRU8+o6CC8dKw38tSWhYIA==",
|
||||
"version": "1.5.102",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz",
|
||||
"integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@ -2275,12 +2465,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
|
||||
"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
||||
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/font-awesome": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
|
||||
"integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==",
|
||||
"license": "(OFL-1.1 AND MIT)",
|
||||
"engines": {
|
||||
"node": ">=0.10.3"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
@ -2386,6 +2585,24 @@
|
||||
"node": ">=0.8.19"
|
||||
}
|
||||
},
|
||||
"node_modules/invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ionicons": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.4.0.tgz",
|
||||
"integrity": "sha512-ZK94MMqgzMCPPMhmk8Ouu6goyVHFIlw/ACP6oe3FrikcI0N7CX0xcwVaEbUc0G/v3W0shI93vo+9ve/KpvcNhQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@ -2430,7 +2647,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
@ -2540,6 +2756,18 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
@ -2627,6 +2855,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
@ -2731,9 +2968,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz",
|
||||
"integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==",
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -2769,6 +3006,30 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types-extra": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
|
||||
"integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-is": "^16.3.2",
|
||||
"warning": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@ -2809,6 +3070,37 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-bootstrap": {
|
||||
"version": "2.10.9",
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.9.tgz",
|
||||
"integrity": "sha512-TJUCuHcxdgYpOqeWmRApM/Dy0+hVsxNRFvq2aRFQuxhNi/+ivOxC5OdWIeHS3agxvzJ4Ev4nDw2ZdBl9ymd/JQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.24.7",
|
||||
"@restart/hooks": "^0.4.9",
|
||||
"@restart/ui": "^1.9.4",
|
||||
"@types/prop-types": "^15.7.12",
|
||||
"@types/react-transition-group": "^4.4.6",
|
||||
"classnames": "^2.3.2",
|
||||
"dom-helpers": "^5.2.1",
|
||||
"invariant": "^2.2.4",
|
||||
"prop-types": "^15.8.1",
|
||||
"prop-types-extra": "^1.1.0",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"uncontrollable": "^7.2.1",
|
||||
"warning": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.14.8",
|
||||
"react": ">=16.14.0",
|
||||
"react-dom": ">=16.14.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
|
||||
@ -2821,6 +3113,27 @@
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
|
||||
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.14.2",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||
@ -2831,6 +3144,68 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.2.0.tgz",
|
||||
"integrity": "sha512-fXyqzPgCPZbqhrk7k3hPcCpYIlQ2ugIXDboHUzhJISFVy2DEPsmHgN588MyGmkIOv3jDgNfUE3kJi83L28s/LQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.6.0",
|
||||
"cookie": "^1.0.1",
|
||||
"set-cookie-parser": "^2.6.0",
|
||||
"turbo-stream": "2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.2.0.tgz",
|
||||
"integrity": "sha512-cU7lTxETGtQRQbafJubvZKHEn5izNABxZhBY0Jlzdv0gqQhCPQt2J8aN5ZPjS6mQOXn5NnirWNh+FpE8TTYN0Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-router": "7.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"dom-helpers": "^5.0.1",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.6.0",
|
||||
"react-dom": ">=16.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
@ -2931,6 +3306,12 @@
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
|
||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@ -3016,6 +3397,18 @@
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/turbo-stream": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
|
||||
"integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@ -3044,15 +3437,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.0.tgz",
|
||||
"integrity": "sha512-/lmv4366en/qbB32Vz5+kCNZEMf6xYHwh1z48suBwZvAtnXKbP+YhGe8OLE2BqC67LMqKkCNLtjejdwsdW6uOQ==",
|
||||
"version": "8.24.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.1.tgz",
|
||||
"integrity": "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.24.0",
|
||||
"@typescript-eslint/parser": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.24.1",
|
||||
"@typescript-eslint/parser": "8.24.1",
|
||||
"@typescript-eslint/utils": "8.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -3066,6 +3459,21 @@
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uncontrollable": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
|
||||
"integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@types/react": ">=16.9.11",
|
||||
"invariant": "^2.2.4",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||
@ -3115,14 +3523,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
|
||||
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz",
|
||||
"integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.24.2",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss": "^8.5.2",
|
||||
"rollup": "^4.30.1"
|
||||
},
|
||||
"bin": {
|
||||
@ -3186,6 +3594,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "surge365.massemailreact.client",
|
||||
"homepage": ".",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
@ -10,11 +11,19 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"admin-lte": "4.0.0-beta3",
|
||||
"bootstrap": "^5.3.3",
|
||||
"font-awesome": "^4.7.0",
|
||||
"ionicons": "^7.4.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
"react-dom": "^19.0.0",
|
||||
"react-bootstrap": "^2.10.9",
|
||||
"react-icons": "^5.3.0",
|
||||
"react-router-dom": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@types/node": "^22",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
@ -24,7 +33,7 @@
|
||||
"globals": "^15.14.0",
|
||||
"typescript": "~5.7.2",
|
||||
"typescript-eslint": "^8.22.0",
|
||||
"vite": "^6.1.0",
|
||||
"@types/node": "^22"
|
||||
}
|
||||
}
|
||||
"vite": "^6.1.0"
|
||||
},
|
||||
"proxy": "http://localhost:5293"
|
||||
}
|
||||
|
||||
@ -0,0 +1,108 @@
|
||||
const INTERNAL_SECOND_MS = 60 * 1000;
|
||||
const INTERNAL_MINUTE_MS = 60 * INTERNAL_SECOND_MS;
|
||||
const INTERNAL_HOUR_MS = 60 * INTERNAL_MINUTE_MS;
|
||||
|
||||
var isIndexedDBSupported = 'indexedDB' in window;
|
||||
|
||||
|
||||
$.dbManager = {
|
||||
openDatabases: {}
|
||||
}
|
||||
|
||||
$.dbManager.alert = function (msg) {
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
$.dbManager.openDatabase = function (name, version, onUpgradeNeeded) {
|
||||
let dbManager = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
let db = dbManager.openDatabases[name];
|
||||
if (db !== undefined && db !== null) {
|
||||
resolve(db);
|
||||
return;
|
||||
}
|
||||
let request = indexedDB.open(name, version);
|
||||
request.onupgradeneeded = function (event) {
|
||||
//Upgrade DB? Drop DB and reload? For now, drop db
|
||||
console.log("onupgradeneeded");
|
||||
|
||||
if (onUpgradeNeeded != null) {
|
||||
onUpgradeNeeded(event);
|
||||
}
|
||||
else {
|
||||
dbManager.deleteDatabase(name).then(
|
||||
function onSuccess(db) {
|
||||
resolve(db);
|
||||
},
|
||||
function onError(error) {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
//reject("Upgrade Needed");
|
||||
};
|
||||
|
||||
request.onerror = function () {
|
||||
console.error("Error: ", request.error);
|
||||
reject(request.error);
|
||||
};
|
||||
|
||||
request.onblocked = function () {
|
||||
console.error();
|
||||
reject("Database blocked");
|
||||
};
|
||||
|
||||
request.onsuccess = function () {
|
||||
let db = request.result;
|
||||
|
||||
db.onversionchange = function (event) {
|
||||
let isDeleted = event.newVersion === null;
|
||||
db.close();
|
||||
if(!isDeleted)
|
||||
alert("Database is outdated, please reload the page: ", event.currentTarget.name)
|
||||
};
|
||||
|
||||
console.log("Database opened: ", name);
|
||||
if (dbManager.openDatabases == null)
|
||||
dbManager.openDatabases = {};
|
||||
|
||||
dbManager.openDatabases[name] = db;
|
||||
db.onclose = function () { //TODO: DOesn't appear to be called currently
|
||||
console.log('Database connection closed: ', name);
|
||||
dbManager.openDatabases[name] = null;
|
||||
}
|
||||
resolve(db);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
$.dbManager.closeDatabase = function (name) {
|
||||
let currentDB = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
let db = currentDB.openDatabases[name];
|
||||
if (db != null) {
|
||||
db.close();
|
||||
}
|
||||
currentDB.openDatabases[name] == null;
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
$.dbManager.deleteDatabase = function (name) {
|
||||
let currentDB = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
let request = indexedDB.deleteDatabase(name);
|
||||
|
||||
request.onerror = function () {
|
||||
console.error("Error", request.error);
|
||||
reject(request.error);
|
||||
};
|
||||
|
||||
request.onsuccess = function () {
|
||||
console.log("database deleted: ", name);
|
||||
currentDB.openDatabases[name] = null;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -0,0 +1,610 @@
|
||||
|
||||
|
||||
//global variables
|
||||
var table;
|
||||
var allUsers = [];
|
||||
var user = null;
|
||||
|
||||
//login stuff
|
||||
function logout() {
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods',
|
||||
'methodName': 'LogOut',
|
||||
'parameters': {},
|
||||
success: function (json) {
|
||||
|
||||
document.location.href = '/login.aspx';
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkLoggedInStatus() {
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods',
|
||||
'methodName': 'CheckAuthToken',
|
||||
'parameters': {},
|
||||
success: function (json) {
|
||||
if ($.getBoolean(json.success)) {
|
||||
$.localStorage("session_currentUser", json.data);
|
||||
|
||||
|
||||
//set user info
|
||||
user = $.localStorage("session_currentUser");
|
||||
|
||||
//set franchise if it isn't set yet.
|
||||
//franchiseDeferred = $.Deferred();
|
||||
|
||||
//call back to page that called this method.
|
||||
// $.when(franchiseDeferred).done(function () {
|
||||
/*
|
||||
if ($.sessionStorage("Auth-Impersonate-Guid") != null) {
|
||||
//session is being impersonated, override name and signout
|
||||
$("#spanProfileName").html("Signed in as " + user.FirstName + ' ' + user.LastName);
|
||||
$("#spanProfileNameTitle").html("Signed in as " + user.FirstName + ' ' + user.LastName);
|
||||
}
|
||||
else {
|
||||
$("#spanProfileName").html(user.FirstName + ' ' + user.LastName);
|
||||
$("#spanProfileNameTitle").html(user.FirstName + ' ' + user.LastName);
|
||||
} */
|
||||
|
||||
// $("#spanMenuName").html(user.FirstName + ' ' + user.LastName);
|
||||
|
||||
// var userid = $.localStorage("session_currentUser").UserID;
|
||||
// var imgid = userid + "&t=" + new Date().getTime();
|
||||
/*
|
||||
if (user.HasProfileImage) {
|
||||
$("#imgRightProfile").attr("src", "/webservices/getprofileimage.ashx?id=" + imgid);
|
||||
$("#imgRightProfile").on('error', function () {
|
||||
$("#imgRightProfile").attr("src", "/img/generic_avatar.jpg");
|
||||
});
|
||||
|
||||
$("#imgLeftProfile").attr("src", "/webservices/getprofileimage.ashx?id=" + imgid);
|
||||
$("#imgLeftProfile").on('error', function () {
|
||||
$("#imgLeftProfile").attr("src", "/img/generic_avatar.jpg");
|
||||
});
|
||||
|
||||
$("#imgMainProfile").attr("src", "/webservices/getprofileimage.ashx?id=" + imgid);
|
||||
$("#imgMainProfile").on('error', function () {
|
||||
$("#imgMainProfile").attr("src", "/img/generic_avatar.jpg");
|
||||
});
|
||||
}
|
||||
else {
|
||||
$("#imgRightProfile").attr("src", "/img/generic_avatar.jpg");
|
||||
$("#imgLeftProfile").attr("src", "/img/generic_avatar.jpg");
|
||||
$("#imgMainProfile").attr("src", "/img/generic_avatar.jpg");
|
||||
} */
|
||||
|
||||
loadPage();
|
||||
|
||||
}
|
||||
else {
|
||||
$.sessionStorage("redirect_url", document.location.href);
|
||||
document.location.href = '/login';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setCurrentFranchise(d) {
|
||||
$.usaHaulersDB.getFranchises().then((data) => {
|
||||
$.sessionStorage("currentFranchise", data);
|
||||
if (d != null) {
|
||||
d.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
search = {};
|
||||
search.FranchiseCode = $.sessionStorage("franchiseCode");
|
||||
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods/',
|
||||
'methodName': 'GetReport_Franchise',
|
||||
'parameters': { "search": search },
|
||||
success: function (json) {
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
$.sessionStorage("currentFranchise", json.data[0]);
|
||||
if (d != null) {
|
||||
d.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
}); */
|
||||
|
||||
}
|
||||
|
||||
function createSetting(obj, settingTypeCode, value) {
|
||||
|
||||
//see if setting exists
|
||||
var bFound = false;
|
||||
for (var x = 0; x < obj.Settings.length; x++) {
|
||||
if (obj.Settings[x].SettingTypeCode == settingTypeCode) {
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bFound) {
|
||||
//existing setting
|
||||
obj.Settings[x].Value = value;
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
setting = {}
|
||||
setting.SettingTypeCode = settingTypeCode;
|
||||
setting.Value = value;
|
||||
|
||||
if (obj.Settings == null) {
|
||||
obj.Settings = [];
|
||||
}
|
||||
obj.Settings.push(setting);
|
||||
}
|
||||
}
|
||||
|
||||
function createCaseSetting(obj, settingTypeCode, value) {
|
||||
|
||||
//see if setting exists
|
||||
var bFound = false;
|
||||
for (var x = 0; x < obj.settings.length; x++) {
|
||||
if (obj.settings[x].case_setting_type_code == settingTypeCode) {
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bFound) {
|
||||
//existing setting
|
||||
obj.settings[x].value = value;
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
setting = {}
|
||||
setting.case_setting_type_code = settingTypeCode;
|
||||
setting.value = value;
|
||||
|
||||
if (obj.settings == null) {
|
||||
obj.settings = [];
|
||||
}
|
||||
obj.settings.push(setting);
|
||||
}
|
||||
}
|
||||
|
||||
function getReportSetting(settings, setting_field, setting_code) {
|
||||
var value = "";
|
||||
if (settings != null) {
|
||||
for (var x = 0; x < settings.length; x++) {
|
||||
setting = settings[x];
|
||||
if (setting[setting_field] == setting_code) {
|
||||
value = setting["value"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function getSetting(settings, settingTypeCode) {
|
||||
var value = "";
|
||||
for (var x = 0; x < settings.length; x++) {
|
||||
setting = settings[x];
|
||||
if (setting.SettingTypeCode == settingTypeCode) {
|
||||
value = setting.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//web calls
|
||||
function callMethod(methodname, callback, sessionName, deferred, search) {
|
||||
|
||||
var params = {};
|
||||
|
||||
if (search == null) {
|
||||
search = {};
|
||||
}
|
||||
|
||||
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods/',
|
||||
'methodName': methodname,
|
||||
'parameters': { "search": search },
|
||||
success: function (json) {
|
||||
|
||||
$.sessionStorage(sessionName, json.data);
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
if (deferred != null) {
|
||||
deferred.resolve(true);
|
||||
}
|
||||
if (callback != null) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
else {
|
||||
notify("Error", "There was an error performing this action. Please try again.")
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function callSearchTransactions(methodname, callback, sessionName, deferred, search) {
|
||||
//REPEAT OF CALL METHOD,, JSON.DATA DOESN'T WORK HERE..
|
||||
//TODO MAKE DYNAMIC LATER.
|
||||
|
||||
var params = {};
|
||||
|
||||
if (search == null) {
|
||||
search = {};
|
||||
}
|
||||
|
||||
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods/',
|
||||
'methodName': methodname,
|
||||
'parameters': { "search": search },
|
||||
success: function (json) {
|
||||
|
||||
$.sessionStorage(sessionName, json);
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
if (deferred != null) {
|
||||
deferred.resolve(true);
|
||||
}
|
||||
if (callback != null) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
else {
|
||||
notify("Error", "There was an error performing this action. Please try again.")
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
//overlay
|
||||
function showwait(item) {
|
||||
$("#waitOverlay").show();
|
||||
if (item) {
|
||||
item.show();
|
||||
|
||||
}
|
||||
else {
|
||||
$("#loading").show();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
function hidewait(item) {
|
||||
$("#waitOverlay").hide();
|
||||
if (item) {
|
||||
item.hide();
|
||||
}
|
||||
else {
|
||||
$("#loading").hide();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//helper function
|
||||
function getParameterByName(name) {
|
||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
||||
results = regex.exec(location.search);
|
||||
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
}
|
||||
function getCurrency(val) {
|
||||
return '$' + parseFloat(val, 10).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,").toString()
|
||||
}
|
||||
function getDate(val) {
|
||||
var newDate = new Date(Date.parse(val)).toLocaleDateString()
|
||||
return newDate;
|
||||
}
|
||||
function changeDateFormat(inputDate) { // expects Y-m-d
|
||||
var splitDate = inputDate.split('-');
|
||||
if (splitDate.count == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var year = splitDate[0];
|
||||
var month = splitDate[1];
|
||||
var day = splitDate[2];
|
||||
|
||||
return month + '/' + day + '/' + year;
|
||||
}
|
||||
|
||||
function getTime(val) {
|
||||
var newDate = new Date(Date.parse(val)).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
return newDate;
|
||||
}
|
||||
function getDateAndTime(val) {
|
||||
var newDate = new Date(Date.parse(val)).toLocaleDateString() + ' ' + new Date(Date.parse(val)).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true })
|
||||
return newDate;
|
||||
}
|
||||
function getDateAndTimeAndSeconds(val) {
|
||||
var newDate = new Date(Date.parse(val)).toLocaleDateString() + ' ' + new Date(Date.parse(val)).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true, second: '2-digit' })
|
||||
return newDate;
|
||||
}
|
||||
function notify(title, message) {
|
||||
$.gritter.add({
|
||||
title: title,
|
||||
text: message,
|
||||
sticky: false,
|
||||
time: '2000',
|
||||
|
||||
});
|
||||
}
|
||||
function getObjectByKey(key, value, objectArray) {
|
||||
for (var x = 0; x < objectArray.length; x++) {
|
||||
if (objectArray[x][key] == value) {
|
||||
return objectArray[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatSelect2Data(id, name, data) {
|
||||
var newdata = [];
|
||||
//var blank = { };
|
||||
// blank.id = "";
|
||||
//blank.text = "";
|
||||
//data.push(blank);
|
||||
for (var x = 0; x < data.length; x++) {
|
||||
var obj = {};
|
||||
obj.id = data[x][id];
|
||||
obj.text = data[x][name]
|
||||
newdata.push(obj);
|
||||
|
||||
}
|
||||
return newdata;
|
||||
}
|
||||
|
||||
function formatSelect2DataForReturnedBatched(id, name, data) {
|
||||
var newdata = [];
|
||||
//var blank = { };
|
||||
// blank.id = "";
|
||||
//blank.text = "";
|
||||
//data.push(blank);
|
||||
for (var x = 0; x < data.length; x++) {
|
||||
if (data[x].Type != "ShiftCharges") {
|
||||
var obj = {};
|
||||
obj.id = data[x][id];
|
||||
obj.text = data[x][name]
|
||||
newdata.push(obj);
|
||||
}
|
||||
|
||||
}
|
||||
return newdata;
|
||||
}
|
||||
|
||||
function formatSelect2DataForUser(id, data) {
|
||||
var newdata = [];
|
||||
//var blank = { };
|
||||
// blank.id = "";
|
||||
//blank.text = "";
|
||||
//data.push(blank);
|
||||
for (var x = 0; x < data.length; x++) {
|
||||
var obj = {};
|
||||
obj.id = data[x][id];
|
||||
obj.text = data[x]["FirstName"] + ' ' + data[x]["LastName"] + ' - ' + data[x]["UserID"];
|
||||
newdata.push(obj);
|
||||
|
||||
}
|
||||
return newdata;
|
||||
}
|
||||
|
||||
//batches
|
||||
function fillDropDown(dropdown, method, session, deferred, fieldname, fieldvalue, placeholder) {
|
||||
if ($.sessionStorage(session) == null) {
|
||||
callMethod(method, fillDropDown, session, deferred, null);
|
||||
}
|
||||
else {
|
||||
var data = formatSelect2Data(fieldname, fieldvalue, $.sessionStorage(session));
|
||||
$(control).select2({
|
||||
placeholder: placeholder,
|
||||
allowClear: true,
|
||||
selectOnClose: false,
|
||||
//closeOnSelect: false,
|
||||
data: data,
|
||||
width: "200px"
|
||||
});
|
||||
batchDeferred.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var currentDropdown;
|
||||
//location
|
||||
function fillLocationsDropDown(deferred) {
|
||||
|
||||
|
||||
|
||||
var search = {};
|
||||
if (!$.userHasRole("Administrators")) {
|
||||
search.UserID = $.localStorage("session_currentUser").UserID;
|
||||
}
|
||||
else {
|
||||
search = null;
|
||||
}
|
||||
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods/',
|
||||
'methodName': 'SearchLocations',
|
||||
'parameters': { "search": search },
|
||||
success: function (json) {
|
||||
|
||||
$.sessionStorage("session_locations", json.data);
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
var data = formatSelect2Data("ID", "Name", $.sessionStorage("session_locations"));
|
||||
|
||||
if ($.userHasRole("Administrators")) {
|
||||
$("#selLocation").select2({
|
||||
placeholder: "Select a location...",
|
||||
allowClear: true,
|
||||
selectOnClose: false,
|
||||
//closeOnSelect: false,
|
||||
data: data
|
||||
});
|
||||
$("#selLocation").enable(true);
|
||||
}
|
||||
else {
|
||||
$("#selLocation").select2({
|
||||
|
||||
data: data
|
||||
});
|
||||
$("#selLocation").select2('val', data[0].id);
|
||||
$("#selLocation").enable(false);
|
||||
}
|
||||
|
||||
if (deferred != null) {
|
||||
deferred.resolve(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
notify("Error", "There was an error performing this action. Please try again.")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
var currentSpinner = null
|
||||
function spin2(spin) {
|
||||
//spinner = $("#spanSpinner");
|
||||
currentSpinner.show();
|
||||
|
||||
if (spin) {
|
||||
rotation = function () {
|
||||
currentSpinner.rotate({
|
||||
angle: 0,
|
||||
animateTo: 360,
|
||||
callback: rotation
|
||||
});
|
||||
}
|
||||
rotation();
|
||||
}
|
||||
else {
|
||||
currentSpinner.stopRotate();
|
||||
currentSpinner.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function spin(spin, spinner) {
|
||||
//spinner = $("#spanSpinner");
|
||||
spinner.show();
|
||||
|
||||
if (spin) {
|
||||
rotation = function () {
|
||||
spinner.rotate({
|
||||
angle: 0,
|
||||
animateTo: 360,
|
||||
callback: rotation
|
||||
});
|
||||
}
|
||||
rotation();
|
||||
}
|
||||
else {
|
||||
spinner.stopRotate();
|
||||
spinner.hide();
|
||||
}
|
||||
}
|
||||
|
||||
//employee
|
||||
function fillEmployeesDropDown(deferred, dropdown) {
|
||||
|
||||
if (dropdown == null) {
|
||||
dropdown = $("#selEmployee");
|
||||
}
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods/',
|
||||
'methodName': 'GetUsers',
|
||||
'parameters': { "activeOnly": false },
|
||||
success: function (json) {
|
||||
|
||||
$.sessionStorage("session_users", json.data);
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
var data = formatSelect2DataForUser("UserID", $.sessionStorage("session_users"));
|
||||
dropdown.select2({
|
||||
placeholder: "Select an employee...",
|
||||
allowClear: true,
|
||||
selectOnClose: false,
|
||||
//closeOnSelect: false,
|
||||
data: data
|
||||
});
|
||||
|
||||
if (deferred != null) {
|
||||
deferred.resolve(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
notify("Error", "There was an error performing this action. Please try again.")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//new imove global functions
|
||||
|
||||
|
||||
function stripCharacters(str) {
|
||||
return str.replace(/[-' ]/g, '').toUpperCase();
|
||||
}
|
||||
|
||||
function searchUsers(d) {
|
||||
search = {};
|
||||
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods/',
|
||||
'methodName': 'SearchUsers',
|
||||
'parameters': { "search": search },
|
||||
success: function (json) {
|
||||
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
|
||||
allUsers = json.data;
|
||||
d.resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function growlWarn(msg) {
|
||||
$.bootstrapGrowl("<strong>" + msg + "</strong>", {
|
||||
type: 'warning',
|
||||
align: 'center',
|
||||
width: 'auto',
|
||||
allow_dismiss: true,
|
||||
offset: { from: 'top', amount: 60 }
|
||||
});
|
||||
}
|
||||
function growlSuccess(msg) {
|
||||
$.bootstrapGrowl("<strong>" + msg + "</strong>", {
|
||||
type: 'success',
|
||||
align: 'center',
|
||||
width: 'auto',
|
||||
allow_dismiss: true,
|
||||
offset: { from: 'top', amount: 60 }
|
||||
});
|
||||
}
|
||||
|
||||
function getUser(users, id) {
|
||||
for (var x = 0; x < users.length; x++) {
|
||||
if (users[x].UserID == id) {
|
||||
return users[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,931 @@
|
||||
const DEFAULT_LOG_LEVELS_TO_LOG = ["debug","warn","info","error"];
|
||||
const DEFAULT_LOG_AJAX_REQUESTS = true;
|
||||
|
||||
const DEFAULT_LOG_AJAX_REQUESTS_TO_CONSOLE = true;
|
||||
const DEFAULT_LOG_AJAX_REQUESTS_TO_CONSOLE_ERROR_ONLY = true;
|
||||
const DEFAULT_LOG_AJAX_REQUESTS_TO_CONSOLE_MAX_RESPONSE_CHARS = 200
|
||||
|
||||
///CURRENTLY THESE INDEXEDDB CONSTS ARE NOT USED, LEAVING HERE IN CASE I FIGURE OUT HOW TO WIRE THEM UP.
|
||||
const DEFAULT_LOG_AJAX_REQUESTS_TO_INDEXEDDB = true;
|
||||
const DEFAULT_LOG_AJAX_REQUESTS_TO_INDEXEDDB_ERROR_ONLY = true;
|
||||
const DEFAULT_LOG_AJAX_REQUESTS_TO_INDEXEDDB_MAX_RESPONSE_CHARS = -1 //< 0 = log all, 0 = log none, > 0 log that # of chars
|
||||
const DEFAULT_LOG_URL = 'https://usahaulerslog.solutionsmith.net/WebServices/LoggingMethods.aspx/SaveLogs';
|
||||
|
||||
const INTERNAL_LOG_URLS = {
|
||||
DEFAULT: "https://usahaulerslogdev.solutionsmith.net/WebServices/LoggingMethods.aspx/SaveLogs",
|
||||
DEV: "https://usahaulerslogdev.solutionsmith.net/WebServices/LoggingMethods.aspx/SaveLogs",
|
||||
PROD: "https://usahaulerslog.solutionsmith.net/WebServices/LoggingMethods.aspx/SaveLogs"
|
||||
}
|
||||
const DEFAULT_LOG_CONFIG_OBJECT = {
|
||||
id: 0,
|
||||
defaultLogLevelsToLog: DEFAULT_LOG_LEVELS_TO_LOG,
|
||||
logAjaxRequests: DEFAULT_LOG_AJAX_REQUESTS,
|
||||
logAjaxRequestsToConsole: DEFAULT_LOG_AJAX_REQUESTS_TO_CONSOLE,
|
||||
logAjaxRequestsToConsoleErrorOnly: DEFAULT_LOG_AJAX_REQUESTS_TO_CONSOLE_ERROR_ONLY,
|
||||
logAjaxRequestsToConsoleMaxResponseChars: DEFAULT_LOG_AJAX_REQUESTS_TO_CONSOLE_MAX_RESPONSE_CHARS,
|
||||
logAjaxRequestsToIndexedDB: DEFAULT_LOG_AJAX_REQUESTS_TO_INDEXEDDB,
|
||||
logAjaxRequestsToIndexedDBErrorOnly: DEFAULT_LOG_AJAX_REQUESTS_TO_INDEXEDDB_ERROR_ONLY,
|
||||
logAjaxRequestsToIndexedDBMaxResponseChars: DEFAULT_LOG_AJAX_REQUESTS_TO_INDEXEDDB_MAX_RESPONSE_CHARS
|
||||
}
|
||||
|
||||
const OLD_CONSOLE_LOG = console.log;
|
||||
const OLD_CONSOLE_DEBUG = console.debug;
|
||||
const OLD_CONSOLE_WARN = console.warn;
|
||||
const OLD_CONSOLE_INFO = console.info;
|
||||
const OLD_CONSOLE_ERROR = console.error;
|
||||
|
||||
const USAHAULERSLOGGING_DATABASE_NAME = "usahaulerslogging";
|
||||
const USAHAULERSLOGGING_DATABASE_VERSION = 1;
|
||||
|
||||
const INTERNAL_USAHAULERSLOGGING_USEHAULERSLOGGINGDBCONFIG_OBJECT_STORE = "usahaulersloggingdb.config";
|
||||
const INTERNAL_USAHAULERSLOGGING_LOG_REFRESH_PERIOD = INTERNAL_MINUTE_MS * 5;
|
||||
|
||||
const INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE = "logs";
|
||||
const INTERNAL_USAHAULERSLOGGING_LOG_INDEX_DATE = "date";
|
||||
const INTERNAL_USAHAULERSLOGGING_LOG_INDEX_LEVEL = "level";
|
||||
const INTERNAL_USAHAULERSLOGGING_LOG_INDEX_UPLOADED = "uploaded";
|
||||
const INTERNAL_USAHAULERSLOGGING_MAXUPLOADQTY = 100
|
||||
|
||||
$.usaHaulersLoggingDB = {
|
||||
config: DEFAULT_LOG_CONFIG_OBJECT,
|
||||
shouldLogLevel: (level) => {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return config.defaultLogLevelsToLog.includes(level.trim().toLowerCase());
|
||||
},
|
||||
shouldLogAjaxRequests: function () {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return config.logAjaxRequests && (config.logAjaxRequestsToConsole || config.logAjaxRequestsToIndexedDB);
|
||||
},
|
||||
shouldLogAjaxRequestsToConsole: function () {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return config.logAjaxRequests && config.logAjaxRequestsToConsole;
|
||||
},
|
||||
shouldLogAjaxRequestsToConsoleErrorOnly: function () {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return config.logAjaxRequests && config.logAjaxRequestsToConsole && config.logAjaxRequestsToConsoleErrorOnly;
|
||||
},
|
||||
logAjaxRequestsToConsoleMaxResponseChars: function () {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return (config.logAjaxRequests && config.logAjaxRequestsToConsole ? config.logAjaxRequestsToConsoleMaxResponseChars : 0);
|
||||
},
|
||||
shouldLogAjaxRequestsToIndexedDB: function () {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return config.logAjaxRequests && config.logAjaxRequestsToIndexedDB && $.usaHaulersLoggingDB.dbInitialized;
|
||||
},
|
||||
shouldLogAjaxRequestsToIndexedDBErrorOnly: function () {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return config.logAjaxRequests && config.logAjaxRequestsToIndexedDB && config.logAjaxRequestsToIndexedDBErrorOnly;
|
||||
},
|
||||
logAjaxRequestsToIndexedDBMaxResponseChars: function () {
|
||||
var config = $.usaHaulersLoggingDB.config;
|
||||
if (config == null)
|
||||
config = DEFAULT_LOG_CONFIG_OBJECT;
|
||||
return (config.logAjaxRequests && config.logAjaxRequestsToIndexedDB ? config.logAjaxRequestsToIndexedDBMaxResponseChars : 0);
|
||||
},
|
||||
prepareLog: function (argumentArray) {
|
||||
var LOG_PREFIX = new Date().toISOString();
|
||||
var args = Array.from(argumentArray);
|
||||
args.unshift(LOG_PREFIX + ": ");
|
||||
return args;
|
||||
},
|
||||
getLogMsgFromArguments: function (argumentArray) {
|
||||
if (argumentArray === undefined || argumentArray === null)
|
||||
return "Unknown log request: null/undefined passed to getLogMsgFromArguments";
|
||||
|
||||
var args = Array.from(argumentArray);
|
||||
|
||||
var msg = "";
|
||||
|
||||
args.forEach((arg) => {
|
||||
var msg1 = "";
|
||||
if (arg !== undefined && arg !== null) {
|
||||
if (typeof arg === 'object')
|
||||
msg1 = JSON.stringify(arg);
|
||||
else
|
||||
msg1 = arg.toString();
|
||||
|
||||
if (msg.length > 0)
|
||||
msg += ", ";
|
||||
|
||||
msg += msg1;
|
||||
}
|
||||
});
|
||||
return msg;
|
||||
},
|
||||
getBoolean: function (variable) {
|
||||
if ($.getBoolean)
|
||||
return $.getBoolean(variable);
|
||||
|
||||
var vtype;
|
||||
var toReturn;
|
||||
|
||||
if (variable != null) {
|
||||
switch (typeof (variable)) {
|
||||
case 'boolean':
|
||||
vtype = "boolean";
|
||||
return variable;
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
vtype = "number";
|
||||
if (variable == 0)
|
||||
toReturn = false;
|
||||
else toReturn = true;
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
vtype = "string";
|
||||
if (variable.toLowerCase() == "true" || variable.toLowerCase() == "yes")
|
||||
toReturn = true;
|
||||
else if (variable.toLowerCase() == "false" || variable.toLowerCase() == "no")
|
||||
toReturn = false;
|
||||
else if (variable.length > 0)
|
||||
toReturn = true;
|
||||
else if (variable.length == 0)
|
||||
toReturn = false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
},
|
||||
removeObjectMethodsForSerialization: function (obj) {
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
catch (error) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log = console.debug = function () {
|
||||
var args = $.usaHaulersLoggingDB.prepareLog(arguments);
|
||||
OLD_CONSOLE_DEBUG.apply(console, args);
|
||||
if ($.usaHaulersLoggingDB && $.usaHaulersLoggingDB.addLog && $.usaHaulersLoggingDB.dbInitialized && $.usaHaulersLoggingDB.shouldLogLevel("debug")) {
|
||||
var msg = $.usaHaulersLoggingDB.getLogMsgFromArguments(arguments);
|
||||
var dbArgs = Array.from(arguments);
|
||||
$.usaHaulersLoggingDB.addLog("DEBUG", msg, dbArgs);
|
||||
}
|
||||
}
|
||||
console.warn = function () {
|
||||
var args = $.usaHaulersLoggingDB.prepareLog(arguments);
|
||||
OLD_CONSOLE_WARN.apply(console, args);
|
||||
if ($.usaHaulersLoggingDB && $.usaHaulersLoggingDB.addLog && $.usaHaulersLoggingDB.dbInitialized && $.usaHaulersLoggingDB.shouldLogLevel("warn")) {
|
||||
var msg = $.usaHaulersLoggingDB.getLogMsgFromArguments(arguments);
|
||||
var dbArgs = Array.from(arguments);
|
||||
$.usaHaulersLoggingDB.addLog("WARN", msg, dbArgs);
|
||||
}
|
||||
}
|
||||
console.info = function () {
|
||||
var args = $.usaHaulersLoggingDB.prepareLog(arguments);
|
||||
OLD_CONSOLE_INFO.apply(console, args);
|
||||
if ($.usaHaulersLoggingDB && $.usaHaulersLoggingDB.addLog && $.usaHaulersLoggingDB.dbInitialized && $.usaHaulersLoggingDB.shouldLogLevel("info")) {
|
||||
var msg = $.usaHaulersLoggingDB.getLogMsgFromArguments(arguments);
|
||||
var dbArgs = Array.from(arguments);
|
||||
$.usaHaulersLoggingDB.addLog("INFO", msg, dbArgs);
|
||||
}
|
||||
}
|
||||
console.error = function () {
|
||||
var args = $.usaHaulersLoggingDB.prepareLog(arguments);
|
||||
OLD_CONSOLE_ERROR.apply(console, args);
|
||||
if ($.usaHaulersLoggingDB && $.usaHaulersLoggingDB.addLog && $.usaHaulersLoggingDB.dbInitialized && $.usaHaulersLoggingDB.shouldLogLevel("error")) {
|
||||
var msg = $.usaHaulersLoggingDB.getLogMsgFromArguments(arguments);
|
||||
var dbArgs = Array.from(arguments);
|
||||
$.usaHaulersLoggingDB.addLog("ERROR", msg, dbArgs);
|
||||
}
|
||||
}
|
||||
|
||||
if ($ && $.ajaxSetup) {
|
||||
$(document).ready(function () {
|
||||
$(document).ajaxSuccess(function (event, xhr, settings) {
|
||||
if ($.usaHaulersLoggingDB.shouldLogAjaxRequests()) {
|
||||
var responseText = "";
|
||||
var isSuccess = true;
|
||||
if (xhr.responseJson != null && xhr.responseJson.d != null && xhr.responseJson.d.success != null && !xhr.responseJson.d.success)
|
||||
isSuccess = false;
|
||||
|
||||
if (!$.usaHaulersLoggingDB.shouldLogAjaxRequestsToConsoleErrorOnly() || !isSuccess) {
|
||||
if (xhr.responseText && xhr.responseText != null) {
|
||||
if ($.usaHaulersLoggingDB.logAjaxRequestsToConsoleMaxResponseChars() <= 0 || xhr.responseText.length <= $.usaHaulersLoggingDB.logAjaxRequestsToConsoleMaxResponseChars())
|
||||
responseText = "response = '" + xhr.responseText + "';";
|
||||
else
|
||||
responseText = "responseSnippet='" + xhr.responseText.substring(0, $.usaHaulersLoggingDB.logAjaxRequestsToConsoleMaxResponseChars()) + "';";
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($.usaHaulersLoggingDB.shouldLogAjaxRequestsToConsole()) {
|
||||
if (!isSuccess)
|
||||
console.debug("Ajax Success, returned success:false", {
|
||||
url: settings.url,
|
||||
httpMethod: settings.type,
|
||||
responseText: responseText
|
||||
});
|
||||
else {
|
||||
console.debug("Ajax Success", {
|
||||
url: settings.url,
|
||||
httpMethod: settings.type,
|
||||
responseText: responseText
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xhr.responseJson != null && xhr.responseJson.d != null && xhr.responseJson.d.success != null && xhr.responseJson.d.success) {
|
||||
var lg_session_guid = request.getResponseHeader('lg_session_guid');
|
||||
var lg_access_token = $.getBoolean(request.getResponseHeader('lg_access_token'));
|
||||
var lg_application_code = $.getBoolean(request.getResponseHeader('lg_application_code'));
|
||||
var lg_application_user_id = $.getBoolean(request.getResponseHeader('lg_application_user_id'));
|
||||
if ($.cookie) {
|
||||
$.cookie.raw = true;
|
||||
$.cookie('lg_session_guid', lg_session_guid, { path: '/' });
|
||||
$.cookie('lg_access_token', lg_access_token, { path: '/' });
|
||||
$.cookie('lg_application_code', lg_application_code, { path: '/' });
|
||||
$.cookie('lg_application_user_id', lg_application_user_id, { path: '/' });
|
||||
}
|
||||
}
|
||||
});
|
||||
$(document).ajaxError(function (event, xhr, settings) {
|
||||
if ($.usaHaulersLoggingDB.shouldLogAjaxRequests()) {
|
||||
var responseText = "";
|
||||
|
||||
if (xhr.responseText && xhr.responseText != null) {
|
||||
if ($.usaHaulersLoggingDB.logAjaxRequestsToConsoleMaxResponseChars() <= 0 || xhr.responseText.length <= $.usaHaulersLoggingDB.logAjaxRequestsToConsoleMaxResponseChars())
|
||||
responseText = "response = '" + xhr.responseText + "';";
|
||||
else
|
||||
responseText = "responseSnippet='" + xhr.responseText.substring(0, $.usaHaulersLoggingDB.logAjaxRequestsToConsoleMaxResponseChars()) + "';";
|
||||
}
|
||||
|
||||
if ($.usaHaulersLoggingDB.shouldLogAjaxRequestsToConsole()) {
|
||||
console.error("Ajax Error", {
|
||||
url: settings.url,
|
||||
httpMethod: settings.type,
|
||||
responseText: responseText,
|
||||
xhr: $.usaHaulersLoggingDB.removeObjectMethodsForSerialization(xhr),
|
||||
settings: $.usaHaulersLoggingDB.removeObjectMethodsForSerialization(settings)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const INTERNAL_USAHAULERSLOGGING_ONUPGRADEDNEEDED = function (event) {
|
||||
const db = event.target.result;
|
||||
const transaction = event.currentTarget.transaction;
|
||||
let oldVersion = event.oldVersion;
|
||||
let newVersion = event.newVersion;
|
||||
|
||||
if (oldVersion < 1 && newVersion >= 1) {
|
||||
|
||||
//setup object stores
|
||||
db.createObjectStore(INTERNAL_USAHAULERSLOGGING_USEHAULERSLOGGINGDBCONFIG_OBJECT_STORE, { keyPath: 'id' });
|
||||
|
||||
if (db.objectStoreNames.contains(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE)) {
|
||||
db.deleteObjectStore(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE);
|
||||
}
|
||||
db.createObjectStore(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, { keyPath: 'id' });
|
||||
|
||||
|
||||
//setup indexes
|
||||
let store = transaction.objectStore(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE);
|
||||
|
||||
if (store.indexNames.contains(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_DATE)) {
|
||||
store.deleteIndex(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_DATE);
|
||||
}
|
||||
store.createIndex(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_DATE, "date", { unique: false });
|
||||
|
||||
if (store.indexNames.contains(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_LEVEL)) {
|
||||
store.deleteIndex(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_LEVEL);
|
||||
}
|
||||
store.createIndex(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_LEVEL, "level", { unique: false });
|
||||
|
||||
if (store.indexNames.contains(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_UPLOADED)) {
|
||||
store.deleteIndex(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_UPLOADED);
|
||||
}
|
||||
store.createIndex(INTERNAL_USAHAULERSLOGGING_LOG_INDEX_UPLOADED, "upload_status", { unique: false });
|
||||
|
||||
}
|
||||
|
||||
if (oldVersion < 2 && newVersion >= 2) {
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$.extend($.usaHaulersLoggingDB, {
|
||||
dbInitialized: false,
|
||||
database: null,
|
||||
initializeDB: function () {
|
||||
let currentDB = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (currentDB.dbInitialized) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
currentDB.refreshConfigObject().then(function () {
|
||||
currentDB.dbInitialized = true;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
createConfigObject: function () {
|
||||
let currentDB = this;
|
||||
var config = (!currentDB.config || currentDB.config == null ? DEFAULT_LOG_CONFIG_OBJECT : currentDB.config);
|
||||
return config;
|
||||
},
|
||||
refreshConfigObject: function () {
|
||||
let currentDB = this;
|
||||
return new Promise(async function (resolve, reject) {
|
||||
try {
|
||||
let config = await currentDB.getObjects(INTERNAL_USAHAULERSLOGGING_USEHAULERSLOGGINGDBCONFIG_OBJECT_STORE);
|
||||
let configDefault = currentDB.createConfigObject();
|
||||
|
||||
if (!config || config.length == 0) {
|
||||
currentDB.config = configDefault;
|
||||
await currentDB.persistConfigObject();
|
||||
}
|
||||
else {
|
||||
currentDB.config = config[0];
|
||||
let updatedConfig = false;
|
||||
for (const prop in configDefault) {
|
||||
if (prop !== "id" || currentDB.config[prop] === undefined) {
|
||||
updatedConfig = true;
|
||||
currentDB.config[prop] = configDefault[prop];
|
||||
}
|
||||
}
|
||||
if (updatedConfig)
|
||||
await currentDB.persistConfigObject();
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
persistConfigObject: function () {
|
||||
let currentDB = this;
|
||||
return currentDB.runTransactionReadWrite(INTERNAL_USAHAULERSLOGGING_USEHAULERSLOGGINGDBCONFIG_OBJECT_STORE, async function (transaction) {
|
||||
const configStore = transaction.objectStore(INTERNAL_USAHAULERSLOGGING_USEHAULERSLOGGINGDBCONFIG_OBJECT_STORE);
|
||||
|
||||
configStore.put(currentDB.config);
|
||||
|
||||
return transaction.complete;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//#region basic indexeddb methods
|
||||
$.extend($.usaHaulersLoggingDB, {
|
||||
create: function (deleteIfExists = true) {
|
||||
return new Promise(async function (resolve, reject) {
|
||||
if (deleteIfExists === true) {
|
||||
try {
|
||||
await $.dbManager.deleteDatabase(USAHAULERSLOGGING_DATABASE_NAME);
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
await $.dbManager.openDatabase(USAHAULERSLOGGING_DATABASE_NAME, USAHAULERSLOGGING_DATABASE_VERSION, INTERNAL_USAHAULERSLOGGING_ONUPGRADEDNEEDED);
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
delete: function () {
|
||||
let currentDB = this;
|
||||
return $.dbManager.deleteDatabase(USAHAULERSLOGGING_DATABASE_NAME);
|
||||
},
|
||||
open: function () {
|
||||
let currentDB = this;
|
||||
return $.dbManager.openDatabase(USAHAULERSLOGGING_DATABASE_NAME, USAHAULERSLOGGING_DATABASE_VERSION, INTERNAL_USAHAULERSLOGGING_ONUPGRADEDNEEDED).then(
|
||||
function onSuccessInternal(db) {
|
||||
currentDB.database = db;
|
||||
if (!currentDB.dbInitialized)
|
||||
return currentDB.initializeDB();
|
||||
else
|
||||
return currentDB.refreshConfigObject();
|
||||
},
|
||||
function onErrorInternal(error) {
|
||||
}
|
||||
);
|
||||
},
|
||||
close: function () {
|
||||
let currentDB = this;
|
||||
|
||||
return $.dbManager.closeDatabase(USAHAULERSLOGGING_DATABASE_NAME).then(
|
||||
function onSuccessInternal(db) {
|
||||
currentDB.database = null;
|
||||
},
|
||||
function onErrorInternal(error) {
|
||||
}
|
||||
);
|
||||
},
|
||||
runTransactionReadOnly: function (objectNames, transactionCode) {
|
||||
let currentDB = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (transactionCode != null) {
|
||||
let didOpenDB = false;
|
||||
var onSuccessInternal = function () {
|
||||
let transaction = currentDB.database.transaction(objectNames, "readonly");
|
||||
|
||||
transactionCode(transaction);
|
||||
|
||||
//if (didOpenDB)
|
||||
// currentDB.close();
|
||||
|
||||
transaction.oncomplete = function (event) {
|
||||
resolve();
|
||||
};
|
||||
|
||||
transaction.onerror = function (event) {
|
||||
reject(error.error);
|
||||
};
|
||||
//Transactions auto-commit after scope ends, cannot manually commit
|
||||
};
|
||||
if ($.usaHaulersLoggingDB.database == null) {
|
||||
didOpenDB = true;
|
||||
currentDB.open().then(
|
||||
onSuccessInternal,
|
||||
function onErrorInternal(error) {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
else {
|
||||
onSuccessInternal();
|
||||
}
|
||||
}
|
||||
else {
|
||||
reject("No transactionCode passed");
|
||||
}
|
||||
});
|
||||
},
|
||||
runTransactionReadWrite: function (objectNames, transactionCode) {
|
||||
let currentDB = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (transactionCode != null) {
|
||||
let didOpenDB = false;
|
||||
var onSuccessInternal = function () {
|
||||
let transaction = currentDB.database.transaction(objectNames, "readwrite");
|
||||
|
||||
transactionCode(transaction);
|
||||
|
||||
//if (didOpenDB)
|
||||
// currentDB.close();
|
||||
|
||||
transaction.oncomplete = function (event) {
|
||||
resolve();
|
||||
};
|
||||
|
||||
transaction.onerror = function (event) {
|
||||
reject(error.error);
|
||||
};
|
||||
//Transactions auto-commit after scope ends, cannot manually commit
|
||||
};
|
||||
if ($.usaHaulersLoggingDB.database == null) {
|
||||
didOpenDB = true;
|
||||
currentDB.open().then(
|
||||
onSuccessInternal,
|
||||
function onErrorInternal(error) {
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
else {
|
||||
onSuccessInternal();
|
||||
}
|
||||
}
|
||||
else {
|
||||
reject("No transactionCode passed");
|
||||
}
|
||||
});
|
||||
},
|
||||
getObjects: function (objectName, query, indexes) {
|
||||
let currentDB = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentDB.runTransactionReadOnly(objectName, function (transaction) {
|
||||
const objectStore = transaction.objectStore(objectName);
|
||||
let request = {};
|
||||
if (indexes && ((typeof indexes === "string" || indexes instanceof String) == false || indexes.length > 0))
|
||||
if (query
|
||||
&& (typeof query === "IDBKeyRange" || query instanceof IDBKeyRange || typeof query === "string" || query instanceof String))
|
||||
request = objectStore.index(indexes).getAll(query);
|
||||
else
|
||||
request = objectStore.index(indexes).getAll();
|
||||
else
|
||||
if (query
|
||||
&& (typeof query === "IDBKeyRange" || query instanceof IDBKeyRange || typeof query === "string" || query instanceof String))
|
||||
request = objectStore.getAll(query);
|
||||
else
|
||||
request = objectStore.getAll()
|
||||
request.onsuccess = function () {
|
||||
if (request.result !== undefined) {
|
||||
objects = request.result;
|
||||
resolve(objects);
|
||||
}
|
||||
else {
|
||||
console.log("no objects found: ", objectName);
|
||||
reject("no objects found: ", objectName);
|
||||
}
|
||||
};
|
||||
request.onerror = function (error) {
|
||||
console.log("Error getting objects(", objectName, ") from db: ", error);
|
||||
reject(error);
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
getObjectsCustom: function (objectName, query, indexes, predicateBlock) {
|
||||
let currentDB = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentDB.runTransactionReadOnly(objectName, function (transaction) {
|
||||
const objectStore = transaction.objectStore(objectName);
|
||||
let request = {};
|
||||
if (indexes && ((typeof indexes === "string" || indexes instanceof String) == false || indexes.length > 0))
|
||||
request = (query && ((typeof query === "string" || query instanceof String) == false || query.length > 0) ? objectStore.index(indexes).getAll(query) : objectStore.index(indexes).getAll());
|
||||
else
|
||||
request = (query && ((typeof query === "string" || query instanceof String) == false || query.length > 0) ? objectStore.getAll(query) : objectStore.getAll());
|
||||
|
||||
request.onsuccess = function () {
|
||||
if (request.result !== undefined) {
|
||||
let objectsUnfiltered = request.result;
|
||||
let objects = [];
|
||||
for (ix in objectsUnfiltered) {
|
||||
if (!predicateBlock || predicateBlock(objectsUnfiltered[ix])) {
|
||||
objects.push(objectsUnfiltered[ix]);
|
||||
}
|
||||
}
|
||||
resolve(objects);
|
||||
}
|
||||
else {
|
||||
console.log("no objects found: ", objectName);
|
||||
reject("no objects found: ", objectName);
|
||||
}
|
||||
};
|
||||
request.onerror = function (error) {
|
||||
console.log("Error getting objects(", objectName, ") from db: ", error);
|
||||
reject(error);
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
deleteAllObjects: function () {
|
||||
let currentDB = this;
|
||||
var error = null;
|
||||
var objectNames = INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE;
|
||||
return this.runTransactionReadWrite(objectNames, async function (transaction) {
|
||||
const logStore = transaction.objectStore(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE);
|
||||
try {
|
||||
await logStore.clear();
|
||||
}
|
||||
catch (error2) {
|
||||
error = error2;
|
||||
}
|
||||
return transaction.complete;
|
||||
});
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//ADD NON-GENERIC METHODS
|
||||
$.extend($.usaHaulersLoggingDB, {
|
||||
newGuid: function () {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
const r = Math.random() * 16 | 0,
|
||||
v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
},
|
||||
createLogObjectInternal: function (id, level, msg, args, date) {
|
||||
return {
|
||||
id: (id == null ? this.newGuid() : id),
|
||||
version: '1.0',
|
||||
url: window.location.href,
|
||||
application_code: $.cookie('lg_application_code'),
|
||||
application_user_id: $.cookie('lg_application_user_id'),
|
||||
environment_code: $.cookie('lg_environment_code'),
|
||||
level: level,
|
||||
msg: msg,
|
||||
arguments: args,
|
||||
date: (date == null ? new Date() : date),
|
||||
time: (date == null ? new Date() : date).toISOString(),
|
||||
uploaded: false,
|
||||
upload_status: 'Not Uploaded',
|
||||
upload_date: null
|
||||
}
|
||||
},
|
||||
createLogObject: function (level, msg, args) {
|
||||
return this.createLogObjectInternal(null, level, msg, args, null);
|
||||
},
|
||||
addLog: async function (level, msg, args) {
|
||||
let currentDB = this;
|
||||
|
||||
args = currentDB.removeObjectMethodsForSerialization(args);
|
||||
try {
|
||||
await currentDB.refreshConfigObject();
|
||||
var error = null;
|
||||
var log = currentDB.createLogObject(level, msg, args);
|
||||
return this.runTransactionReadWrite(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, async function (transaction) {
|
||||
const logStore = transaction.objectStore(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE);
|
||||
logStore.put(log);
|
||||
return transaction.complete;
|
||||
}).then(
|
||||
function () {
|
||||
},
|
||||
function (errorInternal) {
|
||||
error = errorInternal;
|
||||
}
|
||||
);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
deleteLogs: async function (logs) {
|
||||
let currentDB = this;
|
||||
|
||||
try {
|
||||
await currentDB.refreshConfigObject();
|
||||
var error = null;
|
||||
return this.runTransactionReadWrite(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, async function (transaction) {
|
||||
const logStore = transaction.objectStore(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE);
|
||||
|
||||
logs.forEach((log) => {
|
||||
logStore.delete(log.id);
|
||||
});
|
||||
return transaction.complete;
|
||||
}).then(
|
||||
function () {
|
||||
},
|
||||
function (errorInternal) {
|
||||
error = errorInternal;
|
||||
}
|
||||
);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
getLogsByLevel: async function (level, startDate, endDate) {
|
||||
let currentDB = this;
|
||||
let levelText = "";
|
||||
if (level != undefined && level != null)
|
||||
levelText = level.toUpperCase();
|
||||
|
||||
let query = levelText;
|
||||
|
||||
let indexes = INTERNAL_USAHAULERSLOGGING_LOG_INDEX_LEVEL;
|
||||
let logs = await currentDB.getObjects(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, query, indexes);
|
||||
let logs2 = [];
|
||||
logs.forEach((log) => {
|
||||
if ((startDate == null || log.date >= startDate) && (endDate == null || log.date <= endDate))
|
||||
logs2.push(log);
|
||||
});
|
||||
|
||||
logs2.sort(function (l1, l2) {
|
||||
return l1.date - l2.date;
|
||||
});
|
||||
|
||||
return logs2;
|
||||
},
|
||||
getLogsAll: async function (startDate, endDate) {
|
||||
let currentDB = this;
|
||||
let query = "";
|
||||
let logs = await currentDB.getObjects(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, query);
|
||||
let logs2 = [];
|
||||
logs.forEach((log) => {
|
||||
if ((startDate == null || log.date >= startDate) && (endDate == null || log.date <= endDate))
|
||||
logs2.push(log);
|
||||
});
|
||||
|
||||
logs2.sort(function (l1, l2) {
|
||||
return l1.date - l2.date;
|
||||
});
|
||||
|
||||
return logs2;
|
||||
},
|
||||
getLogsByUploaded: async function (uploaded, startDate, endDate) {
|
||||
let currentDB = this;
|
||||
let query = uploaded ? "Uploaded" : "Not Uploaded";
|
||||
|
||||
let indexes = INTERNAL_USAHAULERSLOGGING_LOG_INDEX_UPLOADED;
|
||||
let logs = await currentDB.getObjects(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, query, indexes);
|
||||
let logs2 = [];
|
||||
logs.forEach((log) => {
|
||||
if ((startDate == null || log.date >= startDate) && (endDate == null || log.date <= endDate))
|
||||
logs2.push(log);
|
||||
});
|
||||
|
||||
logs2.sort(function (l1, l2) {
|
||||
return l1.date - l2.date;
|
||||
});
|
||||
|
||||
return logs2;
|
||||
},
|
||||
getLogsByUploadStatus: async function (uploadStatus, startDate, endDate) {
|
||||
let currentDB = this;
|
||||
let query = uploadStatus
|
||||
|
||||
let indexes = INTERNAL_USAHAULERSLOGGING_LOG_INDEX_UPLOADED;
|
||||
let logs = await currentDB.getObjects(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, query, indexes);
|
||||
let logs2 = [];
|
||||
logs.forEach((log) => {
|
||||
if ((startDate == null || log.date >= startDate) && (endDate == null || log.date <= endDate))
|
||||
logs2.push(log);
|
||||
});
|
||||
|
||||
logs2.sort(function (l1, l2) {
|
||||
return l1.date - l2.date;
|
||||
});
|
||||
|
||||
return logs2;
|
||||
},
|
||||
markLogsUploaded: async function (logs) {
|
||||
let currentDB = this;
|
||||
|
||||
try {
|
||||
await currentDB.refreshConfigObject();
|
||||
var error = null;
|
||||
|
||||
logs.forEach((log) => {
|
||||
log.uploaded = true;
|
||||
log.upload_status = "Uploaded";
|
||||
log.upload_date = new Date();
|
||||
});
|
||||
return this.runTransactionReadWrite(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE, async function (transaction) {
|
||||
const logStore = transaction.objectStore(INTERNAL_USAHAULERSLOGGING_LOG_OBJECT_STORE);
|
||||
logs.forEach((log) => {
|
||||
logStore.put(log);
|
||||
});
|
||||
return transaction.complete;
|
||||
}).then(
|
||||
function () {
|
||||
},
|
||||
function (errorInternal) {
|
||||
error = errorInternal;
|
||||
}
|
||||
);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
//throw error;
|
||||
}
|
||||
|
||||
},
|
||||
uploadLogs: async function () {
|
||||
var currentDB = this;
|
||||
try {
|
||||
await currentDB.refreshConfigObject();
|
||||
var logs = null;
|
||||
var maxUploadQty = INTERNAL_USAHAULERSLOGGING_MAXUPLOADQTY;
|
||||
if (maxUploadQty <= 0)
|
||||
maxUploadQty = 999999;
|
||||
|
||||
do {
|
||||
logs = await currentDB.getLogsByUploaded(false, maxUploadQty);
|
||||
if (logs != null && logs.length > 0) {
|
||||
var success = false;
|
||||
|
||||
//try {
|
||||
success = await currentDB.uploadLogChunk(logs);
|
||||
//}
|
||||
//catch {
|
||||
// throw;
|
||||
//}
|
||||
if (!success) {
|
||||
console.debug("currentDB.uploadLogChunk returned false");
|
||||
return false;
|
||||
}
|
||||
//await currentDB.markLogsUploaded(logs);
|
||||
await currentDB.deleteLogs(logs);
|
||||
if (logs.length < maxUploadQty)
|
||||
break;
|
||||
}
|
||||
} while (logs != null && logs.length > 0);
|
||||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
if (!(error instanceof Error))
|
||||
console.error(JSON.stringify(error));
|
||||
else
|
||||
console.error(error);
|
||||
return false;
|
||||
//throw error;
|
||||
}
|
||||
},
|
||||
getLogURL: function () {
|
||||
var environmentCode = $.cookie('lg_environment_code');
|
||||
if (environmentCode === null || environmentCode.trim().length == 0)
|
||||
environmentCode = "DEFAULT";
|
||||
|
||||
environmentCode = environmentCode.toUpperCase();
|
||||
var logUrl = INTERNAL_LOG_URLS[environmentCode];
|
||||
if (logUrl === null || logUrl.trim().length == 0)
|
||||
logUrl = INTERNAL_LOG_URLS['DEFAULT'];
|
||||
return logUrl;
|
||||
},
|
||||
uploadLogChunk: async function (logs) {
|
||||
var currentDB = this;
|
||||
|
||||
var success = false;
|
||||
await $.ajax({
|
||||
type: "POST",
|
||||
url: currentDB.getLogURL(),
|
||||
data: JSON.stringify({ "jsonData": JSON.stringify(logs) }),
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
dataType: 'json',
|
||||
async: true,
|
||||
cache: false,
|
||||
timeout: 30000,
|
||||
disable_auth_token:true,
|
||||
headers: {
|
||||
lg_session_id: $.cookie('lg_session_guid'),
|
||||
lg_access_token: $.cookie('lg_access_token')
|
||||
},
|
||||
success: function (value, textStatus, request) {
|
||||
var json = value.hasOwnProperty("d") ? $.parseJSON(value.d) : $.parseJSON(value);
|
||||
if (currentDB.getBoolean(json.success)) {
|
||||
success = true;
|
||||
return true;
|
||||
}
|
||||
success = false;
|
||||
return false;
|
||||
},
|
||||
error: function (xhr, error, errorThrown) {
|
||||
//if ((error instanceof jqXHR)
|
||||
// console.error(JSON.stringify(error));
|
||||
//else if (!(error instanceof Error))
|
||||
// console.error(JSON.stringify(error));
|
||||
//else
|
||||
// console.error(error);
|
||||
success = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return success;
|
||||
}
|
||||
});
|
||||
|
||||
//TODO: Decide what to do here. This PROBABLY should be a method call that the UI calls on page load, otherwise some calls could happen before this is done/ready. Can't put await on this method, jquery .ready queue will not wait correctly.
|
||||
$(document).ready(function () {
|
||||
$.usaHaulersLoggingDB.open().then(() => {
|
||||
console.log("$.usaHaulersLoggingDB.open() success");
|
||||
return $.usaHaulersLoggingDB.initializeDB();
|
||||
})
|
||||
.then(() => {
|
||||
console.log("$.usaHaulersLoggingDB.initializeDB() success");
|
||||
return $.usaHaulersLoggingDB.uploadLogs();
|
||||
},
|
||||
(error) => {
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ajaxSend(function (event, xhr, settings) {
|
||||
if (settings.disable_auth_token) {
|
||||
xhr.setRequestHeader('Auth-Token', null);
|
||||
xhr.setRequestHeader('Auth-Impersonate-Guid', null);
|
||||
xhr.setRequestHeader('Auth-Current-Franchise', null);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,342 @@
|
||||
//iMove utility functions
|
||||
|
||||
|
||||
//ie is the version of IE running.
|
||||
var ie = (function () {
|
||||
|
||||
var undef,
|
||||
v = 3,
|
||||
div = document.createElement('div'),
|
||||
all = div.getElementsByTagName('i');
|
||||
|
||||
while (
|
||||
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
|
||||
all[0]
|
||||
);
|
||||
|
||||
return v > 4 ? v : undef;
|
||||
|
||||
} ());
|
||||
|
||||
$(document).ajaxSend(function (event, xhr, settings) {
|
||||
var authToken = $.cookie('Auth-Token');
|
||||
if (authToken != null && authToken != undefined && authToken.trim().length > 0) {
|
||||
xhr.setRequestHeader('Auth-Token', authToken);
|
||||
}
|
||||
|
||||
var impersonateGuid = $.getParameterByName("impersonateid");
|
||||
if (impersonateGuid != null && impersonateGuid != undefined && impersonateGuid.trim().length > 0) {
|
||||
$.sessionStorage('Auth-Impersonate-Guid', impersonateGuid);
|
||||
}
|
||||
|
||||
impersonateGuid = $.sessionStorage('Auth-Impersonate-Guid');
|
||||
if (impersonateGuid != null && impersonateGuid != undefined && impersonateGuid.trim().length > 0) {
|
||||
xhr.setRequestHeader('Auth-Impersonate-Guid', impersonateGuid);
|
||||
}
|
||||
|
||||
var franchiseCode = $.sessionStorage('franchiseCode');
|
||||
if (franchiseCode != null && franchiseCode != undefined && franchiseCode.trim().length > 0) {
|
||||
xhr.setRequestHeader('Auth-Current-Franchise', franchiseCode);
|
||||
}
|
||||
});
|
||||
|
||||
$.webMethod = function (options) {
|
||||
var settings = $.extend({
|
||||
'protocol': location.protocol, //http or https
|
||||
'methodPage': '', //This should be something like UserMethods
|
||||
'methodName': '', //Something like Createuser
|
||||
'contentType': 'application/json; charset=utf-8',
|
||||
'dataType': 'json',
|
||||
'async': true,
|
||||
'cache': false,
|
||||
timeout: 300000,
|
||||
'parameters': {},
|
||||
success: function (response) { },
|
||||
error: function (xhr, error, error_thrown) { }
|
||||
}, options);
|
||||
|
||||
if (settings.protocol.indexOf(':') < 0) {
|
||||
settings.protocol = settings.protocol + ':';
|
||||
}
|
||||
|
||||
var result;
|
||||
var baseUrl = window.API_BASE_URL;
|
||||
//var baseUrl = $("base").attr("href");
|
||||
if (baseUrl === undefined || baseUrl === null || baseUrl.length === 0)
|
||||
baseUrl = "";
|
||||
if (baseUrl.length > 0 && baseUrl[baseUrl.length - 1] !== "/")
|
||||
baseUrl = baseUrl + "/";
|
||||
var url = baseUrl + settings.methodPage + (settings.methodName === undefined || settings.methodName === null || settings.methodName.length === 0 ? "" : "/" + settings.methodName);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: JSON.stringify(settings.parameters),
|
||||
contentType: settings.contentType,
|
||||
dataType: settings.dataType,
|
||||
async: settings.async,
|
||||
cache: settings.cache,
|
||||
timeout: settings.timeout,
|
||||
beforeSend: null,
|
||||
success: function (value, textStatus, request) {
|
||||
if (value.hasOwnProperty("d"))
|
||||
result = $.parseJSON(value.d);
|
||||
else if (typeof value === 'object')
|
||||
result = value;
|
||||
else
|
||||
result = $.parseJSON(value);
|
||||
var authToken = request.getResponseHeader('Auth-Token');
|
||||
var loggedIn = $.getBoolean(request.getResponseHeader('usahl_logged_in'));
|
||||
$.cookie.raw = true;
|
||||
|
||||
if ($.getRememberMe() === true) {
|
||||
$.cookie('Auth-Token', authToken, { expires: 14, path: '/' });
|
||||
$.cookie('usahl_logged_in', loggedIn, { expires: 14, path: '/' });
|
||||
}
|
||||
else {
|
||||
$.cookie('Auth-Token', authToken, { expires: 365, path: '/' });
|
||||
$.cookie('usahl_logged_in', loggedIn, { expires: 365, path: '/' });
|
||||
}
|
||||
if (settings.success !== undefined)
|
||||
settings.success(result);
|
||||
},
|
||||
error: function (xhr, error, errorThrown) {
|
||||
if (settings.error !== undefined)
|
||||
settings.error(xhr, error, errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$.webMethodAsync = async function (options) {
|
||||
var settings = $.extend({
|
||||
'protocol': location.protocol, //http or https
|
||||
'methodPage': '', //This should be something like UserMethods.
|
||||
'methodName': '', //Something like Createuser
|
||||
'contentType': 'application/json; charset=utf-8',
|
||||
'dataType': 'json',
|
||||
'async': true,
|
||||
'cache': false,
|
||||
timeout: 300000,
|
||||
'parameters': {},
|
||||
success: function (response) { },
|
||||
error: function (xhr, error, error_thrown) { }
|
||||
}, options);
|
||||
|
||||
if (settings.protocol.indexOf(':') < 0) {
|
||||
settings.protocol = settings.protocol + ':';
|
||||
}
|
||||
|
||||
var result;
|
||||
var baseUrl = window.API_BASE_URL;
|
||||
//var baseUrl = $("base").attr("href");
|
||||
if (baseUrl === undefined || baseUrl === null || baseUrl.length === 0)
|
||||
baseUrl = "";
|
||||
if (baseUrl.length > 0 && baseUrl[baseUrl.length - 1] !== "/")
|
||||
baseUrl = baseUrl + "/";
|
||||
var url = baseUrl + settings.methodPage + (settings.methodName === undefined || settings.methodName === null || settings.methodName.length === 0 ? "" : "/" + settings.methodName);
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: JSON.stringify(settings.parameters),
|
||||
contentType: settings.contentType,
|
||||
dataType: settings.dataType,
|
||||
async: settings.async,
|
||||
cache: settings.cache,
|
||||
timeout: settings.timeout,
|
||||
beforeSend: null,
|
||||
success: function (value, textStatus, request) {
|
||||
if (value.hasOwnProperty("d"))
|
||||
result = $.parseJSON(value.d);
|
||||
else if (typeof value === 'object')
|
||||
result = value;
|
||||
else
|
||||
result = $.parseJSON(value);
|
||||
var authToken = request.getResponseHeader('Auth-Token');
|
||||
var loggedIn = $.getBoolean(request.getResponseHeader('usahl_logged_in'));
|
||||
$.cookie.raw = true;
|
||||
|
||||
if ($.getRememberMe() === true) {
|
||||
$.cookie('Auth-Token', authToken, { expires: 14, path: '/' });
|
||||
$.cookie('usahl_logged_in', loggedIn, { expires: 14, path: '/' });
|
||||
}
|
||||
else {
|
||||
$.cookie('Auth-Token', authToken, { expires: 365, path: '/' });
|
||||
$.cookie('usahl_logged_in', loggedIn, { expires: 365, path: '/' });
|
||||
}
|
||||
if (settings.success !== undefined)
|
||||
settings.success(result);
|
||||
},
|
||||
error: function (xhr, error, errorThrown) {
|
||||
if (settings.error !== undefined)
|
||||
settings.error(xhr, error, errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$.getBoolean = function (variable) {
|
||||
var vtype;
|
||||
var toReturn;
|
||||
|
||||
if (variable != null) {
|
||||
switch (typeof (variable)) {
|
||||
case 'boolean':
|
||||
vtype = "boolean";
|
||||
return variable;
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
vtype = "number";
|
||||
if (variable == 0)
|
||||
toReturn = false;
|
||||
else toReturn = true;
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
vtype = "string";
|
||||
if (variable.toLowerCase() == "true" || variable.toLowerCase() == "yes")
|
||||
toReturn = true;
|
||||
else if (variable.toLowerCase() == "false" || variable.toLowerCase() == "no")
|
||||
toReturn = false;
|
||||
else if (variable.length > 0)
|
||||
toReturn = true;
|
||||
else if (variable.length == 0)
|
||||
toReturn = false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
};
|
||||
|
||||
$.isLoggedIn = function () {
|
||||
return $.getBoolean($.cookie('usahl_logged_in'));
|
||||
}
|
||||
|
||||
//Send the auth-token in all ajax requests
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr, settings) {
|
||||
xhr.setRequestHeader('Auth-Token', $.cookie('Auth-Token'));
|
||||
}
|
||||
});
|
||||
|
||||
$.sessionStorage = function (key, value) {
|
||||
if (value === undefined) {
|
||||
var val = window.sessionStorage.getItem(key);
|
||||
if ((/^usahl_json/).test(val)) {
|
||||
val = val.substring(11, val.length);
|
||||
val = $.parseJSON(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
var val = value;
|
||||
if (typeof value === 'object') {
|
||||
val = "usahl_json:" + JSON.stringify(value);
|
||||
}
|
||||
|
||||
window.sessionStorage.setItem(key, val);
|
||||
}
|
||||
};
|
||||
|
||||
$.sessionStorageClear = function () {
|
||||
window.sessionStorage.clear();
|
||||
};
|
||||
|
||||
$.sessionStorageRemove = function (key) {
|
||||
window.sessionStorage.removeItem(key);
|
||||
};
|
||||
|
||||
$.localStorage = function (key, value) {
|
||||
if (value === undefined) {
|
||||
var val = window.localStorage.getItem(key);
|
||||
if ((/^usahl_json/).test(val)) {
|
||||
val = val.substring(11, val.length);
|
||||
val = $.parseJSON(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
var val = value;
|
||||
if (typeof value === 'object') {
|
||||
val = "usahl_json:" + JSON.stringify(value);
|
||||
}
|
||||
|
||||
window.localStorage.setItem(key, val);
|
||||
}
|
||||
};
|
||||
|
||||
$.localStorageClear = function () {
|
||||
window.localStorage.clear();
|
||||
};
|
||||
|
||||
$.localStorageRemove = function (key) {
|
||||
window.localStorage.removeItem(key);
|
||||
};
|
||||
|
||||
$.setRememberMe = function (rememberMe) {
|
||||
$.sessionStorage("usahl_remember_me", rememberMe);
|
||||
}
|
||||
$.getRememberMe = function () {
|
||||
return true;
|
||||
/*
|
||||
var rememberMe = $.sessionStorage("usahl_remember_me");
|
||||
if (rememberMe === undefined || rememberMe == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $.getBoolean(rememberMe);
|
||||
*/
|
||||
}
|
||||
|
||||
$.userHasPermission = function (permissionCode) {
|
||||
var allowed = false;
|
||||
var user = $.localStorage("session_currentUser");
|
||||
$.each(user.Permissions, function () {
|
||||
if ($.compareStrings(this.Code, permissionCode)) {
|
||||
allowed = true;
|
||||
}
|
||||
});
|
||||
return allowed;
|
||||
}
|
||||
|
||||
$.userHasRole = function (role) {
|
||||
var hasRole = false;
|
||||
var user = $.localStorage("session_currentUser");
|
||||
$.each(user.Roles, function () {
|
||||
if ($.compareStrings(this.FriendlyName, role)) {
|
||||
hasRole = true;
|
||||
}
|
||||
});
|
||||
return hasRole;
|
||||
}
|
||||
|
||||
$.checkForRole = function (user, role) {
|
||||
var hasRole = false;
|
||||
$.each(user.Roles, function () {
|
||||
if ($.compareStrings(this.FriendlyName, role)) {
|
||||
hasRole = true;
|
||||
}
|
||||
});
|
||||
return hasRole;
|
||||
}
|
||||
|
||||
$.checkForRoleCode = function (user, role) {
|
||||
var hasRole = false;
|
||||
$.each(user.roles, function () {
|
||||
if ($.compareStrings(this.role_code, role)) {
|
||||
hasRole = true;
|
||||
}
|
||||
});
|
||||
return hasRole;
|
||||
}
|
||||
|
||||
$.compareStrings = function (string1, string2) {
|
||||
return string1.toLowerCase() === string2.toLowerCase();
|
||||
}
|
||||
|
||||
$.getParameterByName = function (name) {
|
||||
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
||||
results = regex.exec(location.search);
|
||||
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
}
|
||||
@ -0,0 +1,404 @@
|
||||
|
||||
$.webauthn = {
|
||||
methodCodeRegister: "Register",
|
||||
methodCodeLogin: "Login",
|
||||
isSupported: function () {// Availability of `window.PublicKeyCredential` means webauthn is usable.
|
||||
if (window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
abortController: new AbortController(),
|
||||
getPublicKey: async function (method, type, username) {
|
||||
let jsonData = {};
|
||||
let error = null;
|
||||
await $.webMethodAsync({
|
||||
'methodPage': 'Webauthn/GetPublicKey',
|
||||
'parameters': { "method": method, "type": type, "username": username },
|
||||
success: function (json) {
|
||||
if (json.success === true || json.success === "true") {
|
||||
jsonData = json.data;
|
||||
}
|
||||
else {
|
||||
error = "success=false";
|
||||
}
|
||||
},
|
||||
error: function (errorInternal) {
|
||||
error = errorInternal;
|
||||
}
|
||||
});
|
||||
|
||||
if (error)
|
||||
throw error;////
|
||||
|
||||
return jsonData;
|
||||
},
|
||||
getPublicKeyForLogin: async function (username) {
|
||||
return $.webauthn.getPublicKey($.webauthn.methodCodeLogin, "Any", username);
|
||||
},
|
||||
authenticate: async function (publicKey) {
|
||||
if (!this.isSupported())
|
||||
throw new Error("webauthn is not supported");
|
||||
|
||||
var publicKeyMain = JSON.parse(JSON.stringify(publicKey));
|
||||
|
||||
if (publicKey.publicKey !== undefined) {
|
||||
publicKey = publicKey.publicKey;
|
||||
}
|
||||
var manager = this;
|
||||
|
||||
if (publicKey.challenge !== undefined)
|
||||
publicKey.challenge = $.webauthn.coerceToArrayBuffer(publicKey.challenge);
|
||||
|
||||
if (publicKey.user !== undefined && publicKey.user.id !== undefined)
|
||||
publicKey.user.id = $.webauthn.coerceToArrayBuffer(publicKey.user.id);
|
||||
|
||||
if (publicKey.excludeCredentials !== undefined && publicKey.excludeCredentials !== null) {
|
||||
for (var exKey of publicKey.excludeCredentials) {
|
||||
if (exKey.id !== undefined && exKey.id !== null)
|
||||
exKey.id = $.webauthn.coerceToArrayBuffer(exKey.id);
|
||||
}
|
||||
}
|
||||
if (publicKey.allowCredentials !== undefined && publicKey.allowCredentials !== null) {
|
||||
for (var allowCred of publicKey.allowCredentials) {
|
||||
if (allowCred.id !== undefined && allowCred.id !== null)
|
||||
allowCred.id = $.webauthn.coerceToArrayBuffer(allowCred.id);
|
||||
}
|
||||
}
|
||||
|
||||
var clientResponse;
|
||||
try {
|
||||
assertedCredential = await navigator.credentials.get({
|
||||
publicKey: publicKey,
|
||||
signal: $.webauthn.abortController.signal
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
showAlert("error", error);
|
||||
return null;
|
||||
}
|
||||
|
||||
let authData = new Uint8Array(assertedCredential.response.authenticatorData);
|
||||
let clientDataJSON = new Uint8Array(assertedCredential.response.clientDataJSON);
|
||||
let rawId = new Uint8Array(assertedCredential.rawId);
|
||||
let sig = new Uint8Array(assertedCredential.response.signature);
|
||||
const data = {
|
||||
id: assertedCredential.id,
|
||||
rawId: $.webauthn.coerceToBase64Url(rawId),
|
||||
type: assertedCredential.type,
|
||||
extensions: assertedCredential.getClientExtensionResults(),
|
||||
response: {
|
||||
authenticatorData: $.webauthn.coerceToBase64Url(authData),
|
||||
clientDataJSON: $.webauthn.coerceToBase64Url(clientDataJSON),
|
||||
signature: $.webauthn.coerceToBase64Url(sig)
|
||||
}
|
||||
};
|
||||
|
||||
return await $.webauthn.verifyKey(data);
|
||||
},
|
||||
saveKey: async function (type, publicKey, newKey) {
|
||||
let error = null;
|
||||
var outputJson = null;
|
||||
await $.webMethodAsync({
|
||||
'methodPage': 'Webauthn/SaveKey',
|
||||
'parameters': { "type": type, "publicKey": publicKey, "newKey": newKey },
|
||||
success: function (json) {
|
||||
if (json.success === true || json.success === "true") {
|
||||
outputJson = json;
|
||||
}
|
||||
else {
|
||||
error = "success=false";
|
||||
}
|
||||
},
|
||||
error: function (errorInternal) {
|
||||
error = errorInternal;
|
||||
}
|
||||
});
|
||||
|
||||
if (error)
|
||||
throw error;
|
||||
|
||||
return outputJson;
|
||||
},
|
||||
verifyKey: async function (clientResponse) {
|
||||
let error = null;
|
||||
var outputJson = null;
|
||||
await $.webMethodAsync({
|
||||
'methodPage': 'Webauthn/VerifyKey',
|
||||
'parameters': { "clientResponse": clientResponse },
|
||||
success: function (json) {
|
||||
if (json.success === true || json.success === "true") {
|
||||
outputJson = json;
|
||||
}
|
||||
else {
|
||||
error = "success=false";
|
||||
}
|
||||
},
|
||||
error: function (errorInternal) {
|
||||
error = errorInternal;
|
||||
}
|
||||
});
|
||||
|
||||
if (error)
|
||||
throw error;
|
||||
|
||||
return outputJson;
|
||||
},
|
||||
passkeys: {
|
||||
typeCode: "passkey",
|
||||
abortController: new AbortController(),
|
||||
isSupported: function () {
|
||||
if ($.webauthn.isSupported()) {
|
||||
return true;
|
||||
//// Check if conditional mediation is available.
|
||||
//const isCMA = await PublicKeyCredential.isConditionalMediationAvailable();
|
||||
//if (isCMA) {
|
||||
// return true;
|
||||
//}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getPublicKeyForRegister: async function (username) {
|
||||
return $.webauthn.getPublicKey($.webauthn.methodCodeRegister, this.typeCode, username);
|
||||
},
|
||||
getPublicKeyForLogin: async function (username) {
|
||||
return $.webauthn.getPublicKey($.webauthn.methodCodeLogin, this.typeCode, username);
|
||||
},
|
||||
authenticate: async function (publicKey) {
|
||||
if (!this.isSupported())
|
||||
throw new Error("webauthn/passkeys is not supported");
|
||||
|
||||
return $.webauthn.authenticate(publicKey);
|
||||
},
|
||||
create: async function (publicKey) {
|
||||
if (!this.isSupported())
|
||||
throw new Error("webauthn/passkeys is not supported");
|
||||
|
||||
var publicKeyMain = JSON.parse(JSON.stringify(publicKey));
|
||||
|
||||
if (publicKey.publicKey !== undefined) {
|
||||
publicKey = publicKey.publicKey;
|
||||
}
|
||||
var manager = this;
|
||||
|
||||
if (publicKey.challenge !== undefined)
|
||||
publicKey.challenge = $.webauthn.coerceToArrayBuffer(publicKey.challenge);
|
||||
|
||||
if (publicKey.user !== undefined && publicKey.user.id !== undefined)
|
||||
publicKey.user.id = $.webauthn.coerceToArrayBuffer(publicKey.user.id);
|
||||
|
||||
if (publicKey.excludeCredentials !== undefined && publicKey.excludeCredentials !== null) {
|
||||
for (var exKey of publicKey.excludeCredentials) {
|
||||
if (exKey.id !== undefined && exKey.id !== null)
|
||||
exKey.id = $.webauthn.coerceToArrayBuffer(exKey.id);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var credential = await navigator.credentials.create({
|
||||
publicKey: publicKey,
|
||||
signal: $.webauthn.abortController.signal
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
showAlert("error", error);
|
||||
return null;
|
||||
}
|
||||
|
||||
var credential2 = {
|
||||
authenticatorAttachment: credential.authenticatorAttachment,
|
||||
id: credential.id,
|
||||
rawId: $.webauthn.coerceToBase64Url(credential.rawId),
|
||||
type: credential.type,
|
||||
extensions: credential.getClientExtensionResults(),
|
||||
response: {
|
||||
attestationObject: $.webauthn.coerceToBase64Url(credential.response.attestationObject),
|
||||
clientDataJSON: $.webauthn.coerceToBase64Url(credential.response.clientDataJSON),
|
||||
transports: credential.response.getTransports()
|
||||
},
|
||||
type: credential.type
|
||||
}
|
||||
|
||||
var publicKey2 = JSON.parse(JSON.stringify(publicKey));
|
||||
publicKey2.user.id = publicKeyMain.publicKey.user.id;
|
||||
publicKey2.challenge = publicKeyMain.publicKey.challenge;
|
||||
var keySaved = await $.webauthn.saveKey(this.typeCode, publicKey2, credential2);
|
||||
|
||||
if ($.getBoolean(keySaved.success))
|
||||
showAlert("success", "Key created");
|
||||
else
|
||||
showAlert("error", "Key creation failed");
|
||||
}
|
||||
},
|
||||
securityKeys: {
|
||||
typeCode: "securitykey",
|
||||
abortController: new AbortController(),
|
||||
isSupported: function () {
|
||||
if ($.webauthn.isSupported()) {
|
||||
return true;
|
||||
//// Check if conditional mediation is available.
|
||||
//const isCMA = await PublicKeyCredential.isConditionalMediationAvailable();
|
||||
//if (isCMA) {
|
||||
// return true;
|
||||
//}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getPublicKeyForRegister: async function (username) {
|
||||
return $.webauthn.getPublicKey($.webauthn.methodCodeRegister, this.typeCode, username);
|
||||
},
|
||||
getPublicKeyForLogin: async function (username) {
|
||||
return $.webauthn.getPublicKey($.webauthn.methodCodeLogin, this.typeCode, username);
|
||||
},
|
||||
saveKey: async function (publicKey, newKey) {
|
||||
return $.webauthn.saveKey(this.typeCode, publicKey, newKey);
|
||||
},
|
||||
authenticate: async function (publicKey) {
|
||||
if (!this.isSupported())
|
||||
throw new Error("webauthn/securityKeys is not supported");
|
||||
|
||||
return $.webauthn.authenticate(publicKey);
|
||||
},
|
||||
create: async function (publicKey) {
|
||||
if (!this.isSupported())
|
||||
throw new Error("webauthn/securityKeys is not supported");
|
||||
|
||||
var publicKeyMain = JSON.parse(JSON.stringify(publicKey));
|
||||
|
||||
if (publicKey.publicKey !== undefined) {
|
||||
publicKey = publicKey.publicKey;
|
||||
}
|
||||
var manager = this;
|
||||
|
||||
if (publicKey.challenge !== undefined)
|
||||
publicKey.challenge = $.webauthn.coerceToArrayBuffer(publicKey.challenge);
|
||||
|
||||
if (publicKey.user !== undefined && publicKey.user.id !== undefined)
|
||||
publicKey.user.id = $.webauthn.coerceToArrayBuffer(publicKey.user.id);
|
||||
|
||||
if (publicKey.excludeCredentials !== undefined && publicKey.excludeCredentials !== null) {
|
||||
for (var exKey of publicKey.excludeCredentials) {
|
||||
if (exKey.id !== undefined && exKey.id !== null)
|
||||
exKey.id = $.webauthn.coerceToArrayBuffer(exKey.id);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var credential = await navigator.credentials.create({
|
||||
publicKey: publicKey,
|
||||
signal: $.webauthn.abortController.signal
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
showAlert("error", error);
|
||||
return null;
|
||||
}
|
||||
|
||||
var credential2 = {
|
||||
authenticatorAttachment: credential.authenticatorAttachment,
|
||||
id: credential.id,
|
||||
rawId: $.webauthn.coerceToBase64Url(credential.rawId),
|
||||
type: credential.type,
|
||||
extensions: credential.getClientExtensionResults(),
|
||||
response: {
|
||||
attestationObject: $.webauthn.coerceToBase64Url(credential.response.attestationObject),
|
||||
clientDataJSON: $.webauthn.coerceToBase64Url(credential.response.clientDataJSON),
|
||||
transports: credential.response.getTransports()
|
||||
},
|
||||
type: credential.type
|
||||
}
|
||||
|
||||
var publicKey2 = JSON.parse(JSON.stringify(publicKey));
|
||||
publicKey2.user.id = publicKeyMain.publicKey.user.id;
|
||||
publicKey2.challenge = publicKeyMain.publicKey.challenge;
|
||||
var keySaved = await $.webauthn.saveKey(this.typeCode, publicKey2, credential2);
|
||||
|
||||
if ($.getBoolean(keySaved.success))
|
||||
showAlert("success", "Key created");
|
||||
else
|
||||
showAlert("error", "Key creation failed");
|
||||
}
|
||||
},
|
||||
stringToArrayBuffer: function (string) {
|
||||
var string2 = (typeof string !== "string" ? string.toString() : string);
|
||||
return Uint8Array.from(string2, c => c.charCodeAt(0));
|
||||
},
|
||||
arrayBufferToString: function (buffer) {
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buffer));
|
||||
},
|
||||
arrayBufferToBase64String: function (buffer) {
|
||||
return window.btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)));
|
||||
},
|
||||
coerceToArrayBuffer: function (thing, name) {
|
||||
if (thing === undefined || thing === null)
|
||||
return null;
|
||||
|
||||
if (typeof thing === "string") {
|
||||
// base64url to base64
|
||||
thing = thing.replace(/-/g, "+").replace(/_/g, "/");
|
||||
|
||||
// base64 to Uint8Array
|
||||
var str = window.atob(thing);
|
||||
var bytes = new Uint8Array(str.length);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
bytes[i] = str.charCodeAt(i);
|
||||
}
|
||||
thing = bytes;
|
||||
}
|
||||
|
||||
// Array to Uint8Array
|
||||
if (Array.isArray(thing)) {
|
||||
thing = new Uint8Array(thing);
|
||||
}
|
||||
|
||||
// Uint8Array to ArrayBuffer
|
||||
if (thing instanceof Uint8Array) {
|
||||
thing = thing.buffer;
|
||||
}
|
||||
|
||||
// error if none of the above worked
|
||||
if (!(thing instanceof ArrayBuffer)) {
|
||||
throw new TypeError("could not coerce '" + name + "' to ArrayBuffer");
|
||||
}
|
||||
|
||||
return thing;
|
||||
},
|
||||
|
||||
coerceToBase64Url: function (thing) {
|
||||
if (thing === undefined || thing === null)
|
||||
return null;
|
||||
|
||||
// Array or ArrayBuffer to Uint8Array
|
||||
if (Array.isArray(thing)) {
|
||||
thing = Uint8Array.from(thing);
|
||||
}
|
||||
|
||||
if (thing instanceof ArrayBuffer) {
|
||||
thing = new Uint8Array(thing);
|
||||
}
|
||||
|
||||
// Uint8Array to base64
|
||||
if (thing instanceof Uint8Array) {
|
||||
var str = "";
|
||||
var len = thing.byteLength;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
str += String.fromCharCode(thing[i]);
|
||||
}
|
||||
thing = window.btoa(str);
|
||||
}
|
||||
|
||||
if (typeof thing !== "string") {
|
||||
throw new Error("could not coerce to string");
|
||||
}
|
||||
|
||||
// base64 to base64url
|
||||
// NOTE: "=" at the end of challenge is optional, strip it off here
|
||||
//thing = thing.replace(/\+/g, "-").replace(/\//g, "_").replace(/=*$/g, "");
|
||||
|
||||
return thing;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
|
||||
|
||||
async function CheckAuthToken() {
|
||||
|
||||
var data = null;
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
callMethod("CheckAuthToken", {}).then((data) => {
|
||||
//return the first element in the array for this call.
|
||||
resolve(data[0]);
|
||||
}).catch((data) => {
|
||||
reject(data);
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function GetVehicles() {
|
||||
var data = null;
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
callMethod("GetVehicles", {}).then((data) => {
|
||||
//return the first element in the array for this call.
|
||||
resolve(data);
|
||||
}).catch((data) => {
|
||||
reject(data);
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function SaveVehicle(vehicleId, vehicleData)
|
||||
{
|
||||
var data = null;
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
callMethod("SaveVehicle", {"vehicleId":vehicleId, "jsonData": JSON.stringify(vehicle) }).then((data) => {
|
||||
//return the first element in the array for this call.
|
||||
resolve(data);
|
||||
}).catch((data) => {
|
||||
reject(data);
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function GetVehicleImages(vehicleID) {
|
||||
var data = null;
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
callMethod("GetVehicleImages", { "vehicleID": vehicleID }).then((data) => {
|
||||
//return the first element in the array for this call.
|
||||
resolve(data);
|
||||
}).catch((data) => {
|
||||
reject(data);
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function SaveCurrentUser() {
|
||||
|
||||
user = currentUser;
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
callMethod("SaveUser", { "userJson": JSON.stringify(user) }).then((data) => {
|
||||
resolve(data);
|
||||
}).catch((data) => {
|
||||
reject(data);
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function ServerHealthCheck() {
|
||||
return new Promise((resolve, reject) => {
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods/',
|
||||
'methodName': "ServerHealthCheck",
|
||||
'parameters': {},
|
||||
'timeout': 3000,
|
||||
success: function (json) {
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
|
||||
data = json;
|
||||
resolve(data);
|
||||
}
|
||||
else {
|
||||
data = json;
|
||||
reject(data);
|
||||
}
|
||||
},
|
||||
error: function (data) {
|
||||
reject(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function callMethod(methodName, parameters) {
|
||||
return new Promise((resolve, reject) => {
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods',
|
||||
'methodName': methodName,
|
||||
'parameters': parameters,
|
||||
'timeout': 60000,
|
||||
success: function (json) {
|
||||
|
||||
if (json.data != null) {
|
||||
data = json.data;
|
||||
}
|
||||
else {
|
||||
data = json;
|
||||
}
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
resolve(data);
|
||||
}
|
||||
else {
|
||||
reject(data);
|
||||
}
|
||||
},
|
||||
error: function (data) {
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import './App.css';
|
||||
|
||||
interface Forecast {
|
||||
date: string;
|
||||
temperatureC: number;
|
||||
temperatureF: number;
|
||||
summary: string;
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [forecasts, setForecasts] = useState<Forecast[]>();
|
||||
|
||||
useEffect(() => {
|
||||
populateWeatherData();
|
||||
}, []);
|
||||
|
||||
const contents = forecasts === undefined
|
||||
? <p><em>Loading... Please refresh once the ASP.NET backend has started. See <a href="https://aka.ms/jspsintegrationreact">https://aka.ms/jspsintegrationreact</a> for more details.</em></p>
|
||||
: <table className="table table-striped" aria-labelledby="tableLabel">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{forecasts.map(forecast =>
|
||||
<tr key={forecast.date}>
|
||||
<td>{forecast.date}</td>
|
||||
<td>{forecast.temperatureC}</td>
|
||||
<td>{forecast.temperatureF}</td>
|
||||
<td>{forecast.summary}</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 id="tableLabel">Weather forecast</h1>
|
||||
<p>This component demonstrates fetching data from the server.</p>
|
||||
{contents}
|
||||
</div>
|
||||
);
|
||||
|
||||
async function populateWeatherData() {
|
||||
const response = await fetch('weatherforecast');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setForecasts(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
120
surge365.massemailreact.client/src/components/layouts/Layout.tsx
Normal file
120
surge365.massemailreact.client/src/components/layouts/Layout.tsx
Normal file
@ -0,0 +1,120 @@
|
||||
import { ReactNode } from 'react';
|
||||
//import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'admin-lte/dist/css/adminlte.min.css';
|
||||
import 'font-awesome/css/font-awesome.min.css';
|
||||
/*import 'ionicons/dist/css/ionicons.min.css';*/
|
||||
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js'; // Bootstrap JS
|
||||
import 'admin-lte/dist/js/adminlte.min.js';
|
||||
|
||||
const Layout = function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<div className="wrapper" style={{ overflow: 'initial' }}>
|
||||
<link rel="stylesheet" href="/content/dist/css/skins/_all-skins.min.css" />
|
||||
<link href="/content/plugins/datepicker/v4/bootstrap-datetimepicker.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/content/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css" />
|
||||
<link rel="stylesheet" href="/content/plugins/datatables/dataTables.bootstrap.css" />
|
||||
|
||||
{/*<script src="/content/dist/js/app.min.js"></script>AdminLTE?*/}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.min.js"></script>
|
||||
{/*<script src="/content/plugins/datatables/jquery.dataTables.min.js"></script>*/}
|
||||
{/*<script src="/content/plugins/validator/validator.js"></script>*/}
|
||||
<script src="/content/js/jquery.surge365.utilities-1.0.js" />
|
||||
<script src="/content/js/jquery.surge365.global.js?36"></script>
|
||||
<script src="/content/js/jquery.surge365.webmethods-1.0.js?15"></script>
|
||||
<script src="/content/js/Main-1.0.js?39"></script>
|
||||
{/*<script src="/content/plugins/growl/jquery.bootstrap-growl.min.js"></script>*/}
|
||||
{/*<script src="/content/plugins/input-mask-5/jquery.inputmask.js"></script>*/}
|
||||
{/*<script src="/content/plugins/printThis/printThis.js"></script>*/}
|
||||
{/*<script src="/content/plugins/datatables/dataTables.bootstrap.min.js"></script>*/}
|
||||
<header className="main-header">
|
||||
<a href="Dashboard" className="logo" style={{ backgroundColor: '#333' }}>
|
||||
<span className="logo-mini" style={{ backgroundColor: '#333' }}>
|
||||
<img id="imgLogo-sm" src="/content/img/imove_mini_logo.png" style={{ height: '35px', marginBottom: '3px' }} alt="Logo" className="hide" />
|
||||
</span>
|
||||
<span className="logo-lg" style={{ textAlign: 'center', backgroundColor: '#333' }}>
|
||||
<img id="imgLogo-lg" src="/content/img/imove_mini_logo.png" style={{ height: '35px', marginBottom: '3px' }} alt="Logo" className="hide" />
|
||||
<span style={{ marginLeft: '5px', verticalAlign: 'middle' }}><b>USA</b>Haulers</span>
|
||||
</span>
|
||||
</a>
|
||||
<nav className="navbar navbar-static-top">
|
||||
<a href="#" className="fa5 sidebar-toggle" data-toggle="offcanvas" role="button">
|
||||
<span className="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<div className="navbar-custom-menu">
|
||||
<ul className="nav navbar-nav">
|
||||
<li className="dropdown user user-menu">
|
||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown">
|
||||
<span id="spanSpinner" className="fa fa-sync-alt pull-left" style={{ lineHeight: 'unset', display: 'none', fontSize: '16pt', fontWeight: 'bold', marginRight: '10px' }}></span>
|
||||
<img id="imgRightProfile" src="/content/img/generic_avatar.jpg" className="user-image" alt="User Image" />
|
||||
<span id="spanProfileName"></span>
|
||||
</a>
|
||||
<ul className="dropdown-menu">
|
||||
<li className="user-header">
|
||||
<img id="imgMainProfile" src="" className="img-circle" alt="User Image" />
|
||||
<p>
|
||||
<span id="spanProfileNameTitle"></span>
|
||||
</p>
|
||||
</li>
|
||||
<li className="user-footer">
|
||||
<div className="pull-left">
|
||||
<a href="Profile" className="btn btn-default btn-flat">Profile</a>
|
||||
</div>
|
||||
<div className="pull-right">
|
||||
<input type="button" id="btnSignOut" className="btn btn-primary" value="Sign Out" />
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<aside className="main-sidebar">
|
||||
<section className="sidebar">
|
||||
<div className="user-panel">
|
||||
<div className="pull-left image">
|
||||
<img id="imgLeftProfile" src="/content/img/generic_avatar.jpg" className="img-circle" alt="User Image" />
|
||||
</div>
|
||||
<div className="pull-left info" style={{ lineHeight: 3 }}>
|
||||
<p><span id="spanMenuName"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="sidebar-menu">
|
||||
<li className="header">MAIN NAVIGATION</li>
|
||||
<li id="liDashboard" className="active treeview">
|
||||
<a href="Dashboard">
|
||||
<i className="fa fa-home"></i><span>Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className="treeview">
|
||||
<a href="#" id="aSignOut">
|
||||
<i className="fa fa-times-circle"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
{children}
|
||||
|
||||
<footer className="main-footer" style={{ padding: '2px' }}>
|
||||
<div className="pull-right hidden-xs">
|
||||
<b>Version</b> 1.0.0
|
||||
</div>
|
||||
<strong>Copyright © 2024 <a href="https://www.surge365.com">Surge365</a>.</strong> All rights reserved.
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Layout.propTypes = {
|
||||
children: PropTypes.any
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
@ -0,0 +1,29 @@
|
||||
import { ReactNode } from 'react';
|
||||
//import { useEffect } from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'admin-lte/dist/css/adminlte.min.css';
|
||||
import 'font-awesome/css/font-awesome.min.css';
|
||||
/*import 'ionicons/dist/css/ionicons.min.css';*/
|
||||
|
||||
import '@/css/adminlte-custom.css';
|
||||
import '@/css/surge365.css';
|
||||
|
||||
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js'; // Bootstrap JS
|
||||
import 'admin-lte/dist/js/adminlte.min.js';
|
||||
import 'admin-lte/dist/js/adminlte.min.js';
|
||||
|
||||
|
||||
|
||||
const LayoutLogin = function LayoutLogin({ children }: { children: ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
|
||||
LayoutLogin.propTypes = {
|
||||
children: PropTypes.any
|
||||
};
|
||||
|
||||
export default LayoutLogin;
|
||||
@ -0,0 +1,37 @@
|
||||
import { ReactNode } from 'react';
|
||||
//import { useEffect } from 'react';
|
||||
import { Helmet, HelmetProvider } from 'react-helmet-async';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'admin-lte/dist/css/adminlte.min.css';
|
||||
import 'font-awesome/css/font-awesome.min.css';
|
||||
/*import 'ionicons/dist/css/ionicons.min.css';*/
|
||||
|
||||
import '@/css/adminlte-custom.css';
|
||||
import '@/css/surge365.css';
|
||||
|
||||
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js'; // Bootstrap JS
|
||||
import 'admin-lte/dist/js/adminlte.min.js';
|
||||
import 'admin-lte/dist/js/adminlte.min.js';
|
||||
|
||||
|
||||
|
||||
const LayoutLogin = function LayoutLogin({ children }: { children: ReactNode }) {
|
||||
|
||||
return (
|
||||
<HelmetProvider>
|
||||
<Helmet>
|
||||
</Helmet>
|
||||
{children}
|
||||
</HelmetProvider>
|
||||
);
|
||||
}
|
||||
|
||||
LayoutLogin.propTypes = {
|
||||
children: PropTypes.any
|
||||
};
|
||||
|
||||
export default LayoutLogin;
|
||||
@ -0,0 +1,125 @@
|
||||
import { ReactNode } from 'react';
|
||||
//import React from 'react';
|
||||
import { Helmet, HelmetProvider } from 'react-helmet-async';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import 'admin-lte/dist/css/adminlte.min.css';
|
||||
import 'font-awesome/css/font-awesome.min.css';
|
||||
/*import 'ionicons/dist/css/ionicons.min.css';*/
|
||||
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js'; // Bootstrap JS
|
||||
import 'admin-lte/dist/js/adminlte.min.js';
|
||||
|
||||
const Layout = function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<HelmetProvider>
|
||||
<div className="wrapper" style={{ overflow: 'initial' }}>
|
||||
<Helmet>
|
||||
<link rel="stylesheet" href="/content/dist/css/skins/_all-skins.min.css" />
|
||||
<link href="/content/plugins/datepicker/v4/bootstrap-datetimepicker.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/content/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css" />
|
||||
<link rel="stylesheet" href="/content/plugins/datatables/dataTables.bootstrap.css" />
|
||||
|
||||
{/*<script src="/content/dist/js/app.min.js"></script>AdminLTE?*/}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.min.js"></script>
|
||||
{/*<script src="/content/plugins/datatables/jquery.dataTables.min.js"></script>*/}
|
||||
{/*<script src="/content/plugins/validator/validator.js"></script>*/}
|
||||
<script src="/content/js/jquery.surge365.utilities-1.0.js" />
|
||||
<script src="/content/js/jquery.surge365.global.js?36"></script>
|
||||
<script src="/content/js/jquery.surge365.webmethods-1.0.js?15"></script>
|
||||
<script src="/content/js/Main-1.0.js?39"></script>
|
||||
{/*<script src="/content/plugins/growl/jquery.bootstrap-growl.min.js"></script>*/}
|
||||
{/*<script src="/content/plugins/input-mask-5/jquery.inputmask.js"></script>*/}
|
||||
{/*<script src="/content/plugins/printThis/printThis.js"></script>*/}
|
||||
{/*<script src="/content/plugins/datatables/dataTables.bootstrap.min.js"></script>*/}
|
||||
</Helmet>
|
||||
<header className="main-header">
|
||||
<a href="Dashboard" className="logo" style={{ backgroundColor: '#333' }}>
|
||||
<span className="logo-mini" style={{ backgroundColor: '#333' }}>
|
||||
<img id="imgLogo-sm" src="/content/img/imove_mini_logo.png" style={{ height: '35px', marginBottom: '3px' }} alt="Logo" className="hide" />
|
||||
</span>
|
||||
<span className="logo-lg" style={{ textAlign: 'center', backgroundColor: '#333' }}>
|
||||
<img id="imgLogo-lg" src="/content/img/imove_mini_logo.png" style={{ height: '35px', marginBottom: '3px' }} alt="Logo" className="hide" />
|
||||
<span style={{ marginLeft: '5px', verticalAlign: 'middle' }}><b>USA</b>Haulers</span>
|
||||
</span>
|
||||
</a>
|
||||
<nav className="navbar navbar-static-top">
|
||||
<a href="#" className="fa5 sidebar-toggle" data-toggle="offcanvas" role="button">
|
||||
<span className="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<div className="navbar-custom-menu">
|
||||
<ul className="nav navbar-nav">
|
||||
<li className="dropdown user user-menu">
|
||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown">
|
||||
<span id="spanSpinner" className="fa fa-sync-alt pull-left" style={{ lineHeight: 'unset', display: 'none', fontSize: '16pt', fontWeight: 'bold', marginRight: '10px' }}></span>
|
||||
<img id="imgRightProfile" src="/content/img/generic_avatar.jpg" className="user-image" alt="User Image" />
|
||||
<span id="spanProfileName"></span>
|
||||
</a>
|
||||
<ul className="dropdown-menu">
|
||||
<li className="user-header">
|
||||
<img id="imgMainProfile" src="" className="img-circle" alt="User Image" />
|
||||
<p>
|
||||
<span id="spanProfileNameTitle"></span>
|
||||
</p>
|
||||
</li>
|
||||
<li className="user-footer">
|
||||
<div className="pull-left">
|
||||
<a href="Profile" className="btn btn-default btn-flat">Profile</a>
|
||||
</div>
|
||||
<div className="pull-right">
|
||||
<input type="button" id="btnSignOut" className="btn btn-primary" value="Sign Out" />
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<aside className="main-sidebar">
|
||||
<section className="sidebar">
|
||||
<div className="user-panel">
|
||||
<div className="pull-left image">
|
||||
<img id="imgLeftProfile" src="/content/img/generic_avatar.jpg" className="img-circle" alt="User Image" />
|
||||
</div>
|
||||
<div className="pull-left info" style={{ lineHeight: 3 }}>
|
||||
<p><span id="spanMenuName"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="sidebar-menu">
|
||||
<li className="header">MAIN NAVIGATION</li>
|
||||
<li id="liDashboard" className="active treeview">
|
||||
<a href="Dashboard">
|
||||
<i className="fa fa-home"></i><span>Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
<li className="treeview">
|
||||
<a href="#" id="aSignOut">
|
||||
<i className="fa fa-times-circle"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
{children}
|
||||
|
||||
<footer className="main-footer" style={{ padding: '2px' }}>
|
||||
<div className="pull-right hidden-xs">
|
||||
<b>Version</b> 1.0.0
|
||||
</div>
|
||||
<strong>Copyright © 2024 <a href="https://www.surge365.com">Surge365</a>.</strong> All rights reserved.
|
||||
</footer>
|
||||
</div>
|
||||
</HelmetProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Layout.propTypes = {
|
||||
children: PropTypes.any
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
@ -0,0 +1,137 @@
|
||||
import { useState } from 'react';
|
||||
import { Modal, Button, Form } from 'react-bootstrap';
|
||||
import { FaExclamationCircle } from 'react-icons/fa'; // For optional font icon
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import utils from '@/ts/utils.ts'
|
||||
|
||||
const ForgotPasswordModal = ({ show, onClose }) => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [formErrors, setFormErrors] = useState({});
|
||||
const [emailNotFound, setEmailNotFound] = useState(false);
|
||||
const [recoveryStarted, setRecoveryStarted] = useState(false);
|
||||
|
||||
const validate = () => {
|
||||
setFormErrors({});
|
||||
|
||||
const errors = {};
|
||||
if (!email.trim()) {
|
||||
errors.email = 'Email is required';
|
||||
} else if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
errors.email = 'Invalid email address';
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length > 0) {
|
||||
setFormErrors(errors);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const handleStartPasswordRecovery = async (e) => {
|
||||
e.preventDefault();
|
||||
setEmailNotFound(false);
|
||||
|
||||
if (validate()) {
|
||||
console.log('Processing forgot password for', email);
|
||||
await utils.webMethod({
|
||||
'methodPage': 'UserMethods',
|
||||
'methodName': 'GeneratePasswordRecovery',
|
||||
'parameters': { "emailAddress": email },
|
||||
success: function (json) {
|
||||
if (utils.getBoolean(json.success)) {
|
||||
setRecoveryStarted(true);
|
||||
}
|
||||
else {
|
||||
setEmailNotFound(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
$("#btnResetPassword").click(function (e) {
|
||||
$("#frmResetPassword").validator('validate');
|
||||
e.preventDefault();
|
||||
var isValid = !$('#frmResetPassword .has-error').length
|
||||
|
||||
if (isValid) {
|
||||
$.webMethod({
|
||||
'methodPage': 'UserMethods',
|
||||
'methodName': 'ResetPasswordFromToken',
|
||||
'parameters': { "token": getParameterByName("guid"), "password": $("#txtNewPassword").val() },
|
||||
success: function (json) {
|
||||
|
||||
if ($.getBoolean(json.success)) {
|
||||
|
||||
//redirect user to Dashboard
|
||||
location.href = "/vehicles";
|
||||
|
||||
}
|
||||
else {
|
||||
//error
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
*/
|
||||
return (
|
||||
<Modal show={show} onHide={onClose} backdrop="static" keyboard={false} centered={true} animation={false} >
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Forgot your password?</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
{emailNotFound && (
|
||||
<span>An email has been sent to the address you provided. Please follow the instructions in the email in order to reset your password.</span>
|
||||
)}
|
||||
{!recoveryStarted && (
|
||||
<Form onSubmit={handleStartPasswordRecovery}>
|
||||
<Form.Group controlId="formForgotEmail" className="position-relative mb-3">
|
||||
<Form.Label className="mb-4 text-center">Enter your email address below and we'll send you instructions on how to reset your password...</Form.Label>
|
||||
<Form.Label className="visually-hidden">Email Addresss</Form.Label>
|
||||
<Form.Control
|
||||
type="email"
|
||||
placeholder="Email address"
|
||||
value={email}
|
||||
isInvalid={!!formErrors.email} // Add Bootstrap's invalid styling
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
autoFocus
|
||||
size="lg"
|
||||
/>
|
||||
{/* Validation Icon */}
|
||||
{formErrors.email && (
|
||||
<FaExclamationCircle
|
||||
className="validation-icon text-danger"
|
||||
title={formErrors.email}
|
||||
/>
|
||||
)}
|
||||
{/* Validation Message */}
|
||||
<Form.Control.Feedback type="invalid">{formErrors.email}</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<Button variant="primary" className="bg-orange btn-flat w-100" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Form>
|
||||
)}
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button variant="secondary" onClick={onClose} type="button">
|
||||
Close
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
ForgotPasswordModal.propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ForgotPasswordModal;
|
||||
35
surge365.massemailreact.client/src/components/pages/App.tsx
Normal file
35
surge365.massemailreact.client/src/components/pages/App.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
// App.tsx or main routing component
|
||||
//import React from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import Layout from '@/components/layouts/Layout';
|
||||
import LayoutLogin from '@/components/layouts/LayoutLogin';
|
||||
import Vehicles from '@/components/pages/Vehicles';
|
||||
import Login from '@/components/pages/Login';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<Router basename="/">
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate to="/login" replace />} />
|
||||
<Route
|
||||
path="/vehicles"
|
||||
element={
|
||||
<Layout>
|
||||
<Vehicles />
|
||||
</Layout>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<LayoutLogin>
|
||||
<Login />
|
||||
</LayoutLogin>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
177
surge365.massemailreact.client/src/components/pages/Login.tsx
Normal file
177
surge365.massemailreact.client/src/components/pages/Login.tsx
Normal file
@ -0,0 +1,177 @@
|
||||
import { useState } from 'react';
|
||||
import { Button, Form, Spinner } from 'react-bootstrap';
|
||||
//import { Helmet, HelmetProvider } from 'react-helmet-async';
|
||||
|
||||
import utils from '@/ts/utils.ts';
|
||||
import ForgotPasswordModal from '@/components/modals/ForgotPasswordModal';
|
||||
|
||||
type SpinnerState = Record<string, boolean>;
|
||||
type FormErrors = Record<string, string>;
|
||||
|
||||
function Login() {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [spinners, setSpinnersState] = useState<SpinnerState>({});
|
||||
const [formErrors, setFormErrors] = useState<FormErrors>({});
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [showForgotPasswordModal, setShowForgotPasswordModal] = useState(false);
|
||||
const [user, setUser] = useState<any>(null);
|
||||
const [loginError, setLoginError] = useState<boolean>(false);
|
||||
|
||||
//const setSpinners = (newValues: Partial<SpinnerState>) => {
|
||||
// setSpinnersState((prevSpinners) => ({
|
||||
// ...prevSpinners,
|
||||
// ...newValues,
|
||||
// }));
|
||||
//};
|
||||
const setSpinners = (newValues: Partial<SpinnerState>) => {
|
||||
setSpinnersState((prevSpinners) => {
|
||||
const updatedSpinners: SpinnerState = { ...prevSpinners };
|
||||
for (const key in newValues) {
|
||||
if (newValues[key] !== undefined) {
|
||||
updatedSpinners[key] = newValues[key] as boolean;
|
||||
}
|
||||
}
|
||||
return updatedSpinners;
|
||||
});
|
||||
};
|
||||
|
||||
const handleCloseForgotPasswordModal = () => {
|
||||
setShowForgotPasswordModal(false);
|
||||
};
|
||||
|
||||
const handleEmailBlur = () => {
|
||||
};
|
||||
|
||||
const validateLoginForm = () => {
|
||||
setFormErrors({});
|
||||
|
||||
const errors: FormErrors = {};
|
||||
if (!email.trim()) {
|
||||
errors.email = 'Email is required';
|
||||
} else if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
errors.email = 'Invalid email address';
|
||||
}
|
||||
if (!password.trim()) {
|
||||
errors.password = 'Password is required';
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length > 0) {
|
||||
setFormErrors(errors);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
spinners.Login = true;
|
||||
setSpinners(spinners);
|
||||
|
||||
validateLoginForm();
|
||||
|
||||
if (Object.keys(formErrors).length > 0) return;
|
||||
|
||||
setLoginError(false);
|
||||
let loggedInUser: any = null;
|
||||
|
||||
await utils.webMethod({
|
||||
methodPage: 'UserMethods',
|
||||
methodName: 'AuthenticateUser',
|
||||
parameters: { emailAddress: email, password: password },
|
||||
success: (json: any) => {
|
||||
if (utils.getBoolean(json.success)) {
|
||||
loggedInUser = json.data;
|
||||
setUser(loggedInUser);
|
||||
} else {
|
||||
setLoginError(true);
|
||||
setIsLoading(false);
|
||||
spinners.Login = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (loginError) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (loggedInUser == null) {
|
||||
setLoginError(true);
|
||||
setIsLoading(false);
|
||||
spinners.Login = false;
|
||||
setSpinners(spinners);
|
||||
} else {
|
||||
await finishUserLogin(loggedInUser);
|
||||
}
|
||||
};
|
||||
|
||||
const finishUserLogin = async (user: any) => {
|
||||
setIsLoading(false);
|
||||
spinners.Login = false;
|
||||
spinners.LoginWithPasskey = false;
|
||||
setSpinners(spinners);
|
||||
|
||||
utils.localStorage("session_currentUser", user);
|
||||
|
||||
const redirectUrl = utils.sessionStorage("redirect_url");
|
||||
if (redirectUrl) {
|
||||
utils.sessionStorage("redirect_url", null);
|
||||
document.location.href = redirectUrl;
|
||||
} else {
|
||||
document.location.href = '/vehicles';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="row text-center mt-5">
|
||||
<h1>surge365 - React</h1>
|
||||
</div>
|
||||
<div className="row text-center" style={{ maxWidth: '400px', margin: 'auto' }}>
|
||||
<h3 className="form-signin-heading mt-3 mb-1">Please sign in</h3>
|
||||
<Form id="frmLogin" onSubmit={handleLogin}>
|
||||
{loginError && (
|
||||
<Form.Label style={{ color: 'red' }}>Login error</Form.Label>
|
||||
)}
|
||||
<Form.Group className="mb-3" controlId="txtEmail">
|
||||
<Form.Label className="visually-hidden">Email address</Form.Label>
|
||||
<Form.Control
|
||||
type="email"
|
||||
placeholder="Email address"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
onBlur={handleEmailBlur}
|
||||
required
|
||||
autoFocus
|
||||
size="sm"
|
||||
/>
|
||||
{spinners.Username && <Spinner animation="border" size="sm" />}
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group className="mb-3" controlId="txtPassword">
|
||||
<Form.Label className="visually-hidden">Password</Form.Label>
|
||||
<Form.Control
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
size="sm"
|
||||
/>
|
||||
</Form.Group>
|
||||
|
||||
<Button className="bg-orange w-100" type="submit" disabled={isLoading}>
|
||||
{spinners.Login && <Spinner animation="border" size="sm" className="me-2" />}
|
||||
{isLoading && spinners.Login ? 'Signing in...' : 'Sign in'}
|
||||
</Button>
|
||||
<Button variant="secondary" className="w-100 mt-2" onClick={() => setShowForgotPasswordModal(true)}>
|
||||
Forgot Password
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<ForgotPasswordModal show={showForgotPasswordModal} onClose={handleCloseForgotPasswordModal} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
||||
370
surge365.massemailreact.client/src/components/pages/Vehicles.tsx
Normal file
370
surge365.massemailreact.client/src/components/pages/Vehicles.tsx
Normal file
@ -0,0 +1,370 @@
|
||||
//import { useState } from 'react';
|
||||
|
||||
function Vehicles() {
|
||||
return (<div>
|
||||
<link href="/content/plugins/filer/jquery.fileuploader.css" rel="stylesheet" />
|
||||
<link href="/content/plugins/filer/drag-drop/css/jquery.fileuploader-theme-dragdrop.css" rel="stylesheet" />
|
||||
<script src="/content/plugins/filer/jquery.fileuploader.js"></script>
|
||||
|
||||
<script src="/content/js/Vehicles-1.0.js"></script>
|
||||
<div className="content-wrapper">
|
||||
|
||||
{/* Content Header (Page header) */}
|
||||
<section className="content-header">
|
||||
|
||||
<h1>Vehicles
|
||||
<small></small>
|
||||
<button type="button" id="btnNewVehicle" className="btn btn-sm btn-success">New Vehicle</button>
|
||||
<span id="spanLoadPatientsSpinner" className="fa fa-sync-alt" style={{fontSize: '20px', verticalAlign: 'middle', display: 'none' }}></span>
|
||||
</h1>
|
||||
|
||||
</section>
|
||||
<section className="content hide">
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-6">
|
||||
<div className="box">
|
||||
<div className="box-body">
|
||||
|
||||
<form id="frmAddAdjustment" name="frmAddAdjustment" role="form" data-toggle="validator" className="form-horizontal">
|
||||
|
||||
|
||||
<div className="row" role="main">
|
||||
<div className="col-md-12">
|
||||
<div className="form-group has-feedback">
|
||||
<label className="col-sm-2 control-label">LMT</label>
|
||||
<div className="col-sm-10">
|
||||
<select id="selUser" className="form-control" required>
|
||||
</select>
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true" style={{ right: '25px' }}></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="form-group has-feedback">
|
||||
<label className="col-sm-2 control-label">Location</label>
|
||||
<div className="col-sm-10">
|
||||
<select id="selLocations" className="form-control" required>
|
||||
</select>
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true" style={{ right: '25px' }}></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="form-group has-feedback has-success">
|
||||
<label className="col-sm-2 control-label">Batch</label>
|
||||
<div className="col-sm-10">
|
||||
<select id="selBatch" className="form-control" required>
|
||||
</select>
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true" style={{ right: '25px' }}></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="form-group has-feedback">
|
||||
<label className="col-sm-2 control-label">Amount</label>
|
||||
<div className="col-sm-4 has-feedback">
|
||||
<input type="text" id="txtAmount" className="form-control" required pattern="^-?\d+(\.\d{1,2})?$" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true" style={{ right: '25px' }}></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label className="col-sm-2 control-label">Revenue?</label>
|
||||
<div className="col-sm-4 has-feedback">
|
||||
<select id="selRevenue" className="form-control">
|
||||
<option value="Yes">Yes</option>
|
||||
<option value="No">No</option>
|
||||
</select>
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true" style={{ right: '25px' }}></span>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div className="form-group has-feedback">
|
||||
<label className="col-sm-2 control-label">Description</label>
|
||||
<div className="col-sm-10">
|
||||
<input type="text" id="txtDescription" className="form-control" required />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true" style={{ right: '25px' }}></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button id="btnSaveAdjustment" type="button" className="btn btn-success pull-right ">Save Adjustment</button>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<section className="content">
|
||||
|
||||
{/* Info boxes */}
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
{/* Box Comment */}
|
||||
<div className="box">
|
||||
|
||||
{/* /.box-header */}
|
||||
<div className="box-body table-responsive table-condensed no-padding">
|
||||
<table id="tblVehicles" className="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>VIN</th>
|
||||
<th>Name</th>
|
||||
<th>Price</th>
|
||||
<th>Stock #</th>
|
||||
<th>Year</th>
|
||||
<th>Make</th>
|
||||
<th>Model</th>
|
||||
<th>Ext. Color</th>
|
||||
<th>Int. Color</th>
|
||||
<th>Seating</th>
|
||||
<th>Transmission</th>
|
||||
<th>Title</th>
|
||||
<th>Featured<br />
|
||||
Image</th>
|
||||
<th>Images</th>
|
||||
<th>View</th>
|
||||
<th>Edit</th>
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
<tbody id="divRows">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/* /.box-body */}
|
||||
</div>
|
||||
{/* /.box */}
|
||||
</div>
|
||||
{/* /.col */}
|
||||
</div>
|
||||
{/* /.row */}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div id="divEditVehicle" className="modal fade">
|
||||
<div className="modal-dialog modal-lg">
|
||||
|
||||
<div className="modal-content">
|
||||
<form id="frmEditVehicle" name="frmEditVehicle" role="form" data-toggle="validator" data-focus="false" className="form-group-sm">
|
||||
|
||||
<div className="modal-header" style={{ background: '#00a65a' }} >
|
||||
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 className="modal-title" style={{ color: 'white' }}><span id="spanEditType">Edit Patient</span></h4>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="row" role="main">
|
||||
<div className="col-md-12">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Display Name</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtDisplayName" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">VIN</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtVIN" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Stock #</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtStockNumber" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Year</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtYear" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Make</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtMake" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Model</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtModel" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Price</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtPrice" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Seating</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtSeating" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Transmission</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtTranmission" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Interior Color</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtInteriorColor" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
|
||||
<label className="control-label">Exterior Color</label>
|
||||
<div className="has-feedback">
|
||||
<input type="text" id="txtExteriorColor" className="form-control input-sm" required placeholder="" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="form-group has-feedback">
|
||||
<label className="control-label">Featured Image</label>
|
||||
<div className="has-feedback">
|
||||
<img style={{ width: '75px', height: 'auto' }} src="" type="text" id="imgFeaturedImage" />
|
||||
<span className="glyphicon form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-12">
|
||||
<div className="form-group has-feedback">
|
||||
<label className="control-label">Additional Images</label>
|
||||
<div className="drop-zone" id="drop-zone">
|
||||
Drag and drop images here or click to select
|
||||
|
||||
</div>
|
||||
<input type="file" id="file-input" multiple style={{ display: 'none' }} />
|
||||
<div className="preview" id="preview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
|
||||
<div>
|
||||
|
||||
<button type="button" className="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<input id="btnSaveVehicle" type="button" className="btn btn-primary" value="Save" />
|
||||
<span id="spanSpinner" className="fa fa-sync-alt" style={{ fontSize: '20px', verticalAlign: 'middle', display: 'none' }}></span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* /.modal-content */}
|
||||
</div>
|
||||
{/* /.modal-dialog */}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="divUploadDocument" className="modal fade">
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<form id="frmUploadUserDocument" name="frmUploadUserDocument" role="form" data-toggle="validator" style={{ paddingTop: '5px' }} >
|
||||
<div className="modal-header">
|
||||
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span></button>
|
||||
<h4 className="modal-title">Upload new document?</h4>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="row" role="main">
|
||||
<div className="col-md-12">
|
||||
<div id="divNewDocument" className="col-sm-12">
|
||||
<input type="file" name="newDocument" id="newDocument" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
|
||||
<input id="btnSubmitNewDocumentFinal" type="button" className="btn btn-danger" value="Submit Document" />
|
||||
<span id="spanSubmitNewDocumentSpinner" className="fa fa-sync-alt" style={{ fontSize: '20px', verticalAlign: 'middle', display: 'none' }} ></span>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/* /.modal-content */}
|
||||
</div>
|
||||
{/* /.modal-dialog */}
|
||||
</div></div>
|
||||
);
|
||||
//return content;
|
||||
}
|
||||
|
||||
export default Vehicles;
|
||||
11
surge365.massemailreact.client/src/components/pages/main.tsx
Normal file
11
surge365.massemailreact.client/src/components/pages/main.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import '@/css/main.css'
|
||||
import App from '@/components/pages/App.tsx'
|
||||
import '@/config/constants';
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
12
surge365.massemailreact.client/src/config/constants.js
Normal file
12
surge365.massemailreact.client/src/config/constants.js
Normal file
@ -0,0 +1,12 @@
|
||||
// src/config/constants.js
|
||||
|
||||
// Set up constants from environment variables
|
||||
export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
// Add more constants as needed, all prefixed by 'VITE_' for compatibility
|
||||
|
||||
|
||||
// Add global values to window object for use in static JS
|
||||
if (typeof window !== 'undefined') {
|
||||
window.API_BASE_URL = API_BASE_URL;
|
||||
}
|
||||
78
surge365.massemailreact.client/src/css/Vehicles.css
Normal file
78
surge365.massemailreact.client/src/css/Vehicles.css
Normal file
@ -0,0 +1,78 @@
|
||||
.has-feedback .form-control {
|
||||
padding-right: 30.5px;
|
||||
}
|
||||
|
||||
.notesStyle {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 200px;
|
||||
min-width: 200px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td {
|
||||
padding: 3px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.dataTables_wrapper {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.dataTables_wrapper .sorting_icon {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.no-sort {
|
||||
padding-right: 3px !important;
|
||||
}
|
||||
|
||||
.drop-zone {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
border: 2px dashed #ccc;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
margin: 20px auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drop-zone.dragover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.preview {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.preview div {
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.preview img {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.preview button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background: red;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
107
surge365.massemailreact.client/src/css/adminlte-custom.css
Normal file
107
surge365.massemailreact.client/src/css/adminlte-custom.css
Normal file
@ -0,0 +1,107 @@
|
||||
/* Custom CSS to restore old AdminLTE color classes in AdminLTE 4.x */
|
||||
|
||||
/* Orange Background */
|
||||
.bg-orange {
|
||||
background-color: #ff851b !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Blue Background */
|
||||
.bg-blue {
|
||||
background-color: #0073b7 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Green Background */
|
||||
.bg-green {
|
||||
background-color: #00a65a !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Red Background */
|
||||
.bg-red {
|
||||
background-color: #dd4b39 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Yellow Background */
|
||||
.bg-yellow {
|
||||
background-color: #f39c12 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Purple Background */
|
||||
.bg-purple {
|
||||
background-color: #605ca8 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Light Blue Background */
|
||||
.bg-light-blue {
|
||||
background-color: #3c8dbc !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Navy Background */
|
||||
.bg-navy {
|
||||
background-color: #001f3f !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Teal Background */
|
||||
.bg-teal {
|
||||
background-color: #39cccc !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Maroon Background */
|
||||
.bg-maroon {
|
||||
background-color: #d81b60 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Black Background */
|
||||
.bg-black {
|
||||
background-color: #111 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Olive Background */
|
||||
.bg-olive {
|
||||
background-color: #3d9970 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Lime Background */
|
||||
.bg-lime {
|
||||
background-color: #01ff70 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Fuchsia Background */
|
||||
.bg-fuchsia {
|
||||
background-color: #f012be !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Aqua Background */
|
||||
.bg-aqua {
|
||||
background-color: #00c0ef !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Gray Background */
|
||||
.bg-gray {
|
||||
background-color: #d2d6de !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Flat Button */
|
||||
.btn-flat {
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
padding: 10px 15px;
|
||||
font-size: 14px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
0
surge365.massemailreact.client/src/css/main.css
Normal file
0
surge365.massemailreact.client/src/css/main.css
Normal file
38
surge365.massemailreact.client/src/css/surge365.css
Normal file
38
surge365.massemailreact.client/src/css/surge365.css
Normal file
@ -0,0 +1,38 @@
|
||||
body {
|
||||
}
|
||||
|
||||
|
||||
.form-signin {
|
||||
max-width: 330px;
|
||||
padding: 15px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.form-signin .form-signin-heading,
|
||||
.form-signin .checkbox {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.form-signin .checkbox {
|
||||
font-weight: normal;
|
||||
}
|
||||
.form-signin .form-control {
|
||||
position: relative;
|
||||
height: auto;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.form-signin .form-control:focus {
|
||||
z-index: 2;
|
||||
}
|
||||
.form-signin input[type="email"] {
|
||||
margin-bottom: -1px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.form-signin input[type="password"] {
|
||||
margin-bottom: 10px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
156
surge365.massemailreact.client/src/ts/utils.ts
Normal file
156
surge365.massemailreact.client/src/ts/utils.ts
Normal file
@ -0,0 +1,156 @@
|
||||
const utils = {
|
||||
getCookie: (name: string): string | null => {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop()?.split(';').shift() ?? null;
|
||||
return null;
|
||||
},
|
||||
getParameterByName: (name: string): string | null => {
|
||||
const regex = new RegExp(`[\?&]${name}=([^&#]*)`);
|
||||
const results = regex.exec(window.location.search);
|
||||
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
|
||||
},
|
||||
addAuthHeaders: (headers: Record<string, string> = {}): Record<string, string> => {
|
||||
const authToken = utils.getCookie('Auth-Token');
|
||||
if (authToken) {
|
||||
headers['Auth-Token'] = authToken;
|
||||
}
|
||||
|
||||
const impersonateGuid = utils.getParameterByName("impersonateid") || sessionStorage.getItem('Auth-Impersonate-Guid');
|
||||
if (impersonateGuid) {
|
||||
sessionStorage.setItem('Auth-Impersonate-Guid', impersonateGuid);
|
||||
headers['Auth-Impersonate-Guid'] = impersonateGuid;
|
||||
}
|
||||
|
||||
const franchiseCode = sessionStorage.getItem('franchiseCode');
|
||||
if (franchiseCode) {
|
||||
headers['Auth-Current-Franchise'] = franchiseCode;
|
||||
}
|
||||
|
||||
return headers;
|
||||
},
|
||||
webMethod: async ({
|
||||
httpMethod = 'POST',
|
||||
baseMethodPath = 'api/',
|
||||
methodPage = '',
|
||||
methodName = '',
|
||||
parameters = {},
|
||||
contentType = 'application/json;',
|
||||
timeout = 300000,
|
||||
success = () => { },
|
||||
error = () => { },
|
||||
}: {
|
||||
httpMethod?: string;
|
||||
baseMethodPath?: string;
|
||||
methodPage?: string;
|
||||
methodName?: string;
|
||||
parameters?: Record<string, any>;
|
||||
contentType?: string;
|
||||
timeout?: number;
|
||||
success?: (data: any) => void;
|
||||
error?: (err: any) => void;
|
||||
}): Promise<void> => {
|
||||
try {
|
||||
const baseUrl = window.API_BASE_URL || '';
|
||||
const url = `${baseUrl.replace(/\/$/, '')}/${baseMethodPath.replace(/\/$/, '')}/${methodPage}${methodName ? '/' + methodName : ''}`;
|
||||
|
||||
const headers = utils.addAuthHeaders({
|
||||
'Content-Type': contentType,
|
||||
});
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: httpMethod,
|
||||
headers,
|
||||
body: JSON.stringify(parameters),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const authToken = response.headers.get('Auth-Token');
|
||||
const loggedIn = response.headers.get('usahl_logged_in') === 'true';
|
||||
|
||||
const expires = loggedIn ? 365 : 14;
|
||||
document.cookie = `Auth-Token=${authToken};path=/;max-age=${expires * 24 * 60 * 60}`;
|
||||
document.cookie = `usahl_logged_in=${loggedIn};path=/;max-age=${expires * 24 * 60 * 60}`;
|
||||
|
||||
const data = await response.json();
|
||||
success(data);
|
||||
} catch (err) {
|
||||
if ((err as Error).name === 'AbortError') {
|
||||
console.error('Request timed out');
|
||||
}
|
||||
error(err);
|
||||
}
|
||||
},
|
||||
getBoolean: (variable: any): boolean => {
|
||||
if (variable != null) {
|
||||
switch (typeof variable) {
|
||||
case 'boolean':
|
||||
return variable;
|
||||
case 'number':
|
||||
return variable !== 0;
|
||||
case 'string':
|
||||
return /^(true|yes)$/i.test(variable) || variable.length > 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
isLoggedIn: (): boolean => {
|
||||
return utils.getBoolean(utils.getCookie('usahl_logged_in'));
|
||||
},
|
||||
sessionStorage: (key: string, value?: any): any => {
|
||||
if (value === undefined) {
|
||||
let val = window.sessionStorage.getItem(key);
|
||||
if (val && val.startsWith('usahl_json:')) {
|
||||
val = val.substring(11);
|
||||
return JSON.parse(val);
|
||||
}
|
||||
return val;
|
||||
} else {
|
||||
const val = typeof value === 'object' ? `usahl_json:${JSON.stringify(value)}` : value;
|
||||
window.sessionStorage.setItem(key, val);
|
||||
}
|
||||
},
|
||||
sessionStorageClear: (): void => {
|
||||
window.sessionStorage.clear();
|
||||
},
|
||||
sessionStorageRemove: (key: string): void => {
|
||||
window.sessionStorage.removeItem(key);
|
||||
},
|
||||
localStorage: (key: string, value?: any): any => {
|
||||
if (value === undefined) {
|
||||
let val = window.localStorage.getItem(key);
|
||||
if (val && val.startsWith('usahl_json:')) {
|
||||
val = val.substring(11);
|
||||
return JSON.parse(val);
|
||||
}
|
||||
return val;
|
||||
} else {
|
||||
const val = typeof value === 'object' ? `usahl_json:${JSON.stringify(value)}` : value;
|
||||
window.localStorage.setItem(key, val);
|
||||
}
|
||||
},
|
||||
localStorageClear: (): void => {
|
||||
window.localStorage.clear();
|
||||
},
|
||||
localStorageRemove: (key: string): void => {
|
||||
window.localStorage.removeItem(key);
|
||||
}
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
utils: object
|
||||
}
|
||||
}
|
||||
window.utils = utils;
|
||||
|
||||
export default utils;
|
||||
@ -8,4 +8,11 @@
|
||||
<!-- Folder where production build objects will be placed -->
|
||||
<BuildOutputFolder>$(MSBuildProjectDirectory)\dist</BuildOutputFolder>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="src\components\layouts\LayoutLogin_Backup.tsx" />
|
||||
<None Remove="src\components\layouts\Layout_backup.tsx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="public\content\lib\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -3,5 +3,11 @@
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [ "./src/*" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user