diff --git a/node_modules/.bin/baseline-browser-mapping b/node_modules/.bin/baseline-browser-mapping index d296188..1977474 120000 --- a/node_modules/.bin/baseline-browser-mapping +++ b/node_modules/.bin/baseline-browser-mapping @@ -1 +1,16 @@ -../baseline-browser-mapping/dist/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../baseline-browser-mapping/dist/cli.js" "$@" +else + exec node "$basedir/../baseline-browser-mapping/dist/cli.js" "$@" +fi diff --git a/node_modules/.bin/browserslist b/node_modules/.bin/browserslist index 3cd991b..60e71ad 120000 --- a/node_modules/.bin/browserslist +++ b/node_modules/.bin/browserslist @@ -1 +1,16 @@ -../browserslist/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../browserslist/cli.js" "$@" +else + exec node "$basedir/../browserslist/cli.js" "$@" +fi diff --git a/node_modules/.bin/esbuild b/node_modules/.bin/esbuild index c83ac07..63bb6d4 120000 --- a/node_modules/.bin/esbuild +++ b/node_modules/.bin/esbuild @@ -1 +1,16 @@ -../esbuild/bin/esbuild \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../esbuild/bin/esbuild" "$@" +else + exec node "$basedir/../esbuild/bin/esbuild" "$@" +fi diff --git a/node_modules/.bin/jsesc b/node_modules/.bin/jsesc index 7237604..879c413 120000 --- a/node_modules/.bin/jsesc +++ b/node_modules/.bin/jsesc @@ -1 +1,16 @@ -../jsesc/bin/jsesc \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../jsesc/bin/jsesc" "$@" +else + exec node "$basedir/../jsesc/bin/jsesc" "$@" +fi diff --git a/node_modules/.bin/json5 b/node_modules/.bin/json5 index 217f379..abf72a4 120000 --- a/node_modules/.bin/json5 +++ b/node_modules/.bin/json5 @@ -1 +1,16 @@ -../json5/lib/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../json5/lib/cli.js" "$@" +else + exec node "$basedir/../json5/lib/cli.js" "$@" +fi diff --git a/node_modules/.bin/loose-envify b/node_modules/.bin/loose-envify index ed9009c..076f91b 120000 --- a/node_modules/.bin/loose-envify +++ b/node_modules/.bin/loose-envify @@ -1 +1,16 @@ -../loose-envify/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../loose-envify/cli.js" "$@" +else + exec node "$basedir/../loose-envify/cli.js" "$@" +fi diff --git a/node_modules/.bin/nanoid b/node_modules/.bin/nanoid index e2be547..46220bd 120000 --- a/node_modules/.bin/nanoid +++ b/node_modules/.bin/nanoid @@ -1 +1,16 @@ -../nanoid/bin/nanoid.cjs \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../nanoid/bin/nanoid.cjs" "$@" +else + exec node "$basedir/../nanoid/bin/nanoid.cjs" "$@" +fi diff --git a/node_modules/.bin/parser b/node_modules/.bin/parser index ce7bf97..7696ad4 120000 --- a/node_modules/.bin/parser +++ b/node_modules/.bin/parser @@ -1 +1,16 @@ -../@babel/parser/bin/babel-parser.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../@babel/parser/bin/babel-parser.js" "$@" +else + exec node "$basedir/../@babel/parser/bin/babel-parser.js" "$@" +fi diff --git a/node_modules/.bin/rollup b/node_modules/.bin/rollup index 5939621..998fc16 120000 --- a/node_modules/.bin/rollup +++ b/node_modules/.bin/rollup @@ -1 +1,16 @@ -../rollup/dist/bin/rollup \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../rollup/dist/bin/rollup" "$@" +else + exec node "$basedir/../rollup/dist/bin/rollup" "$@" +fi diff --git a/node_modules/.bin/semver b/node_modules/.bin/semver index 5aaadf4..97c5327 120000 --- a/node_modules/.bin/semver +++ b/node_modules/.bin/semver @@ -1 +1,16 @@ -../semver/bin/semver.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../semver/bin/semver.js" "$@" +else + exec node "$basedir/../semver/bin/semver.js" "$@" +fi diff --git a/node_modules/.bin/update-browserslist-db b/node_modules/.bin/update-browserslist-db index b11e16f..cced63c 120000 --- a/node_modules/.bin/update-browserslist-db +++ b/node_modules/.bin/update-browserslist-db @@ -1 +1,16 @@ -../update-browserslist-db/cli.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../update-browserslist-db/cli.js" "$@" +else + exec node "$basedir/../update-browserslist-db/cli.js" "$@" +fi diff --git a/node_modules/.bin/vite b/node_modules/.bin/vite index 6d1e3be..014463f 120000 --- a/node_modules/.bin/vite +++ b/node_modules/.bin/vite @@ -1 +1,16 @@ -../vite/bin/vite.js \ No newline at end of file +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) + if command -v cygpath > /dev/null 2>&1; then + basedir=`cygpath -w "$basedir"` + fi + ;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@" +else + exec node "$basedir/../vite/bin/vite.js" "$@" +fi diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 7ab0de3..8d2c1bb 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -32,6 +32,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -275,17 +276,17 @@ "node": ">=6.9.0" } }, - "node_modules/@esbuild/darwin-arm64": { + "node_modules/@esbuild/win32-x64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ - "arm64" + "x64" ], "dev": true, "optional": true, "os": [ - "darwin" + "win32" ], "engines": { "node": ">=12" @@ -350,17 +351,30 @@ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", "dev": true }, - "node_modules/@rollup/rollup-darwin-arm64": { + "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.53.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.5.tgz", - "integrity": "sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.5.tgz", + "integrity": "sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==", "cpu": [ - "arm64" + "x64" ], "dev": true, "optional": true, "os": [ - "darwin" + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.5.tgz", + "integrity": "sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" ] }, "node_modules/@tabler/icons": { @@ -447,6 +461,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "dev": true, + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -523,6 +538,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -799,20 +815,6 @@ } } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1133,6 +1135,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -1144,6 +1147,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -1299,7 +1303,8 @@ "version": "0.182.0", "resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz", "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tr46": { "version": "0.0.3", @@ -1347,6 +1352,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/node_modules/esbuild/bin/esbuild b/node_modules/esbuild/bin/esbuild index e81b7da..971ac09 100755 Binary files a/node_modules/esbuild/bin/esbuild and b/node_modules/esbuild/bin/esbuild differ diff --git a/package-lock.json b/package-lock.json index e19e3dc..18d5b38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1096,6 +1097,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "dev": true, + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -1172,6 +1174,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -1782,6 +1785,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -1793,6 +1797,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -1948,7 +1953,8 @@ "version": "0.182.0", "resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz", "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tr46": { "version": "0.0.3", @@ -1996,6 +2002,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/src/components/CopyableCredential.jsx b/src/components/CopyableCredential.jsx new file mode 100644 index 0000000..510cae4 --- /dev/null +++ b/src/components/CopyableCredential.jsx @@ -0,0 +1,85 @@ +import { useState } from 'react' +import { FaEye, FaEyeSlash, FaCheck } from 'react-icons/fa6' + +/** + * Anzeige mit Auge: Klick kopiert den Wert und schaltet Sichtbarkeit um. + */ +export default function CopyableCredential({ value }) { + const [visible, setVisible] = useState(false) + const [copied, setCopied] = useState(false) + const text = (value || '').trim() + + if (!text) { + return + } + + const handleClick = async (e) => { + e.preventDefault() + e.stopPropagation() + setVisible((v) => !v) + try { + await navigator.clipboard.writeText(text) + } catch { + const ta = document.createElement('textarea') + ta.value = text + ta.setAttribute('readonly', '') + ta.style.position = 'fixed' + ta.style.left = '-9999px' + document.body.appendChild(ta) + ta.select() + document.execCommand('copy') + document.body.removeChild(ta) + } + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + const masked = '•'.repeat(Math.min(Math.max(text.length, 8), 16)) + const display = visible ? text : masked + + return ( + + + {display} + + + + ) +} + +export function getCustomerPortalPassword(customer) { + return customer?.portalPassword || customer?.password || '' +} diff --git a/src/hooks/useCustomers.js b/src/hooks/useCustomers.js index 55cde48..5a09d64 100644 --- a/src/hooks/useCustomers.js +++ b/src/hooks/useCustomers.js @@ -54,8 +54,12 @@ export function useCustomers() { const createCustomer = async (data) => { if (DEMO_MODE) { - const { password: _pw, ...rest } = data - const newCustomer = { ...rest, $id: Date.now().toString() } + const { password, ...rest } = data + const newCustomer = { + ...rest, + portalPassword: password || rest.portalPassword || '', + $id: Date.now().toString(), + } setCustomers(prev => [...prev, newCustomer]) return { success: true, data: newCustomer } } @@ -63,7 +67,10 @@ export function useCustomers() { try { const { password, ...fields } = data const result = await createCustomerWithPortalAccess({ ...fields, password }) - const customer = result.customer + const customer = { + ...result.customer, + portalPassword: result.customer?.portalPassword || password || '', + } setCustomers(prev => [...prev, customer]) return { success: true, data: customer } } catch (err) { @@ -73,8 +80,15 @@ export function useCustomers() { const updateCustomer = async (id, data) => { if (DEMO_MODE) { - const { password: _pw, ...rest } = data - setCustomers(prev => prev.map(c => c.$id === id ? { ...c, ...rest } : c)) + const { password, ...rest } = data + setCustomers(prev => + prev.map(c => { + if (c.$id !== id) return c + const next = { ...c, ...rest } + if (password) next.portalPassword = password + return next + }) + ) return { success: true } } @@ -84,8 +98,22 @@ export function useCustomers() { if (password) payload.password = password const result = await updateCustomerWithPortalAccess(id, payload) - const customer = result.customer - setCustomers(prev => prev.map(c => c.$id === id ? customer : c)) + const customer = { + ...result.customer, + portalPassword: + result.customer?.portalPassword || + password || + undefined, + } + setCustomers(prev => + prev.map(c => { + if (c.$id !== id) return c + return { + ...customer, + portalPassword: customer.portalPassword ?? c.portalPassword, + } + }) + ) return { success: true, data: customer } } catch (err) { return { success: false, error: err.message } diff --git a/src/pages/AdminPage.jsx b/src/pages/AdminPage.jsx index ba44e68..ab82ba8 100644 --- a/src/pages/AdminPage.jsx +++ b/src/pages/AdminPage.jsx @@ -5,6 +5,7 @@ import { useCustomers } from '../hooks/useCustomers' import { useEmployees } from '../hooks/useEmployees' import { FaPlus, FaTrash, FaFloppyDisk, FaSpinner } from 'react-icons/fa6' import { FaEdit } from 'react-icons/fa' +import CopyableCredential, { getCustomerPortalPassword } from '../components/CopyableCredential' export default function AdminPage() { const { user, isAdmin } = useAuth() @@ -398,6 +399,7 @@ export default function AdminPage() { Name Location Email + Passwort Phone Portal Aktionen @@ -499,7 +501,12 @@ export default function AdminPage() { {customer.code || '-'} {customer.name || '-'} {customer.location || '-'} - {customer.email || '-'} + + + + + + {customer.phone || '-'} {customer.portalAccessEnabled ? (