WIP
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"plugins": {
|
||||
"@tailwindcss/postcss": {}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -48,7 +48,8 @@
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
"src/styles.scss",
|
||||
"src/tailwind.css"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
@@ -106,7 +107,8 @@
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
"src/styles.scss",
|
||||
"src/tailwind.css"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Escrow Portal Access - ROLCC AC</title>
|
||||
<title>Church Portal Access - ROLCC AC</title>
|
||||
<style>
|
||||
/* Email-safe CSS - compatible with most email clients */
|
||||
body {
|
||||
@@ -233,7 +233,7 @@
|
||||
<tr>
|
||||
<td class="email-header"
|
||||
style="background-color: #1e3a8a; padding: 30px 20px; text-align: center; color: white;">
|
||||
<img src="assets/rbj-logo.svg" alt="RBJ Logo" class="logo-image"
|
||||
<img src="assets/images/ROLCC-Logo-Color.png" alt="ROLCC Logo" class="logo-image"
|
||||
style="height: 50px; width: auto; margin-bottom: 15px;">
|
||||
<div class="logo-text">
|
||||
<h1 style="font-size: 28px; font-weight: bold; margin: 0 0 5px 0;">ROLCC AC</h1>
|
||||
|
||||
Generated
+621
-8
@@ -63,6 +63,7 @@
|
||||
"@angular/cli": "^20.1.6",
|
||||
"@angular/compiler-cli": "^20.1.0",
|
||||
"@angular/localize": "^20.2.1",
|
||||
"@tailwindcss/postcss": "^4.3.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.8.0",
|
||||
"karma": "~6.4.0",
|
||||
@@ -70,6 +71,8 @@
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"postcss": "^8.5.15",
|
||||
"tailwindcss": "^4.3.0",
|
||||
"typescript": "~5.8.2"
|
||||
}
|
||||
},
|
||||
@@ -282,6 +285,19 @@
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
@@ -1910,6 +1926,17 @@
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/remapping": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
||||
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
@@ -4830,6 +4857,287 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tailwindcss/node": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
|
||||
"integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.5",
|
||||
"enhanced-resolve": "^5.21.0",
|
||||
"jiti": "^2.6.1",
|
||||
"lightningcss": "1.32.0",
|
||||
"magic-string": "^0.30.21",
|
||||
"source-map-js": "^1.2.1",
|
||||
"tailwindcss": "4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/node/node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz",
|
||||
"integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tailwindcss/oxide-android-arm64": "4.3.0",
|
||||
"@tailwindcss/oxide-darwin-arm64": "4.3.0",
|
||||
"@tailwindcss/oxide-darwin-x64": "4.3.0",
|
||||
"@tailwindcss/oxide-freebsd-x64": "4.3.0",
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0",
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": "4.3.0",
|
||||
"@tailwindcss/oxide-linux-arm64-musl": "4.3.0",
|
||||
"@tailwindcss/oxide-linux-x64-gnu": "4.3.0",
|
||||
"@tailwindcss/oxide-linux-x64-musl": "4.3.0",
|
||||
"@tailwindcss/oxide-wasm32-wasi": "4.3.0",
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": "4.3.0",
|
||||
"@tailwindcss/oxide-win32-x64-msvc": "4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-android-arm64": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz",
|
||||
"integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-darwin-arm64": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz",
|
||||
"integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-darwin-x64": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz",
|
||||
"integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-freebsd-x64": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz",
|
||||
"integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz",
|
||||
"integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz",
|
||||
"integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz",
|
||||
"integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz",
|
||||
"integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz",
|
||||
"integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz",
|
||||
"integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==",
|
||||
"bundleDependencies": [
|
||||
"@napi-rs/wasm-runtime",
|
||||
"@emnapi/core",
|
||||
"@emnapi/runtime",
|
||||
"@tybys/wasm-util",
|
||||
"@emnapi/wasi-threads",
|
||||
"tslib"
|
||||
],
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.10.0",
|
||||
"@emnapi/runtime": "^1.10.0",
|
||||
"@emnapi/wasi-threads": "^1.2.1",
|
||||
"@napi-rs/wasm-runtime": "^1.1.4",
|
||||
"@tybys/wasm-util": "^0.10.1",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz",
|
||||
"integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz",
|
||||
"integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/postcss": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.0.tgz",
|
||||
"integrity": "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"@tailwindcss/node": "4.3.0",
|
||||
"@tailwindcss/oxide": "4.3.0",
|
||||
"postcss": "^8.5.10",
|
||||
"tailwindcss": "4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tufjs/canonical-json": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
|
||||
@@ -5930,7 +6238,6 @@
|
||||
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -6178,6 +6485,20 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.22.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz",
|
||||
"integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ent": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz",
|
||||
@@ -7337,6 +7658,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
|
||||
"integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -7924,6 +8255,267 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"lightningcss-android-arm64": "1.32.0",
|
||||
"lightningcss-darwin-arm64": "1.32.0",
|
||||
"lightningcss-darwin-x64": "1.32.0",
|
||||
"lightningcss-freebsd-x64": "1.32.0",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.32.0",
|
||||
"lightningcss-linux-arm64-gnu": "1.32.0",
|
||||
"lightningcss-linux-arm64-musl": "1.32.0",
|
||||
"lightningcss-linux-x64-gnu": "1.32.0",
|
||||
"lightningcss-linux-x64-musl": "1.32.0",
|
||||
"lightningcss-win32-arm64-msvc": "1.32.0",
|
||||
"lightningcss-win32-x64-msvc": "1.32.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-android-arm64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
|
||||
"integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-arm64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
|
||||
"integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-x64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
|
||||
"integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-freebsd-x64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
|
||||
"integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
|
||||
"integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-gnu": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
|
||||
"integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-musl": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
|
||||
"integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-gnu": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
|
||||
"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-musl": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
|
||||
"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-arm64-msvc": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
|
||||
"integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-x64-msvc": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
|
||||
"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/listr2": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz",
|
||||
@@ -8597,9 +9189,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -9376,9 +9968,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"version": "8.5.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -9396,7 +9988,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"nanoid": "^3.3.12",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
@@ -10576,6 +11168,27 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
|
||||
"integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
|
||||
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||
|
||||
+4
-1
@@ -77,6 +77,7 @@
|
||||
"@angular/cli": "^20.1.6",
|
||||
"@angular/compiler-cli": "^20.1.0",
|
||||
"@angular/localize": "^20.2.1",
|
||||
"@tailwindcss/postcss": "^4.3.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.8.0",
|
||||
"karma": "~6.4.0",
|
||||
@@ -84,6 +85,8 @@
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"postcss": "^8.5.15",
|
||||
"tailwindcss": "^4.3.0",
|
||||
"typescript": "~5.8.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
<kendo-dialog title="Quick add member" (close)="cancelled.emit()" [width]="420">
|
||||
<div style="display:flex;flex-direction:column;gap:0.75rem;">
|
||||
<label>First name (EN) *<kendo-textbox [(ngModel)]="firstName_en"></kendo-textbox></label>
|
||||
<label>Last name (EN) *<kendo-textbox [(ngModel)]="lastName_en"></kendo-textbox></label>
|
||||
<label>名 (中)<kendo-textbox [(ngModel)]="firstName_zh"></kendo-textbox></label>
|
||||
<label>姓 (中)<kendo-textbox [(ngModel)]="lastName_zh"></kendo-textbox></label>
|
||||
<label>Cell phone<kendo-textbox [(ngModel)]="phoneCell"></kendo-textbox></label>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
<label class="flex flex-col gap-1">First name (EN) *<kendo-textbox [(ngModel)]="firstName_en"></kendo-textbox></label>
|
||||
<label class="flex flex-col gap-1">Last name (EN) *<kendo-textbox [(ngModel)]="lastName_en"></kendo-textbox></label>
|
||||
<label class="flex flex-col gap-1">名 (中)<kendo-textbox [(ngModel)]="firstName_zh"></kendo-textbox></label>
|
||||
<label class="flex flex-col gap-1">姓 (中)<kendo-textbox [(ngModel)]="lastName_zh"></kendo-textbox></label>
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Cell phone<kendo-textbox [(ngModel)]="phoneCell"></kendo-textbox></label>
|
||||
</div>
|
||||
<kendo-dialog-actions>
|
||||
<button kendoButton (click)="cancelled.emit()">Cancel</button>
|
||||
|
||||
+7
-7
@@ -25,28 +25,28 @@
|
||||
</kendo-grid>
|
||||
|
||||
<kendo-dialog *ngIf="showDialog" [title]="editing ? 'Edit Giving Type' : 'Add Giving Type'" (close)="showDialog=false" [width]="480">
|
||||
<div class="form-grid">
|
||||
<label>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
<label class="flex flex-col gap-1">
|
||||
Name (EN) *
|
||||
<kendo-textbox [(ngModel)]="form.name_en"></kendo-textbox>
|
||||
</label>
|
||||
<label>
|
||||
<label class="flex flex-col gap-1">
|
||||
名稱 (中)
|
||||
<kendo-textbox [(ngModel)]="form.name_zh"></kendo-textbox>
|
||||
</label>
|
||||
<label>
|
||||
<label class="flex flex-col gap-1">
|
||||
Description (EN)
|
||||
<kendo-textbox [(ngModel)]="form.description_en"></kendo-textbox>
|
||||
</label>
|
||||
<label>
|
||||
<label class="flex flex-col gap-1">
|
||||
說明 (中)
|
||||
<kendo-textbox [(ngModel)]="form.description_zh"></kendo-textbox>
|
||||
</label>
|
||||
<label>
|
||||
<label class="flex flex-col gap-1">
|
||||
Sort order
|
||||
<kendo-numerictextbox [(ngModel)]="form.sortOrder" [format]="'n0'" [decimals]="0" [min]="0"></kendo-numerictextbox>
|
||||
</label>
|
||||
<label *ngIf="editing">
|
||||
<label *ngIf="editing" class="flex items-center gap-2 md:col-span-2">
|
||||
<input type="checkbox" [(ngModel)]="form.isActive" /> Active
|
||||
</label>
|
||||
</div>
|
||||
|
||||
-12
@@ -17,15 +17,3 @@
|
||||
gap: 0.25rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.form-grid label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
</kendo-grid>
|
||||
|
||||
<kendo-dialog *ngIf="showDialog" title="Add Giving" (close)="showDialog=false" [width]="520">
|
||||
<div class="form-grid">
|
||||
<label>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
<label class="flex items-center gap-2 md:col-span-2">
|
||||
<input type="checkbox" [ngModel]="form.isAnonymous" (ngModelChange)="toggleAnonymous()" /> Anonymous
|
||||
</label>
|
||||
|
||||
<label *ngIf="!form.isAnonymous">Giver
|
||||
<label *ngIf="!form.isAnonymous" class="flex flex-col gap-1 md:col-span-2">Giver
|
||||
<kendo-dropdownlist [data]="memberResults" textField="displayName" valueField="id"
|
||||
[valuePrimitive]="true" [filterable]="true"
|
||||
(filterChange)="onMemberFilter($event)"
|
||||
@@ -44,34 +44,34 @@
|
||||
placeholder="Search member by name"></kendo-dropdownlist>
|
||||
</label>
|
||||
|
||||
<label>Type
|
||||
<label class="flex flex-col gap-1">Type
|
||||
<kendo-dropdownlist [data]="categories" textField="name_en" valueField="id"
|
||||
[valuePrimitive]="true" [(ngModel)]="form.givingCategoryId"></kendo-dropdownlist>
|
||||
</label>
|
||||
|
||||
<label>Payment method
|
||||
<label class="flex flex-col gap-1">Payment method
|
||||
<kendo-dropdownlist [data]="paymentMethods" [(ngModel)]="form.paymentMethod"></kendo-dropdownlist>
|
||||
</label>
|
||||
|
||||
<label *ngIf="form.paymentMethod === 'Check'">Check #
|
||||
<label *ngIf="form.paymentMethod === 'Check'" class="flex flex-col gap-1">Check #
|
||||
<kendo-textbox [(ngModel)]="form.checkNumber"></kendo-textbox>
|
||||
</label>
|
||||
<label *ngIf="form.paymentMethod === 'Zelle'">Zelle ref
|
||||
<label *ngIf="form.paymentMethod === 'Zelle'" class="flex flex-col gap-1">Zelle ref
|
||||
<kendo-textbox [(ngModel)]="form.zelleReferenceCode"></kendo-textbox>
|
||||
</label>
|
||||
<label *ngIf="form.paymentMethod === 'PayPal'">PayPal txn
|
||||
<label *ngIf="form.paymentMethod === 'PayPal'" class="flex flex-col gap-1">PayPal txn
|
||||
<kendo-textbox [(ngModel)]="form.payPalTransactionId"></kendo-textbox>
|
||||
</label>
|
||||
|
||||
<label>Amount
|
||||
<label class="flex flex-col gap-1">Amount
|
||||
<kendo-numerictextbox [(ngModel)]="form.amount" [min]="0" [format]="'c2'"></kendo-numerictextbox>
|
||||
</label>
|
||||
|
||||
<label>Date
|
||||
<label class="flex flex-col gap-1">Date
|
||||
<kendo-datepicker [(ngModel)]="givingDateValue"></kendo-datepicker>
|
||||
</label>
|
||||
|
||||
<label>Notes
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Notes
|
||||
<kendo-textbox [(ngModel)]="form.notes"></kendo-textbox>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; }
|
||||
.filters { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
|
||||
.form-grid { display: flex; flex-direction: column; gap: 0.75rem; }
|
||||
.form-grid label { display: flex; flex-direction: column; gap: 0.25rem; }
|
||||
|
||||
@@ -120,9 +120,7 @@ export class GivingsPageComponent implements OnInit {
|
||||
|
||||
save(): void {
|
||||
// Sync the datepicker Date back to the ISO string field.
|
||||
this.form.givingDate = this.givingDateValue
|
||||
? this.givingDateValue.toISOString().slice(0, 10)
|
||||
: new Date().toISOString().slice(0, 10);
|
||||
this.form.givingDate = this.toIso(this.givingDateValue ?? new Date());
|
||||
|
||||
if (this.editingId) {
|
||||
this.api.update(this.editingId, this.form).subscribe(() => { this.showDialog = false; this.load(); });
|
||||
@@ -149,9 +147,18 @@ export class GivingsPageComponent implements OnInit {
|
||||
checkNumber: null,
|
||||
zelleReferenceCode: null,
|
||||
payPalTransactionId: null,
|
||||
givingDate: new Date().toISOString().slice(0, 10),
|
||||
givingDate: this.toIso(new Date()),
|
||||
isAnonymous: false,
|
||||
notes: null,
|
||||
};
|
||||
}
|
||||
|
||||
// Format using LOCAL date components — NOT toISOString(), which converts to UTC and
|
||||
// rolls the date forward a day for behind-UTC users when the Date carries an evening time.
|
||||
private toIso(d: Date): string {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${y}-${m}-${day}`;
|
||||
}
|
||||
}
|
||||
|
||||
+122
-72
@@ -1,92 +1,142 @@
|
||||
<div class="page">
|
||||
<header class="page-header">
|
||||
<h2>Sunday Offering Entry / 主日奉獻錄入</h2>
|
||||
<label>Date
|
||||
<kendo-datepicker [(ngModel)]="sessionDate" (valueChange)="checkDate()" [disabled]="editingSessionId != null"></kendo-datepicker>
|
||||
</label>
|
||||
</header>
|
||||
<!-- Card A — Session header -->
|
||||
<section class="card">
|
||||
<header class="page-header">
|
||||
<h2 style="margin:0">Sunday Offering Entry / 主日奉獻錄入</h2>
|
||||
<label class="flex flex-col gap-1">Date
|
||||
<kendo-datepicker [(ngModel)]="sessionDate" (valueChange)="checkDate()"
|
||||
[disabled]="editingSessionId != null"></kendo-datepicker>
|
||||
</label>
|
||||
</header>
|
||||
|
||||
<div *ngIf="editingSessionId != null" class="edit-banner">
|
||||
Editing submitted session — make changes and click "Update Session".
|
||||
<button kendoButton fillMode="flat" (click)="cancelEdit()">Cancel edit</button>
|
||||
</div>
|
||||
<div *ngIf="editingSessionId != null" class="edit-banner">
|
||||
<span class="badge badge--draft">Editing</span>
|
||||
Editing session — make changes and click "Update Session".
|
||||
<button kendoButton fillMode="flat" (click)="cancelEdit()">Cancel edit</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="dateConflict && editingSessionId == null" class="warn">
|
||||
An offering session for this date already exists. Pick another date, or reopen the existing session to edit.
|
||||
</div>
|
||||
|
||||
<section class="entry-row">
|
||||
<label *ngIf="!entry.isAnonymous">Giver
|
||||
<kendo-dropdownlist [data]="memberResults" textField="displayName" valueField="id"
|
||||
[valuePrimitive]="true" [filterable]="true"
|
||||
(filterChange)="onMemberFilter($event)" [(ngModel)]="selectedMemberId"
|
||||
(valueChange)="onMemberSelected($event)" placeholder="Search by name"></kendo-dropdownlist>
|
||||
</label>
|
||||
<span *ngIf="entry.isAnonymous" class="anon-chip">Anonymous</span>
|
||||
|
||||
<label>Type
|
||||
<kendo-dropdownlist [data]="categories" textField="name_en" valueField="id"
|
||||
[valuePrimitive]="true" [(ngModel)]="entry.givingCategoryId"></kendo-dropdownlist>
|
||||
</label>
|
||||
<label>Method
|
||||
<kendo-dropdownlist [data]="paymentMethods" [(ngModel)]="entry.paymentMethod"></kendo-dropdownlist>
|
||||
</label>
|
||||
<label *ngIf="entry.paymentMethod === 'Check'">Check #<kendo-textbox [(ngModel)]="entry.checkNumber"></kendo-textbox></label>
|
||||
<label>Amount
|
||||
<kendo-numerictextbox [(ngModel)]="entry.amount" [min]="0" [format]="'c2'" (keydown.enter)="addLine()"></kendo-numerictextbox>
|
||||
</label>
|
||||
<label>Notes<kendo-textbox [(ngModel)]="entry.notes" (keydown.enter)="addLine()"></kendo-textbox></label>
|
||||
|
||||
<div class="entry-actions">
|
||||
<button kendoButton (click)="markAnonymous()">Anonymous</button>
|
||||
<button kendoButton (click)="showQuickAdd = true">+ Quick add member</button>
|
||||
<button kendoButton themeColor="primary" (click)="addLine()">+ Add (Enter)</button>
|
||||
<div *ngIf="dateConflict && editingSessionId == null" class="warn">
|
||||
An offering session for this date already exists. Pick another date, or reopen the existing session to edit.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<kendo-grid [data]="buffer">
|
||||
<kendo-grid-column title="Giver">
|
||||
<ng-template kendoGridCellTemplate let-l>{{ l.isAnonymous ? '(Anonymous)' : l.memberName }}</ng-template>
|
||||
</kendo-grid-column>
|
||||
<kendo-grid-column field="categoryName" title="Type"></kendo-grid-column>
|
||||
<kendo-grid-column field="paymentMethod" title="Method" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="checkNumber" title="Check #" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="amount" title="Amount" [width]="110" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column title="" [width]="120">
|
||||
<ng-template kendoGridCellTemplate let-l let-i="rowIndex">
|
||||
<button kendoButton fillMode="flat" (click)="editLine(i)">Edit</button>
|
||||
<button kendoButton fillMode="flat" (click)="removeLine(i)">×</button>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
</kendo-grid>
|
||||
<!-- Card B — Add giving -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Add Giving / 錄入奉獻</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-x-4 gap-y-3">
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Giver
|
||||
<kendo-dropdownlist *ngIf="!entry.isAnonymous" [data]="memberResults" textField="displayName" valueField="id"
|
||||
[valuePrimitive]="true" [filterable]="true" (filterChange)="onMemberFilter($event)"
|
||||
[(ngModel)]="selectedMemberId" (valueChange)="onMemberSelected($event)"
|
||||
placeholder="Search by name"></kendo-dropdownlist>
|
||||
<span *ngIf="entry.isAnonymous" class="flex items-center gap-2">
|
||||
<span class="anon-chip">Anonymous</span>
|
||||
<button kendoButton fillMode="flat" size="small" (click)="clearAnonymous()">Clear</button>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<section class="reconcile">
|
||||
<div>Lines: {{ buffer.length }} | System total: {{ systemTotal | currency }}</div>
|
||||
<label>Cash counted<kendo-numerictextbox [(ngModel)]="cashTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox></label>
|
||||
<label>Check counted<kendo-numerictextbox [(ngModel)]="checkTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox></label>
|
||||
<div [class.ok]="difference === 0" [class.bad]="difference !== 0">Difference: {{ difference | currency }}</div>
|
||||
<button kendoButton themeColor="primary"
|
||||
[disabled]="buffer.length === 0 || (editingSessionId == null && dateConflict) || submitting"
|
||||
(click)="submit()">{{ editingSessionId != null ? 'Update Session' : 'Submit' }}</button>
|
||||
<label class="flex flex-col gap-1">Type
|
||||
<kendo-dropdownlist [data]="categories" textField="name_en" valueField="id" [valuePrimitive]="true"
|
||||
[(ngModel)]="entry.givingCategoryId"></kendo-dropdownlist>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">Method
|
||||
<kendo-dropdownlist [data]="paymentMethods" [(ngModel)]="entry.paymentMethod"></kendo-dropdownlist>
|
||||
</label>
|
||||
|
||||
<label *ngIf="entry.paymentMethod === 'Check'" class="flex flex-col gap-1">Check #
|
||||
<kendo-textbox [(ngModel)]="entry.checkNumber"></kendo-textbox>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">Amount
|
||||
<kendo-numerictextbox [(ngModel)]="entry.amount" [min]="0" [format]="'c2'"
|
||||
(keydown.enter)="addLine()"></kendo-numerictextbox>
|
||||
</label>
|
||||
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Notes
|
||||
<kendo-textbox [(ngModel)]="entry.notes" (keydown.enter)="addLine()"></kendo-textbox>
|
||||
</label>
|
||||
|
||||
<div class="flex flex-wrap gap-2 md:col-span-2">
|
||||
<button kendoButton (click)="markAnonymous()">Anonymous</button>
|
||||
<button kendoButton (click)="showQuickAdd = true">+ Quick add member</button>
|
||||
<button kendoButton themeColor="primary" (click)="addLine()">{{ editingIndex !== null ? 'Update line' : '+ Add
|
||||
(Enter)' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sessions-list">
|
||||
<h3>Recent Sessions</h3>
|
||||
<!-- Card C — Lines -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Lines / 已加入明細</h3>
|
||||
<div *ngIf="buffer.length === 0" class="empty">No lines yet — add givings above.</div>
|
||||
<kendo-grid *ngIf="buffer.length > 0" [data]="buffer">
|
||||
<kendo-grid-column title="Giver">
|
||||
<ng-template kendoGridCellTemplate let-l>{{ l.isAnonymous ? '(Anonymous)' : l.memberName }}</ng-template>
|
||||
</kendo-grid-column>
|
||||
<kendo-grid-column field="categoryName" title="Type"></kendo-grid-column>
|
||||
<kendo-grid-column field="paymentMethod" title="Method" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="checkNumber" title="Check #" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="amount" title="Amount" [width]="110" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column title="" [width]="120">
|
||||
<ng-template kendoGridCellTemplate let-l let-i="rowIndex">
|
||||
<button kendoButton fillMode="flat" (click)="editLine(i)">Edit</button>
|
||||
<button kendoButton fillMode="flat" (click)="removeLine(i)">×</button>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
</kendo-grid>
|
||||
<div *ngIf="buffer.length > 0" class="lines-footer">Lines: {{ buffer.length }} · System total: {{ systemTotal |
|
||||
currency }}</div>
|
||||
</section>
|
||||
|
||||
<!-- Card D — Reconcile & submit -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Reconcile & Submit / 對帳</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
<label class="flex flex-col gap-1">Cash counted
|
||||
<kendo-numerictextbox [(ngModel)]="cashTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">Check counted
|
||||
<kendo-numerictextbox [(ngModel)]="checkTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Session notes
|
||||
<kendo-textarea [(ngModel)]="notes" [rows]="2"></kendo-textarea>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-4 mt-4">
|
||||
<span>System total: {{ systemTotal | currency }}</span>
|
||||
<span [class.ok]="difference === 0" [class.bad]="difference !== 0">Difference: {{ difference | currency }}</span>
|
||||
<button kendoButton themeColor="primary"
|
||||
[disabled]="buffer.length === 0 || (editingSessionId == null && dateConflict) || submitting"
|
||||
(click)="submit()">{{ editingSessionId != null ? 'Update Session' : 'Submit' }}</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Card E — Recent sessions -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Recent Sessions</h3>
|
||||
<kendo-grid [data]="sessions">
|
||||
<kendo-grid-column field="sessionDate" title="Date" [width]="120"></kendo-grid-column>
|
||||
<kendo-grid-column field="status" title="Status" [width]="110"></kendo-grid-column>
|
||||
<kendo-grid-column title="Status" [width]="120">
|
||||
<ng-template kendoGridCellTemplate let-s>
|
||||
<span class="badge" [class.badge--draft]="s.status === 'Draft'"
|
||||
[class.badge--submitted]="s.status === 'Submitted'" [class.badge--reconciled]="s.status === 'Reconciled'">{{
|
||||
s.status }}</span>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
<kendo-grid-column field="lineCount" title="Lines" [width]="80"></kendo-grid-column>
|
||||
<kendo-grid-column field="systemTotal" title="System" [width]="110" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column field="difference" title="Diff" [width]="100" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column title="" [width]="140">
|
||||
<kendo-grid-column title="" [width]="150">
|
||||
<ng-template kendoGridCellTemplate let-s>
|
||||
<button kendoButton fillMode="flat" *ngIf="s.status === 'Submitted'" (click)="reopenAndEdit(s)">Reopen & Edit</button>
|
||||
<button kendoButton fillMode="flat" *ngIf="s.status === 'Submitted'" (click)="reopenAndEdit(s)">Reopen &
|
||||
Edit</button>
|
||||
<button kendoButton fillMode="flat" *ngIf="s.status === 'Draft'" (click)="continueEditDraft(s)">Continue
|
||||
editing</button>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
</kendo-grid>
|
||||
</section>
|
||||
|
||||
<app-member-quick-add-dialog *ngIf="showQuickAdd"
|
||||
(created)="onMemberQuickCreated($event)"
|
||||
(cancelled)="showQuickAdd = false"></app-member-quick-add-dialog>
|
||||
</div>
|
||||
<app-member-quick-add-dialog *ngIf="showQuickAdd" (created)="onMemberQuickCreated($event)"
|
||||
(cancelled)="showQuickAdd = false"></app-member-quick-add-dialog>
|
||||
</div>
|
||||
+29
-8
@@ -1,11 +1,32 @@
|
||||
.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; }
|
||||
.page-header { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; }
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 1rem 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.section-title { font-size: 1rem; font-weight: 600; margin: 0 0 0.75rem; }
|
||||
|
||||
.warn { background: #fff3cd; padding: 0.5rem 1rem; border-radius: 4px; margin-bottom: 1rem; }
|
||||
.entry-row { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: flex-end; margin-bottom: 1rem; }
|
||||
.entry-row label { display: flex; flex-direction: column; gap: 0.25rem; }
|
||||
.entry-actions { display: flex; gap: 0.5rem; }
|
||||
.anon-chip { padding: 0.25rem 0.5rem; background: #eee; border-radius: 4px; }
|
||||
.reconcile { display: flex; gap: 1rem; align-items: flex-end; margin-top: 1rem; }
|
||||
.reconcile .ok { color: green; font-weight: 600; }
|
||||
.reconcile .bad { color: #c00; font-weight: 600; }
|
||||
.edit-banner { display: flex; align-items: center; gap: 1rem; background: #fff3cd; border-left: 4px solid #f0a500; padding: 0.5rem 1rem; border-radius: 4px; margin-bottom: 1rem; font-weight: 500; }
|
||||
.sessions-list { margin-top: 2rem; }
|
||||
|
||||
.ok { color: green; font-weight: 600; }
|
||||
.bad { color: #c00; font-weight: 600; }
|
||||
|
||||
.empty { color: #6b7280; padding: 1rem 0; }
|
||||
.lines-footer { margin-top: 0.5rem; color: #374151; font-weight: 500; }
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.badge--draft { background: #fef3c7; color: #92400e; }
|
||||
.badge--submitted { background: #dcfce7; color: #166534; }
|
||||
.badge--reconciled { background: #e2e8f0; color: #334155; }
|
||||
|
||||
+23
-1
@@ -87,6 +87,15 @@ export class OfferingSessionPageComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
// Already a Draft (e.g. a session reopened then left) — load it straight back in, no reopen.
|
||||
continueEditDraft(s: OfferingSessionListItemDto): void {
|
||||
if (s.status !== 'Draft') return;
|
||||
this.api.getById(s.id).subscribe({
|
||||
next: dto => this.loadIntoBuffer(dto),
|
||||
error: (err: { error?: { message?: string } }) => alert(err?.error?.message ?? 'Load failed.'),
|
||||
});
|
||||
}
|
||||
|
||||
private loadIntoBuffer(dto: OfferingSessionDto): void {
|
||||
this.editingSessionId = dto.id;
|
||||
this.sessionDate = new Date(dto.sessionDate + 'T00:00:00');
|
||||
@@ -110,6 +119,8 @@ export class OfferingSessionPageComponent implements OnInit {
|
||||
this.buffer = []; this.cashTotal = 0; this.checkTotal = 0; this.notes = null;
|
||||
this.sessionDate = new Date();
|
||||
this.checkDate();
|
||||
// The reopened session is now a server-side Draft — refresh so its "Continue editing" appears.
|
||||
this.loadSessions();
|
||||
}
|
||||
|
||||
onMemberFilter(term: string): void {
|
||||
@@ -130,6 +141,10 @@ export class OfferingSessionPageComponent implements OnInit {
|
||||
this.selectedMemberId = null; this.selectedMemberName = null;
|
||||
}
|
||||
|
||||
clearAnonymous(): void {
|
||||
this.entry.isAnonymous = false;
|
||||
}
|
||||
|
||||
addLine(): void {
|
||||
if (this.entry.amount <= 0) return;
|
||||
if (this.entry.paymentMethod === 'Check' && !this.entry.checkNumber) return;
|
||||
@@ -221,5 +236,12 @@ export class OfferingSessionPageComponent implements OnInit {
|
||||
};
|
||||
}
|
||||
|
||||
private toIso(d: Date): string { return d.toISOString().slice(0, 10); }
|
||||
// Format using LOCAL date components — NOT toISOString(), which converts to UTC and
|
||||
// rolls the date forward a day for behind-UTC users when the Date carries an evening time.
|
||||
private toIso(d: Date): string {
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${y}-${m}-${day}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="branding-section">
|
||||
<div class="branding-content">
|
||||
<div class="logo-container">
|
||||
<img src="assets/rbj-logo.svg" alt="RBJ Logo" class="logo-image">
|
||||
<img src="assets/images/ROLCC-Logo-Color.png" alt="ROLCC Logo" class="logo-image">
|
||||
<div class="logo-text">
|
||||
<h1>ROLCC AC</h1>
|
||||
<span class="tagline">Church Management Portal</span>
|
||||
|
||||
+14
-8
@@ -5,7 +5,8 @@
|
||||
<!-- TAB 1: Basic Info -->
|
||||
<kendo-tabstrip-tab title="Basic Info" [selected]="true">
|
||||
<ng-template kendoTabContent>
|
||||
<div class="k-form k-form-horizontal k-mt-4">
|
||||
<div class="k-form k-form-vertical k-mt-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Legal First Name *"></kendo-label>
|
||||
@@ -17,7 +18,7 @@
|
||||
<kendo-textbox formControlName="lastName_en"></kendo-textbox>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-formfield class="md:col-span-2">
|
||||
<kendo-label text="Nick Name (Common Name)"></kendo-label>
|
||||
<kendo-textbox formControlName="nickName" placeholder="e.g. Chris"></kendo-textbox>
|
||||
</kendo-formfield>
|
||||
@@ -63,6 +64,7 @@
|
||||
</kendo-dropdownlist>
|
||||
</kendo-formfield>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</kendo-tabstrip-tab>
|
||||
@@ -70,9 +72,10 @@
|
||||
<!-- TAB 2: Contact -->
|
||||
<kendo-tabstrip-tab title="Contact">
|
||||
<ng-template kendoTabContent>
|
||||
<div class="k-form k-form-horizontal k-mt-4">
|
||||
<div class="k-form k-form-vertical k-mt-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-formfield class="md:col-span-2">
|
||||
<kendo-label text="Email"></kendo-label>
|
||||
<kendo-textbox formControlName="email"></kendo-textbox>
|
||||
</kendo-formfield>
|
||||
@@ -87,7 +90,7 @@
|
||||
<kendo-textbox formControlName="phoneHome"></kendo-textbox>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-formfield class="md:col-span-2">
|
||||
<kendo-label text="Address"></kendo-label>
|
||||
<kendo-textbox formControlName="address"></kendo-textbox>
|
||||
</kendo-formfield>
|
||||
@@ -112,6 +115,7 @@
|
||||
<kendo-textbox formControlName="country"></kendo-textbox>
|
||||
</kendo-formfield>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</kendo-tabstrip-tab>
|
||||
@@ -119,7 +123,8 @@
|
||||
<!-- TAB 3: Church Info -->
|
||||
<kendo-tabstrip-tab title="Church Info">
|
||||
<ng-template kendoTabContent>
|
||||
<div class="k-form k-form-horizontal k-mt-4">
|
||||
<div class="k-form k-form-vertical k-mt-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Join Date"></kendo-label>
|
||||
@@ -131,16 +136,17 @@
|
||||
<kendo-datepicker formControlName="baptismDate"></kendo-datepicker>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-formfield class="md:col-span-2">
|
||||
<kendo-label text="Baptism Church"></kendo-label>
|
||||
<kendo-textbox formControlName="baptismChurch"></kendo-textbox>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-formfield class="md:col-span-2">
|
||||
<kendo-label text="Notes"></kendo-label>
|
||||
<kendo-textarea formControlName="notes" [rows]="4"></kendo-textarea>
|
||||
</kendo-formfield>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</kendo-tabstrip-tab>
|
||||
|
||||
+5
-3
@@ -1,5 +1,6 @@
|
||||
<kendo-dialog title="Add New User" (close)="onCancel()" [minWidth]="460" [width]="500">
|
||||
<form [formGroup]="form" class="k-form k-form-vertical k-p-2">
|
||||
<div class="grid grid-cols-1 gap-y-3">
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Email *"></kendo-label>
|
||||
@@ -8,14 +9,14 @@
|
||||
<kendo-formerror *ngIf="form.get('email')?.errors?.['email']">Invalid email.</kendo-formerror>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield class="k-mt-3">
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Roles *"></kendo-label>
|
||||
<kendo-multiselect formControlName="roles" [data]="roleOptions"
|
||||
placeholder="Select roles"></kendo-multiselect>
|
||||
<kendo-formerror>At least one role is required.</kendo-formerror>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield class="k-mt-3">
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Language"></kendo-label>
|
||||
<kendo-dropdownlist formControlName="languagePreference"
|
||||
[data]="langOptions" textField="text" valueField="value"
|
||||
@@ -23,12 +24,13 @@
|
||||
</kendo-dropdownlist>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield class="k-mt-3">
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Member ID (optional)"></kendo-label>
|
||||
<kendo-numerictextbox formControlName="memberId" [format]="'0'"
|
||||
placeholder="Link to a member record"></kendo-numerictextbox>
|
||||
</kendo-formfield>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<kendo-dialog-actions>
|
||||
|
||||
+5
-3
@@ -1,5 +1,6 @@
|
||||
<kendo-dialog title="Edit User" (close)="onCancel()" [minWidth]="460" [width]="500">
|
||||
<form [formGroup]="form" class="k-form k-form-vertical k-p-2">
|
||||
<div class="grid grid-cols-1 gap-y-3">
|
||||
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Email *"></kendo-label>
|
||||
@@ -8,13 +9,13 @@
|
||||
<kendo-formerror *ngIf="form.get('email')?.errors?.['email']">Invalid email.</kendo-formerror>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield class="k-mt-3">
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Roles *"></kendo-label>
|
||||
<kendo-multiselect formControlName="roles" [data]="roleOptions"
|
||||
placeholder="Select roles"></kendo-multiselect>
|
||||
</kendo-formfield>
|
||||
|
||||
<kendo-formfield class="k-mt-3">
|
||||
<kendo-formfield>
|
||||
<kendo-label text="Language"></kendo-label>
|
||||
<kendo-dropdownlist formControlName="languagePreference"
|
||||
[data]="langOptions" textField="text" valueField="value"
|
||||
@@ -22,11 +23,12 @@
|
||||
</kendo-dropdownlist>
|
||||
</kendo-formfield>
|
||||
|
||||
<div class="k-d-flex k-align-items-center k-gap-2 k-mt-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<input kendoCheckBox type="checkbox" formControlName="isActive" id="isActiveCheck" />
|
||||
<kendo-label for="isActiveCheck" text="Account Active"></kendo-label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<kendo-dialog-actions>
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
<aside class="sidebar" [class.collapsed]="sidebarCollapsed">
|
||||
<div class="sidebar-header">
|
||||
<div class="logo-section">
|
||||
<img src="assets/rbj-logo.svg" alt="RBJ Logo" class="logo-image">
|
||||
<img src="assets/images/ROLCC-Logo-Color.png" alt="ROLCC Logo" class="logo-image">
|
||||
<div class="logo-text" *ngIf="!sidebarCollapsed">
|
||||
<h2>ROLCC AC</h2>
|
||||
<span class="tagline">Escrow Portal</span>
|
||||
<span class="tagline">Church Portal</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="sidebar-toggle" (click)="toggleSidebar()" title="Toggle sidebar">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="token-verification-container">
|
||||
<div class="verification-card">
|
||||
<div class="logo-section">
|
||||
<img src="assets/rbj-logo.svg" alt="RBJ Logo" class="logo">
|
||||
<img src="assets/images/ROLCC-Logo-Color.png" alt="ROLCC Logo" class="logo">
|
||||
</div>
|
||||
|
||||
<div class="verification-content">
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Tailwind v4 — utilities + theme only. NO preflight: Kendo UI owns base element
|
||||
* styling and styles.scss already ships its own reset. Loading Tailwind's base reset
|
||||
* would fight Kendo.
|
||||
*
|
||||
* theme -> kept in its own layer (design tokens / CSS vars only, no output by itself)
|
||||
* utilities -> imported UNLAYERED so layout utilities (grid/col-span/gap/flex) reliably
|
||||
* win over Kendo's unlayered CDN theme when they ever land on the same node.
|
||||
*
|
||||
* Used by the shared form-layout convention: a neutral wrapper <div> carries
|
||||
* grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3
|
||||
* and full-width fields use md:col-span-2.
|
||||
*/
|
||||
@layer theme;
|
||||
@import "tailwindcss/theme.css" layer(theme);
|
||||
@import "tailwindcss/utilities.css";
|
||||
|
||||
/* Explicit source scanning (auto-detection also covers these). */
|
||||
@source "./";
|
||||
+4
-4
@@ -1315,12 +1315,12 @@ assets/i18n/zh-TW.json
|
||||
## 7. 開發階段規劃 (Roadmap)
|
||||
|
||||
### Phase 0 — 技術基礎 & DevOps (2–3 週)
|
||||
- [ ] Azure VM 建置 + Docker 環境
|
||||
- [X] Azure VM 建置 + Docker 環境
|
||||
- [ ] Gitea + Jenkins 啟動,CI pipeline 通
|
||||
- [ ] Angular + Capacitor 專案骨架(含 ngx-translate en/zh-TW)
|
||||
- [ ] ASP.NET Core API 骨架 + EF Core 初始 Migration
|
||||
- [ ] 認證系統(JWT + Refresh Token + ASP.NET Identity)
|
||||
- [ ] RBAC 框架(角色 + Ministry Scope middleware)
|
||||
- [X] ASP.NET Core API 骨架 + EF Core 初始 Migration
|
||||
- [X] 認證系統(JWT + Refresh Token + ASP.NET Identity)
|
||||
- [X] RBAC 框架(角色 + Ministry Scope middleware)
|
||||
- [ ] Audit Log 基礎建設
|
||||
- [ ] Mobile-first UI 元件庫設定(底部導覽、touch target 規範)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user