diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..56d1fb8e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules +.next +npm-debug.log +Dockerfile +docker-compose.yml +.git +.gitignore +README.md diff --git a/.env b/.env new file mode 100644 index 00000000..1e00b870 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +NEXT_PUBLIC_MAPS_AUTOCOMPLETE_API = 'AIzaSyAxBDdnJsmCX-zQa-cO9iy-v5pn53vXEFA' +NEXT_PUBLIC_NEW_API_URL = 'https://platform.v2-dev.flexabledats.com/api/v1.0' +NEXT_PUBLIC_NFT_STORAGE_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGY3MTE1ZTI3NEZCQkRjNEMxMTg0NTU4M2RkNDgyZmY4Y2ZBNjg1MWYiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTY2NDM3MDM3NTI4NCwibmFtZSI6IkZsZXhhYmxlIn0.KdNTTPilIqY9DS3KMVDqMuYUBpUsfi0fvWtztQYQwew' +NEXT_PUBLIC_AUTH = 'https://auth.staging.flexabledats.com' +NEXT_PUBLIC_NFT_STORAGE_PREFIX_URL = https://nftstorage.link/ipfs +NEXT_PUBLIC_PROJECT_ID=e5e3cd7248034842bf2c5ea640676e48 + diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0ee25142..3ede49c8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -29,11 +29,20 @@ jobs: - name: NextJS Build run: | - npm ci - if [ "$GITHUB_REF_NAME" = main ]; then echo $DEV_ENV_FILE | base64 --decode > .env; fi - if [ "$GITHUB_REF_NAME" = staging ]; then echo $STAGING_ENV_FILE | base64 --decode > .env; fi - if [ "$GITHUB_REF_NAME" = prod ]; then echo $PROD_ENV_FILE | base64 --decode > .env; fi - npm run build + npm install --legacy-peer-deps + if [ "$GITHUB_REF_NAME" = "main" ]; then + echo "$DEV_ENV_FILE" | base64 --decode > .env + elif [ "$GITHUB_REF_NAME" = "staging" ]; then + echo "$STAGING_ENV_FILE" | base64 --decode > .env + elif [ "$GITHUB_REF_NAME" = "prod" ]; then + echo "$PROD_ENV_FILE" | base64 --decode > .env + else + echo "Invalid branch: $GITHUB_REF_NAME" + exit 1 + fi + + echo "Environment file content:" + cat .env env: DEV_ENV_FILE: ${{secrets.DEV_ENV_FILE}} STAGING_ENV_FILE: ${{secrets.STAGING_ENV_FILE}} @@ -47,19 +56,35 @@ jobs: .next public .env - retention-days: 0 # artifact retention duration, can be upto 30 days + retention-days: 1 # artifact retention duration, can be upto 30 days ghcr-push: - name: + name: Push Image to GHCR needs: next-build # Job depends on next-build(above) job runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout source + uses: actions/checkout@v3 - - name: Download next build # Download the above uploaded artifact - uses: actions/download-artifact@v4 with: - name: build + fetch-depth: 0 + + - name: Setup environment file based on branch + run: | + echo "Branch detected: $GITHUB_REF_NAME" + if [ "$GITHUB_REF_NAME" = "main" ]; then + echo "$DEV_ENV_FILE" | base64 -d > .env + elif [ "$GITHUB_REF_NAME" = "staging" ]; then + echo "$STAGING_ENV_FILE" | base64 -d > .env + elif [ "$GITHUB_REF_NAME" = "prod" ]; then + echo "$PROD_ENV_FILE" | base64 -d > .env + fi + echo "Generated .env file:" + cat .env + env: + DEV_ENV_FILE: ${{ secrets.DEV_ENV_FILE }} + STAGING_ENV_FILE: ${{ secrets.STAGING_ENV_FILE }} + PROD_ENV_FILE: ${{ secrets.PROD_ENV_FILE }} + - name: Login to GitHub Container Registry uses: docker/login-action@v2 @@ -128,4 +153,4 @@ jobs: sudo podman pull ghcr.io/weareflexable/portal:prod sudo podman stop portal sudo podman rm portal - sudo podman run --name="portal" -p 9083:3000 -d ghcr.io/weareflexable/portal:prod + sudo podman run --name="portal" -p 9083:3000 -d ghcr.io/weareflexable/portal:prod \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..00ad71fb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib" +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 7b1a70eb..c8725158 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,56 +1,51 @@ -# Install dependencies only when needed -FROM node:18-alpine AS deps -# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. -RUN apk add --no-cache libc6-compat -WORKDIR /app -COPY package.json yarn.lock ./ -RUN yarn install --frozen-lockfile +# --- Step 1: Build Stage --- +FROM node:16-bullseye AS builder -# If using npm with a `package-lock.json` comment out above and use below instead -# COPY package.json package-lock.json ./ -# RUN npm ci +# Install system dependencies for native modules +RUN apt-get update && apt-get install -y \ + python3 \ + make \ + g++ \ + build-essential -# Rebuild the source code only when needed -FROM node:16-alpine AS builder WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules + + +# Copy package files first for better caching +COPY package*.json ./ + +# Force install legacy peer deps (important for AntD 5 + Chakra + Next.js) +RUN npm config set legacy-peer-deps true +RUN npm ci + + +# After npm install +RUN npm install && npm run postinstall +# Copy rest of the application code COPY . . -# Next.js collects completely anonymous telemetry data about general usage. -# Learn more here: https://nextjs.org/telemetry -# Uncomment the following line in case you want to disable telemetry during the build. -# ENV NEXT_TELEMETRY_DISABLED 1 +# Before build +COPY .env .env +# Ensure TypeScript builds correctly +RUN npm run build -RUN yarn build +# --- Step 2: Production Runner Stage --- +FROM node:18-alpine AS runner -# If using npm comment out above and use below instead -# RUN npm run build -# Production image, copy all the files and run next -FROM node:16-alpine AS runner WORKDIR /app -ENV NODE_ENV production -# Uncomment the following line in case you want to disable telemetry during runtime. -# ENV NEXT_TELEMETRY_DISABLED 1 - -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs +# Only copy what’s needed to run -# You only need to copy next.config.js if you are NOT using the default configuration -# COPY --from=builder /app/next.config.js ./ +COPY --from=builder /app/.next ./.next COPY --from=builder /app/public ./public COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/next.config.js ./next.config.js -# Automatically leverage output traces to reduce image size -# https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ -COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static - -USER nextjs +ENV NODE_ENV=production EXPOSE 3000 -ENV PORT 3000 - -CMD ["node", "server.js"] +# Use node instead of npm (better control) +CMD ["node", "node_modules/next/dist/bin/next", "start"] diff --git a/analyze/FlexableVendor.json b/analyze/FlexableVendor.json new file mode 100644 index 00000000..eea1ead9 --- /dev/null +++ b/analyze/FlexableVendor.json @@ -0,0 +1,596 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "FlexableVendor", + "sourceName": "contracts/FlexableVendor.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_flexableAuthAddr", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC721IncorrectOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ERC721InsufficientApproval", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC721InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "ERC721InvalidOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC721InvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC721InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC721InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ERC721NonexistentToken", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "serviceMetadata", + "type": "string" + } + ], + "name": "VendorCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "burnVendor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_uri", + "type": "string" + } + ], + "name": "createVendor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "isVendorActive", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_uri", + "type": "string" + } + ], + "name": "setTokenURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenIdToVendorWallet", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_wallet", + "type": "address" + } + ], + "name": "updateVendorWallet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052600160075534801561001557600080fd5b5060405161175a38038061175a833981016040819052610034916100c3565b6040518060400160405280600e81526020016d233632bc30b13632ab32b73237b960911b8152506040518060400160405280600a815260200169232622ac2b22a72227a960b11b815250816000908161008d9190610194565b50600161009a8282610194565b5050600680546001600160a01b0319166001600160a01b03939093169290921790915550610253565b6000602082840312156100d557600080fd5b81516001600160a01b03811681146100ec57600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061011d57607f821691505b60208210810361013d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561018f576000816000526020600020601f850160051c8101602086101561016c5750805b601f850160051c820191505b8181101561018b57828155600101610178565b5050505b505050565b81516001600160401b038111156101ad576101ad6100f3565b6101c1816101bb8454610109565b84610143565b602080601f8311600181146101f657600084156101de5750858301515b600019600386901b1c1916600185901b17855561018b565b600085815260208120601f198616915b8281101561022557888601518255948401946001909101908401610206565b50858210156102435787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6114f8806102626000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c80636352211e116100ad578063a22cb46511610071578063a22cb46514610277578063b88d4fde1461028a578063c87b56dd1461029d578063d051f262146102b0578063e985e9c5146102d957600080fd5b80636352211e146102025780636e80a01b1461021557806370a082311461023b57806395d89b411461025c57806399dd15471461026457600080fd5b8063095ea7b3116100f4578063095ea7b3146101a357806314426bc2146101b6578063162094c4146101c957806323b872dd146101dc57806342842e0e146101ef57600080fd5b806301ffc9a71461012657806303b4c26f1461014e57806306fdde0314610163578063081812fc14610178575b600080fd5b610139610134366004610efb565b6102ec565b60405190151581526020015b60405180910390f35b61016161015c366004610f1f565b61033e565b005b61016b61039f565b6040516101459190610f7e565b61018b610186366004610f1f565b610431565b6040516001600160a01b039091168152602001610145565b6101616101b1366004610fad565b61045a565b6101616101c4366004610fd7565b610469565b6101616101d73660046110af565b6104e7565b6101616101ea3660046110f6565b6105bc565b6101616101fd3660046110f6565b610647565b61018b610210366004610f1f565b610662565b610139610223366004610f1f565b60009081526009602052604090206003015460ff1690565b61024e610249366004611132565b61066d565b604051908152602001610145565b61016b6106b5565b61016161027236600461114d565b6106c4565b6101616102853660046111cf565b61084b565b610161610298366004611206565b610856565b61016b6102ab366004610f1f565b61086d565b61018b6102be366004610f1f565b6000908152600960205260409020546001600160a01b031690565b6101396102e7366004611282565b61090f565b60006001600160e01b031982166380ac58cd60e01b148061031d57506001600160e01b03198216635b5e139f60e01b145b8061033857506301ffc9a760e01b6001600160e01b03198316145b92915050565b3361034882610662565b6001600160a01b0316146103935760405162461bcd60e51b815260206004820152600d60248201526c2737ba103a34329037bbb732b960991b60448201526064015b60405180910390fd5b61039c8161093d565b50565b6060600080546103ae906112ac565b80601f01602080910402602001604051908101604052809291908181526020018280546103da906112ac565b80156104275780601f106103fc57610100808354040283529160200191610427565b820191906000526020600020905b81548152906001019060200180831161040a57829003601f168201915b5050505050905090565b600061043c82610978565b506000828152600460205260409020546001600160a01b0316610338565b6104658282336109b1565b5050565b3361047383610662565b6001600160a01b0316146104b95760405162461bcd60e51b815260206004820152600d60248201526c2737ba103a34329027bbb732b960991b604482015260640161038a565b60009182526009602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561053d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056191906112e6565b61059f5760405162461bcd60e51b815260206004820152600f60248201526e2737ba1030b71037b832b930ba37b960891b604482015260640161038a565b60008281526008602052604090206105b78282611353565b505050565b6001600160a01b0382166105e657604051633250574960e11b81526000600482015260240161038a565b60006105f38383336109be565b9050836001600160a01b0316816001600160a01b031614610641576040516364283d7b60e01b81526001600160a01b038086166004830152602482018490528216604482015260640161038a565b50505050565b6105b783838360405180602001604052806000815250610856565b600061033882610978565b60006001600160a01b038216610699576040516322718ad960e21b81526000600482015260240161038a565b506001600160a01b031660009081526003602052604090205490565b6060600180546103ae906112ac565b6106cd8361066d565b156107135760405162461bcd60e51b815260206004820152601660248201527515995b991bdc88185b1c9958591e4818dc99585d195960521b604482015260640161038a565b6007546107208482610ab7565b60008181526008602052604090206107388382611353565b506040805160a0810182526001600160a01b0386811682526020808301878152838501879052600160608501819052600060808601819052878152600990935294909120835181546001600160a01b03191693169290921782555191929091908201906107a59082611353565b50604082015160028201906107ba9082611353565b5060608201516003909101805460809093015115156101000261ff00199215159290921661ffff1990931692909217179055600780549060006107fc83611413565b919050555080846001600160a01b03167f5ae5aaf61746d686646c5bae215acafc2afef0869a64bd75dc2f89fec7c60f7d858560405161083d92919061143a565b60405180910390a350505050565b610465338383610ad1565b6108618484846105bc565b61064184848484610b70565b600081815260086020526040902080546060919061088a906112ac565b80601f01602080910402602001604051908101604052809291908181526020018280546108b6906112ac565b80156109035780601f106108d857610100808354040283529160200191610903565b820191906000526020600020905b8154815290600101906020018083116108e657829003601f168201915b50505050509050919050565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600061094c60008360006109be565b90506001600160a01b03811661046557604051637e27328960e01b81526004810183905260240161038a565b6000818152600260205260408120546001600160a01b03168061033857604051637e27328960e01b81526004810184905260240161038a565b6105b78383836001610c99565b6000828152600260205260408120546001600160a01b03908116908316156109eb576109eb818486610d9f565b6001600160a01b03811615610a2957610a08600085600080610c99565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610a58576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b610465828260405180602001604052806000815250610e03565b6001600160a01b038216610b0357604051630b61174360e31b81526001600160a01b038316600482015260240161038a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561064157604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610bb2903390889087908790600401611468565b6020604051808303816000875af1925050508015610bed575060408051601f3d908101601f19168201909252610bea918101906114a5565b60015b610c56573d808015610c1b576040519150601f19603f3d011682016040523d82523d6000602084013e610c20565b606091505b508051600003610c4e57604051633250574960e11b81526001600160a01b038516600482015260240161038a565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610c9257604051633250574960e11b81526001600160a01b038516600482015260240161038a565b5050505050565b8080610cad57506001600160a01b03821615155b15610d6f576000610cbd84610978565b90506001600160a01b03831615801590610ce95750826001600160a01b0316816001600160a01b031614155b8015610cfc5750610cfa818461090f565b155b15610d255760405163a9fbf51f60e01b81526001600160a01b038416600482015260240161038a565b8115610d6d5783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b610daa838383610e1a565b6105b7576001600160a01b038316610dd857604051637e27328960e01b81526004810182905260240161038a565b60405163177e802f60e01b81526001600160a01b03831660048201526024810182905260440161038a565b610e0d8383610e80565b6105b76000848484610b70565b60006001600160a01b03831615801590610e785750826001600160a01b0316846001600160a01b03161480610e545750610e54848461090f565b80610e7857506000828152600460205260409020546001600160a01b038481169116145b949350505050565b6001600160a01b038216610eaa57604051633250574960e11b81526000600482015260240161038a565b6000610eb8838360006109be565b90506001600160a01b038116156105b7576040516339e3563760e11b81526000600482015260240161038a565b6001600160e01b03198116811461039c57600080fd5b600060208284031215610f0d57600080fd5b8135610f1881610ee5565b9392505050565b600060208284031215610f3157600080fd5b5035919050565b6000815180845260005b81811015610f5e57602081850181015186830182015201610f42565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610f186020830184610f38565b80356001600160a01b0381168114610fa857600080fd5b919050565b60008060408385031215610fc057600080fd5b610fc983610f91565b946020939093013593505050565b60008060408385031215610fea57600080fd5b82359150610ffa60208401610f91565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111561103457611034611003565b604051601f8501601f19908116603f0116810190828211818310171561105c5761105c611003565b8160405280935085815286868601111561107557600080fd5b858560208301376000602087830101525050509392505050565b600082601f8301126110a057600080fd5b610f1883833560208501611019565b600080604083850312156110c257600080fd5b82359150602083013567ffffffffffffffff8111156110e057600080fd5b6110ec8582860161108f565b9150509250929050565b60008060006060848603121561110b57600080fd5b61111484610f91565b925061112260208501610f91565b9150604084013590509250925092565b60006020828403121561114457600080fd5b610f1882610f91565b60008060006060848603121561116257600080fd5b61116b84610f91565b9250602084013567ffffffffffffffff8082111561118857600080fd5b6111948783880161108f565b935060408601359150808211156111aa57600080fd5b506111b78682870161108f565b9150509250925092565b801515811461039c57600080fd5b600080604083850312156111e257600080fd5b6111eb83610f91565b915060208301356111fb816111c1565b809150509250929050565b6000806000806080858703121561121c57600080fd5b61122585610f91565b935061123360208601610f91565b925060408501359150606085013567ffffffffffffffff81111561125657600080fd5b8501601f8101871361126757600080fd5b61127687823560208401611019565b91505092959194509250565b6000806040838503121561129557600080fd5b61129e83610f91565b9150610ffa60208401610f91565b600181811c908216806112c057607f821691505b6020821081036112e057634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156112f857600080fd5b8151610f18816111c1565b601f8211156105b7576000816000526020600020601f850160051c8101602086101561132c5750805b601f850160051c820191505b8181101561134b57828155600101611338565b505050505050565b815167ffffffffffffffff81111561136d5761136d611003565b6113818161137b84546112ac565b84611303565b602080601f8311600181146113b6576000841561139e5750858301515b600019600386901b1c1916600185901b17855561134b565b600085815260208120601f198616915b828110156113e5578886015182559484019460019091019084016113c6565b50858210156114035787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006001820161143357634e487b7160e01b600052601160045260246000fd5b5060010190565b60408152600061144d6040830185610f38565b828103602084015261145f8185610f38565b95945050505050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061149b90830184610f38565b9695505050505050565b6000602082840312156114b757600080fd5b8151610f1881610ee556fea2646970667358221220a216c6367cb6a8aed9f02f487f4a12c8ada9154ed3ae81a03fa577341ef0a1a964736f6c63430008190033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101215760003560e01c80636352211e116100ad578063a22cb46511610071578063a22cb46514610277578063b88d4fde1461028a578063c87b56dd1461029d578063d051f262146102b0578063e985e9c5146102d957600080fd5b80636352211e146102025780636e80a01b1461021557806370a082311461023b57806395d89b411461025c57806399dd15471461026457600080fd5b8063095ea7b3116100f4578063095ea7b3146101a357806314426bc2146101b6578063162094c4146101c957806323b872dd146101dc57806342842e0e146101ef57600080fd5b806301ffc9a71461012657806303b4c26f1461014e57806306fdde0314610163578063081812fc14610178575b600080fd5b610139610134366004610efb565b6102ec565b60405190151581526020015b60405180910390f35b61016161015c366004610f1f565b61033e565b005b61016b61039f565b6040516101459190610f7e565b61018b610186366004610f1f565b610431565b6040516001600160a01b039091168152602001610145565b6101616101b1366004610fad565b61045a565b6101616101c4366004610fd7565b610469565b6101616101d73660046110af565b6104e7565b6101616101ea3660046110f6565b6105bc565b6101616101fd3660046110f6565b610647565b61018b610210366004610f1f565b610662565b610139610223366004610f1f565b60009081526009602052604090206003015460ff1690565b61024e610249366004611132565b61066d565b604051908152602001610145565b61016b6106b5565b61016161027236600461114d565b6106c4565b6101616102853660046111cf565b61084b565b610161610298366004611206565b610856565b61016b6102ab366004610f1f565b61086d565b61018b6102be366004610f1f565b6000908152600960205260409020546001600160a01b031690565b6101396102e7366004611282565b61090f565b60006001600160e01b031982166380ac58cd60e01b148061031d57506001600160e01b03198216635b5e139f60e01b145b8061033857506301ffc9a760e01b6001600160e01b03198316145b92915050565b3361034882610662565b6001600160a01b0316146103935760405162461bcd60e51b815260206004820152600d60248201526c2737ba103a34329037bbb732b960991b60448201526064015b60405180910390fd5b61039c8161093d565b50565b6060600080546103ae906112ac565b80601f01602080910402602001604051908101604052809291908181526020018280546103da906112ac565b80156104275780601f106103fc57610100808354040283529160200191610427565b820191906000526020600020905b81548152906001019060200180831161040a57829003601f168201915b5050505050905090565b600061043c82610978565b506000828152600460205260409020546001600160a01b0316610338565b6104658282336109b1565b5050565b3361047383610662565b6001600160a01b0316146104b95760405162461bcd60e51b815260206004820152600d60248201526c2737ba103a34329027bbb732b960991b604482015260640161038a565b60009182526009602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561053d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056191906112e6565b61059f5760405162461bcd60e51b815260206004820152600f60248201526e2737ba1030b71037b832b930ba37b960891b604482015260640161038a565b60008281526008602052604090206105b78282611353565b505050565b6001600160a01b0382166105e657604051633250574960e11b81526000600482015260240161038a565b60006105f38383336109be565b9050836001600160a01b0316816001600160a01b031614610641576040516364283d7b60e01b81526001600160a01b038086166004830152602482018490528216604482015260640161038a565b50505050565b6105b783838360405180602001604052806000815250610856565b600061033882610978565b60006001600160a01b038216610699576040516322718ad960e21b81526000600482015260240161038a565b506001600160a01b031660009081526003602052604090205490565b6060600180546103ae906112ac565b6106cd8361066d565b156107135760405162461bcd60e51b815260206004820152601660248201527515995b991bdc88185b1c9958591e4818dc99585d195960521b604482015260640161038a565b6007546107208482610ab7565b60008181526008602052604090206107388382611353565b506040805160a0810182526001600160a01b0386811682526020808301878152838501879052600160608501819052600060808601819052878152600990935294909120835181546001600160a01b03191693169290921782555191929091908201906107a59082611353565b50604082015160028201906107ba9082611353565b5060608201516003909101805460809093015115156101000261ff00199215159290921661ffff1990931692909217179055600780549060006107fc83611413565b919050555080846001600160a01b03167f5ae5aaf61746d686646c5bae215acafc2afef0869a64bd75dc2f89fec7c60f7d858560405161083d92919061143a565b60405180910390a350505050565b610465338383610ad1565b6108618484846105bc565b61064184848484610b70565b600081815260086020526040902080546060919061088a906112ac565b80601f01602080910402602001604051908101604052809291908181526020018280546108b6906112ac565b80156109035780601f106108d857610100808354040283529160200191610903565b820191906000526020600020905b8154815290600101906020018083116108e657829003601f168201915b50505050509050919050565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600061094c60008360006109be565b90506001600160a01b03811661046557604051637e27328960e01b81526004810183905260240161038a565b6000818152600260205260408120546001600160a01b03168061033857604051637e27328960e01b81526004810184905260240161038a565b6105b78383836001610c99565b6000828152600260205260408120546001600160a01b03908116908316156109eb576109eb818486610d9f565b6001600160a01b03811615610a2957610a08600085600080610c99565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615610a58576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b610465828260405180602001604052806000815250610e03565b6001600160a01b038216610b0357604051630b61174360e31b81526001600160a01b038316600482015260240161038a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561064157604051630a85bd0160e11b81526001600160a01b0384169063150b7a0290610bb2903390889087908790600401611468565b6020604051808303816000875af1925050508015610bed575060408051601f3d908101601f19168201909252610bea918101906114a5565b60015b610c56573d808015610c1b576040519150601f19603f3d011682016040523d82523d6000602084013e610c20565b606091505b508051600003610c4e57604051633250574960e11b81526001600160a01b038516600482015260240161038a565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b14610c9257604051633250574960e11b81526001600160a01b038516600482015260240161038a565b5050505050565b8080610cad57506001600160a01b03821615155b15610d6f576000610cbd84610978565b90506001600160a01b03831615801590610ce95750826001600160a01b0316816001600160a01b031614155b8015610cfc5750610cfa818461090f565b155b15610d255760405163a9fbf51f60e01b81526001600160a01b038416600482015260240161038a565b8115610d6d5783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b610daa838383610e1a565b6105b7576001600160a01b038316610dd857604051637e27328960e01b81526004810182905260240161038a565b60405163177e802f60e01b81526001600160a01b03831660048201526024810182905260440161038a565b610e0d8383610e80565b6105b76000848484610b70565b60006001600160a01b03831615801590610e785750826001600160a01b0316846001600160a01b03161480610e545750610e54848461090f565b80610e7857506000828152600460205260409020546001600160a01b038481169116145b949350505050565b6001600160a01b038216610eaa57604051633250574960e11b81526000600482015260240161038a565b6000610eb8838360006109be565b90506001600160a01b038116156105b7576040516339e3563760e11b81526000600482015260240161038a565b6001600160e01b03198116811461039c57600080fd5b600060208284031215610f0d57600080fd5b8135610f1881610ee5565b9392505050565b600060208284031215610f3157600080fd5b5035919050565b6000815180845260005b81811015610f5e57602081850181015186830182015201610f42565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610f186020830184610f38565b80356001600160a01b0381168114610fa857600080fd5b919050565b60008060408385031215610fc057600080fd5b610fc983610f91565b946020939093013593505050565b60008060408385031215610fea57600080fd5b82359150610ffa60208401610f91565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111561103457611034611003565b604051601f8501601f19908116603f0116810190828211818310171561105c5761105c611003565b8160405280935085815286868601111561107557600080fd5b858560208301376000602087830101525050509392505050565b600082601f8301126110a057600080fd5b610f1883833560208501611019565b600080604083850312156110c257600080fd5b82359150602083013567ffffffffffffffff8111156110e057600080fd5b6110ec8582860161108f565b9150509250929050565b60008060006060848603121561110b57600080fd5b61111484610f91565b925061112260208501610f91565b9150604084013590509250925092565b60006020828403121561114457600080fd5b610f1882610f91565b60008060006060848603121561116257600080fd5b61116b84610f91565b9250602084013567ffffffffffffffff8082111561118857600080fd5b6111948783880161108f565b935060408601359150808211156111aa57600080fd5b506111b78682870161108f565b9150509250925092565b801515811461039c57600080fd5b600080604083850312156111e257600080fd5b6111eb83610f91565b915060208301356111fb816111c1565b809150509250929050565b6000806000806080858703121561121c57600080fd5b61122585610f91565b935061123360208601610f91565b925060408501359150606085013567ffffffffffffffff81111561125657600080fd5b8501601f8101871361126757600080fd5b61127687823560208401611019565b91505092959194509250565b6000806040838503121561129557600080fd5b61129e83610f91565b9150610ffa60208401610f91565b600181811c908216806112c057607f821691505b6020821081036112e057634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156112f857600080fd5b8151610f18816111c1565b601f8211156105b7576000816000526020600020601f850160051c8101602086101561132c5750805b601f850160051c820191505b8181101561134b57828155600101611338565b505050505050565b815167ffffffffffffffff81111561136d5761136d611003565b6113818161137b84546112ac565b84611303565b602080601f8311600181146113b6576000841561139e5750858301515b600019600386901b1c1916600185901b17855561134b565b600085815260208120601f198616915b828110156113e5578886015182559484019460019091019084016113c6565b50858210156114035787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006001820161143357634e487b7160e01b600052601160045260246000fd5b5060010190565b60408152600061144d6040830185610f38565b828103602084015261145f8185610f38565b95945050505050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061149b90830184610f38565b9695505050505050565b6000602082840312156114b757600080fd5b8151610f1881610ee556fea2646970667358221220a216c6367cb6a8aed9f02f487f4a12c8ada9154ed3ae81a03fa577341ef0a1a964736f6c63430008190033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/components/AppWalletProvider.tsx b/components/AppWalletProvider.tsx new file mode 100644 index 00000000..cc59bb45 --- /dev/null +++ b/components/AppWalletProvider.tsx @@ -0,0 +1,44 @@ +"use client"; + +import React, { useMemo } from "react"; +import { + ConnectionProvider, + WalletProvider, +} from "@solana/wallet-adapter-react"; +import { WalletAdapterNetwork } from "@solana/wallet-adapter-base"; +import { WalletModalProvider } from "@solana/wallet-adapter-react-ui"; +import { clusterApiUrl } from "@solana/web3.js"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +import "@solana/wallet-adapter-react-ui/styles.css"; +import dynamic from "next/dynamic"; + +// Dynamically import Wallet button +export const WalletButton = dynamic( + async () => (await import("@solana/wallet-adapter-react-ui")).WalletMultiButton, + { ssr: false } +); + +// Create a React Query client +const queryClient = new QueryClient(); + +export default function AppWalletProvider({ + children, +}: { + children: React.ReactNode; +}) { + const network = WalletAdapterNetwork.Devnet; + const endpoint = useMemo(() => clusterApiUrl(network), [network]); + + const wallets = useMemo(() => [], []); // Add wallet adapters if needed + + return ( + + + + {children} + + + + ); +} diff --git a/components/AuthButton.tsx b/components/AuthButton.tsx new file mode 100644 index 00000000..a2465d95 --- /dev/null +++ b/components/AuthButton.tsx @@ -0,0 +1,66 @@ +'use client'; + +import { Button } from '../components/ui/button'; +import { useWalletAuth } from '../context/appkit'; +import { Loader2, ShieldCheck, Lock } from 'lucide-react'; +import { cn } from '../components/lib/utils'; +import { useDisclosure } from '@chakra-ui/react'; +import { AccountSetupModal } from '../components/modal/AccountSetupModal'; + +export function AuthButton() { + const { + + isConnected, + isAuthenticated, + isAuthenticating, + authenticate + } = useWalletAuth(); + + const { isOpen, onOpen, onClose } = useDisclosure(); + + const handleClick = async () => { + const success = await authenticate(); + if (success) { + onOpen(); + } + }; + + if (!isConnected) return null; + + return ( + <> + + + {/* ✅ Modal for Account Verification */} + + + ); +} diff --git a/components/BillingsPage/BankAccountsList/BankAccountsList.tsx b/components/BillingsPage/BankAccountsList/BankAccountsList.tsx index 14200827..c9ceb35e 100644 --- a/components/BillingsPage/BankAccountsList/BankAccountsList.tsx +++ b/components/BillingsPage/BankAccountsList/BankAccountsList.tsx @@ -1,85 +1,80 @@ -import React from 'react' -import {Card,List,Typography,Button,Avatar, Descriptions} from 'antd' -import {PlusCircleOutlined} from '@ant-design/icons' -import { useRouter } from 'next/router' +import { List, Typography, Button } from 'antd' import { BankAccount } from '../../../types/BankAccount' import { useOrgContext } from '../../../context/OrgContext' -const {Title,Text} = Typography +const { Text } = Typography -interface BankAccountListProps{ +interface BankAccountListProps { bankAccounts: Array, - onCreateBankAccount: ()=>void, - onSelectBankAccount: (service:BankAccount)=>void, - onDeleteBankAccount: (itemKey: string)=>void, + onCreateBankAccount: () => void, + onSelectBankAccount: (service: BankAccount) => void, + onDeleteBankAccount: (itemKey: string) => void, isLoading: boolean, } -export default function BankAccountListProps({onDeleteBankAccount, isLoading, onSelectBankAccount, bankAccounts, onCreateBankAccount}:BankAccountListProps){ +export default function BankAccountListProps({ onDeleteBankAccount, isLoading, onSelectBankAccount, bankAccounts }: BankAccountListProps) { + const { isAdmin } = useOrgContext() - const router = useRouter() - const {isAdmin} = useOrgContext() - - return( -
+ return ( +
( - onDeleteBankAccount(item.id)} - key={item.id}>Delete , - ]} - > - -
- Acct No: - {item.accountNo} -
-
- Address: - {item.beneficiaryAddress} -
-
- Swift Code: - {item.swiftCode} -
+ itemLayout="horizontal" + dataSource={bankAccounts} + loading={isLoading} + bordered={false} + renderItem={(item: BankAccount) => ( + onDeleteBankAccount(item.id)} + key={item.id}>Delete, + ]} + > + +
+ Acct No: + {item.accountNo} +
+
+ Address: + {item.beneficiaryAddress} +
+
+ Swift Code: + {item.swiftCode} +
-
- Routing No: - {item.routingNumber} -
+
+ Routing No: + {item.routingNumber} +
-
- Account name: - {item.beneficiaryName} -
+
+ Account name: + {item.beneficiaryName} +
-
- Currency: - {item.currency} -
+
+ Currency: + {item.currency} +
-
- } - /> - - )} - /> +
+ } + /> + + )} + /> ) } \ No newline at end of file diff --git a/components/BillingsPage/CreateBankAccountForm/CreateBankAccountForm.tsx b/components/BillingsPage/CreateBankAccountForm/CreateBankAccountForm.tsx index a09297fa..fd54a642 100644 --- a/components/BillingsPage/CreateBankAccountForm/CreateBankAccountForm.tsx +++ b/components/BillingsPage/CreateBankAccountForm/CreateBankAccountForm.tsx @@ -1,20 +1,20 @@ -import React,{useState} from 'react' -import {Card,Form,Input, InputNumber,Button, Radio, notification} from 'antd' +import React from 'react' +import { Form, Input, Button, Radio } from 'antd' import { BankAccount } from '../../../types/BankAccount' import { useOrgContext } from '../../../context/OrgContext' -interface CreateBankAccountFormProps{ - onCreateBankAccount: (formData:BankAccount)=>void +interface CreateBankAccountFormProps { + onCreateBankAccount: (formData: BankAccount) => void isCreatingData: boolean } -export default function CreateBankAccountForm({ isCreatingData, onCreateBankAccount}:CreateBankAccountFormProps){ +export default function CreateBankAccountForm({ isCreatingData, onCreateBankAccount }: CreateBankAccountFormProps) { - const {currentOrg} = useOrgContext() + const { currentOrg } = useOrgContext() - const onFinish = (formData:BankAccount)=>{ + const onFinish = (formData: BankAccount) => { // call function to create store const formObject = { ...formData, @@ -26,13 +26,13 @@ export default function CreateBankAccountForm({ isCreatingData, onCreateBankAcco // onCloseForm() } - return( -
+ > + > - + > Savings Current @@ -112,10 +112,10 @@ export default function CreateBankAccountForm({ isCreatingData, onCreateBankAcco - + ) } \ No newline at end of file diff --git a/components/BillingsPage/EditBankAccountForm/EditBankAccountForm.tsx b/components/BillingsPage/EditBankAccountForm/EditBankAccountForm.tsx index ffdedfa6..e7aacba5 100644 --- a/components/BillingsPage/EditBankAccountForm/EditBankAccountForm.tsx +++ b/components/BillingsPage/EditBankAccountForm/EditBankAccountForm.tsx @@ -1,21 +1,21 @@ -import React,{useState} from 'react' -import {Card,Form,Input, InputNumber,Button, Radio} from 'antd' +import React from 'react' +import { Form, Input, Button, Radio } from 'antd' import { BankAccount } from '../../../types/BankAccount' -interface EditBankAccountFormProps{ +interface EditBankAccountFormProps { initValues: BankAccount | undefined - onEditBankAccount: (store:BankAccount)=>void - onCloseEditForm: ()=>void, + onEditBankAccount: (store: BankAccount) => void + onCloseEditForm: () => void, isPatchingData: boolean } -export default function EditBankAccountForm({initValues,onEditBankAccount, isPatchingData, onCloseEditForm}:EditBankAccountFormProps){ +export default function EditBankAccountForm({ initValues, onEditBankAccount, isPatchingData }: EditBankAccountFormProps) { const prevValues = initValues; - const onFinish = (formData:BankAccount)=>{ + const onFinish = (formData: BankAccount) => { // call function to create store const formObject = { ...prevValues, @@ -26,20 +26,20 @@ export default function EditBankAccountForm({initValues,onEditBankAccount, isPat } - - return( -
+ > + > @@ -68,11 +68,11 @@ export default function EditBankAccountForm({initValues,onEditBankAccount, isPat - + > Savings Current @@ -107,10 +107,10 @@ export default function EditBankAccountForm({initValues,onEditBankAccount, isPat - + ) } \ No newline at end of file diff --git a/components/BillingsPage/index.tsx b/components/BillingsPage/index.tsx index 1238f386..242c5260 100644 --- a/components/BillingsPage/index.tsx +++ b/components/BillingsPage/index.tsx @@ -1,204 +1,198 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -const {Text,Title} = Typography -const {Option} = Select -import React, { ReactNode, useRef, useState } from 'react' -import {Typography,Button,Avatar, Upload, Tag, Image, Descriptions, Table, InputRef, Input, Space, DatePicker, Radio, Dropdown, MenuProps, Drawer, Row, Col, Divider, Form, Modal, notification, Select, Popconfirm, Spin} from 'antd' +const { Text, Title } = Typography +import React, { ReactNode, useState } from 'react' +import { Typography, Button, Input, Form, Modal, Spin } from 'antd' import axios from 'axios'; import { useAuthContext } from '../../context/AuthContext'; -import { Bank } from "./Types/Banks.types"; import useUrlPrefix from '../../hooks/useUrlPrefix' import { useOrgContext } from "../../context/OrgContext"; -import { useRouter } from "next/router"; import utils from "../../utils/env"; -export default function BillingsView(){ +export default function BillingsView() { - const {paseto} = useAuthContext() - const {currentOrg} = useOrgContext() + const { paseto } = useAuthContext() + const { currentOrg } = useOrgContext() - const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false) + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false) + const queryClient = useQueryClient() - const router = useRouter() + const urlPrefix = useUrlPrefix() - const queryClient = useQueryClient() - const urlPrefix = useUrlPrefix() - - - async function fetchBankAccount(){ - const res = await axios({ - method:'get', - //@ts-ignore - url:`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/org-bank/stripe?orgId=${currentOrg.orgId}`, - headers:{ - "Authorization": paseto - } - }) - return res.data.data; - } - - const bankAccountQuery = useQuery({ - queryKey: ['bank','details','admin',currentOrg.id], - queryFn: fetchBankAccount, - enabled: paseto !== undefined, - }) - - const deleteActionMutation = useMutation({ - mutationFn: async(payload:{orgId:string | undefined})=>{ - const res = await axios.delete(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/orgs/bank-account`,{data:payload, - headers:{ - 'Authorization': paseto - } - } - ) - return res.data - }, - onSuccess:(data:any)=>{ - queryClient.invalidateQueries(['bank','details','admin',currentOrg.id]) - }, - onError:(error:any)=>{ - console.log('Error generating account links') - } - }) - const editAccountMutation = useMutation({ - mutationFn: async(payload:{orgId:string | undefined})=>{ - const res = await axios.patch(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/orgs/account-link`,payload,{ - headers:{ - 'Authorization': paseto - } - }) - return res.data - }, - onSuccess:(data:any)=>{ - const stripeOnboardUrl = data.data - window.location.href = stripeOnboardUrl - }, - onError:(error:any)=>{ - console.log('Error generating account links') + async function fetchBankAccount() { + const res = await axios({ + method: 'get', + //@ts-ignore + url: `${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/org-bank/stripe?orgId=${currentOrg.orgId}`, + headers: { + "Authorization": paseto } }) + return res.data.data; + } - const accountLinkMutation = useMutation({ - mutationFn: async(payload:{orgId:string | undefined})=>{ - const res = await axios.post(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/orgs/account-link`,payload,{ - headers:{ - 'Authorization': paseto - } - }) - return res.data - }, - onSuccess:(data:any)=>{ - const stripeOnboardUrl = data.data - console.log(stripeOnboardUrl) - window.location.href = stripeOnboardUrl - }, - onError:(error:any)=>{ - console.log('Error generating account links') + const bankAccountQuery = useQuery({ + queryKey: ['bank', 'details', 'admin', currentOrg.id], + queryFn: fetchBankAccount, + enabled: paseto !== undefined, + }) + + const deleteActionMutation = useMutation({ + mutationFn: async (payload: { orgId: string | undefined }) => { + const res = await axios.delete(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/orgs/bank-account`, { + data: payload, + headers: { + 'Authorization': paseto + } } - }) - - function editAccountInfo(){ - editAccountMutation.mutate({orgId: currentOrg.orgId}) + ) + return res.data + }, + onSuccess: (data: any) => { + queryClient.invalidateQueries(['bank', 'details', 'admin', currentOrg.id]) + }, + onError: (error: any) => { + console.log('Error generating account links') } - - function toggleDeleteModal(){ - setIsDeleteModalOpen(!isDeleteModalOpen) + }) + const editAccountMutation = useMutation({ + mutationFn: async (payload: { orgId: string | undefined }) => { + const res = await axios.patch(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/orgs/account-link`, payload, { + headers: { + 'Authorization': paseto + } + }) + return res.data + }, + onSuccess: (data: any) => { + const stripeOnboardUrl = data.data + window.location.href = stripeOnboardUrl + }, + onError: (error: any) => { + console.log('Error generating account links') } + }) - function deleteUserAccount(){ - deleteActionMutation.mutate({orgId: currentOrg.orgId}) + const accountLinkMutation = useMutation({ + mutationFn: async (payload: { orgId: string | undefined }) => { + const res = await axios.post(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/orgs/account-link`, payload, { + headers: { + 'Authorization': paseto + } + }) + return res.data + }, + onSuccess: (data: any) => { + const stripeOnboardUrl = data.data + console.log(stripeOnboardUrl) + // window.location.href = stripeOnboardUrl + }, + onError: (error: any) => { + console.log('Error generating account links') } + }) - function connectToStripeOnboarding(){ - accountLinkMutation.mutate({orgId: currentOrg.orgId}) - } + function editAccountInfo() { + editAccountMutation.mutate({ orgId: currentOrg.orgId }) + } + function toggleDeleteModal() { + setIsDeleteModalOpen(!isDeleteModalOpen) + } + function deleteUserAccount() { + deleteActionMutation.mutate({ orgId: currentOrg.orgId }) + } - return ( -
-
- Payout - Manage your organizations billing information -
- { bankAccountQuery.isLoading || bankAccountQuery.isRefetching - ? - : bankAccountQuery.data.fingerprint === '' - ? - - - : - <> - {/* statistics */} -
-
- Event Sales - ${(bankAccountQuery?.data?.eventSales/100).toLocaleString()} -
-
- Community Sales - ${(bankAccountQuery?.data?.communitySales/100).toLocaleString()} -
-
- Service Sales - ${(bankAccountQuery?.data?.serviceSales/100).toLocaleString()} -
-
- Total Sales - ${(bankAccountQuery?.data?.totalSales/100).toLocaleString()} -
-
- - {/* account details */} -
-
-
- {bankAccountQuery?.data?.account_holder_name !==''? bankAccountQuery?.data?.account_holder_name: '-- -- --'} - {bankAccountQuery?.data?.bank_name} -
-
- {`${bankAccountQuery?.data?.country} • ${bankAccountQuery?.data?.currency}`} -
-
+ function connectToStripeOnboarding() { + accountLinkMutation.mutate({ orgId: currentOrg.orgId }) + } -
-
- {`**** **** **** ${bankAccountQuery?.data?.last4}`} - Account No -
-
- {bankAccountQuery?.data?.routing_number} - Routing No -
-
- Checking - Account Type -
-
-
- - {/* */} - + + return ( +
+
+ Payout + Manage your organizations billing information +
+ {bankAccountQuery.isLoading || bankAccountQuery.isRefetching + ? + : bankAccountQuery.data.fingerprint === '' + ? + + + : + <> + {/* statistics */} +
+
+ Event Sales + ${(bankAccountQuery?.data?.eventSales / 100).toLocaleString()} +
+
+ Community Sales + ${(bankAccountQuery?.data?.communitySales / 100).toLocaleString()} +
+
+ Service Sales + ${(bankAccountQuery?.data?.serviceSales / 100).toLocaleString()} +
+
+ Total Sales + ${(bankAccountQuery?.data?.totalSales / 100).toLocaleString()} +
+
+ + {/* account details */} +
+
+
+ {bankAccountQuery?.data?.account_holder_name !== '' ? bankAccountQuery?.data?.account_holder_name : '-- -- --'} + {bankAccountQuery?.data?.bank_name} +
+
+ {`${bankAccountQuery?.data?.country} • ${bankAccountQuery?.data?.currency}`}
-
- +
- - } - -
- ) +
+
+ {`**** **** **** ${bankAccountQuery?.data?.last4}`} + Account No +
+
+ {bankAccountQuery?.data?.routing_number} + Routing No +
+
+ Checking + Account Type +
+
+ +
+ + {/* */} + +
+ + + + + } + + ) @@ -207,71 +201,71 @@ export default function BillingsView(){ -interface DeleteProp{ +interface DeleteProp { account: any isOpen: boolean - onCloseModal: ()=>void - onDeleteAccount: ()=>void + onCloseModal: () => void + onDeleteAccount: () => void isDeletingAccount: boolean } -function DeleteAccountModal({account, isOpen, isDeletingAccount, onDeleteAccount, onCloseModal}:DeleteProp){ +function DeleteAccountModal({ account, isOpen, isDeletingAccount, onDeleteAccount, onCloseModal }: DeleteProp) { - function onFinish(){ + function onFinish() { // call mutate function to delete record onDeleteAccount() } const [form] = Form.useForm() - return( - {}} onCancel={onCloseModal}> + return ( + { }} onCancel={onCloseModal}> {/* */} {`Deleting this account will not enable you to receive payments on all services, communities and events listed on the marketplace. All services, communities and events created without an account will be saved as draft by default `} -
- - - - - + + + + + + {() => ( - - )} - - - - -
+ + )} +
+ + + + ) } @@ -279,19 +273,19 @@ function DeleteAccountModal({account, isOpen, isDeletingAccount, onDeleteAccount -interface EmptyStateProps{ +interface EmptyStateProps { children: ReactNode } -function EmptyState({children}:EmptyStateProps){ +function EmptyState({ children }: EmptyStateProps) { - return( -
-
- Create New Account - Add an account to get started receiving payouts from your tickets purchases on the marketplace -
- {children} + return ( +
+
+ Create New Account + Add an account to get started receiving payouts from your tickets purchases on the marketplace +
+ {children}
diff --git a/components/CommunityPage/Editables/Artwork.tsx b/components/CommunityPage/Editables/Artwork.tsx index 6dff4f77..ad9e1420 100644 --- a/components/CommunityPage/Editables/Artwork.tsx +++ b/components/CommunityPage/Editables/Artwork.tsx @@ -1,207 +1,206 @@ import { useQueryClient, useMutation } from "@tanstack/react-query" import { Row, Col, Button, Space, Typography, Image as AntImage, Drawer, Upload, UploadProps } from "antd" import axios from "axios" -import { useEffect, useRef, useState } from "react" +import { useRef, useState } from "react" import { useAuthContext } from "../../../context/AuthContext" import useUrlPrefix from "../../../hooks/useUrlPrefix" import { Community } from "../../../types/Community" -import {SelectOutlined,UploadOutlined} from "@ant-design/icons" -import Image from 'next/image' +import { SelectOutlined } from "@ant-design/icons" +import Image from 'next/image' import { getBase64 } from "../../../utils/convertToBase64" -import { useRouter } from "next/router" import { uploadToPinata } from "../../../utils/nftStorage" import utils from "../../../utils/env" - -const {Text} = Typography -interface EditableProp{ - selectedRecord: Community +const { Text } = Typography + +interface EditableProp { + selectedRecord: Community } -export function EditableArtwork({selectedRecord}:EditableProp){ - - const {paseto} = useAuthContext() +export function EditableArtwork({ selectedRecord }: EditableProp) { + + const { paseto } = useAuthContext() // make this default value to be lineskip images first element - const artworkRef = useRef(selectedRecord.artworkHash) + const artworkRef = useRef(selectedRecord.artworkHash) - const queryClient = useQueryClient() + const queryClient = useQueryClient() - const [isEditMode, setIsEditMode] = useState(false) - const [updatedArtworkHash, setUpdatedArtworkHash] = useState(selectedRecord.artworkHash) - const [artwork, setArtwork] = useState(selectedRecord.artworkHash) - const [isDrawerOpen, setIsDrawerOpen] = useState(false) - const urlPrefix = useUrlPrefix() + const [isEditMode, setIsEditMode] = useState(false) + const [updatedArtworkHash, setUpdatedArtworkHash] = useState(selectedRecord.artworkHash) + const [artwork, setArtwork] = useState(selectedRecord.artworkHash) + const [isDrawerOpen, setIsDrawerOpen] = useState(false) + const urlPrefix = useUrlPrefix() - const [imageBlob, setImageBlob] = useState() + const [imageBlob, setImageBlob] = useState() - const [isHashingImage, setIsHashingImage] = useState(false) + const [isHashingImage, setIsHashingImage] = useState(false) - const isUploadedImage = artwork.startsWith('data') - - function toggleEdit(){ - setIsEditMode(!isEditMode) - } + const isUploadedImage = artwork.startsWith('data') + function toggleEdit() { + setIsEditMode(!isEditMode) + } - - function toggleDrawer(){ - setIsDrawerOpen(!isDrawerOpen) - } - function handleSelectImage(imageHash:string){ - setArtwork(imageHash) - } - - - const mutationHandler = async(updatedItem:any)=>{ - const {data} = await axios.patch(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`,updatedItem,{ - headers:{ - //@ts-ignore - "Authorization": paseto - } - }) - return data; - } - const mutation = useMutation({ - mutationKey:['artwork_hash'], - mutationFn: mutationHandler, - onSuccess:()=>{ - toggleEdit() - }, - onSettled:(data)=>{ - setUpdatedArtworkHash(data?.data?.artworkHash) - queryClient.invalidateQueries(['community']) - } - }) - const props: UploadProps = { - name: 'file', - multiple:false, - showUploadList:false, - onChange: async (info) => { - const imageBlob = info.file.originFileObj - const src = await getBase64(imageBlob) - setArtwork(src) - setImageBlob(info.file.originFileObj) - }, - }; - - - async function onFinish(){ - - //hash image here\ - setIsHashingImage(true) - const artworkHash = isUploadedImage? await uploadToPinata(imageBlob): artwork - setIsHashingImage(false) - - const payload = { - artworkHash: artworkHash, - id: selectedRecord.id + function toggleDrawer() { + setIsDrawerOpen(!isDrawerOpen) + } + + function handleSelectImage(imageHash: string) { + setArtwork(imageHash) + } + + + const mutationHandler = async (updatedItem: any) => { + const { data } = await axios.patch(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, updatedItem, { + headers: { + //@ts-ignore + "Authorization": paseto } - // setUpdatedArtworkHash(coverImageHash) - mutation.mutate(payload) + }) + return data; + } + const mutation = useMutation({ + mutationKey: ['artwork_hash'], + mutationFn: mutationHandler, + onSuccess: () => { + toggleEdit() + }, + onSettled: (data) => { + setUpdatedArtworkHash(data?.data?.artworkHash) + queryClient.invalidateQueries(['community']) + } + }) + + const props: UploadProps = { + name: 'file', + multiple: false, + showUploadList: false, + onChange: async (info) => { + const imageBlob = info.file.originFileObj + const src = await getBase64(imageBlob) + setArtwork(src) + setImageBlob(info.file.originFileObj) + }, + }; + + + async function onFinish() { + + //hash image here\ + setIsHashingImage(true) + const artworkHash = isUploadedImage ? await uploadToPinata(imageBlob) : artwork + setIsHashingImage(false) + + const payload = { + artworkHash: artworkHash, + id: selectedRecord.id } - - const {isLoading:isEditing} = mutation - - - const editable = ( -
- - - Artwork preview -
-
- - or - - - -
- {/* */} + // setUpdatedArtworkHash(coverImageHash) + mutation.mutate(payload) + } + + const { isLoading: isEditing } = mutation + + + const editable = ( +
+ + + Artwork preview +
+
+ + or + + +
- - - - - - - - - - - - -
- ) + {/* */} +
+ + + + + + + + + + + + +
+ ) + + const readOnly = ( +
+ + +
+ ) + + return ( +
+ Artwork + {isEditMode ? editable : readOnly} +
+ ) +} - const readOnly = ( -
- - -
- ) - - return( -
- Artwork - {isEditMode?editable:readOnly} -
- ) - } - - interface IArtworkPicker{ - isOpen: boolean, - onSelectImage: (image:string) =>void - currentSelectedArtwork: string, - onToggleDrawer: ()=>void +interface IArtworkPicker { + isOpen: boolean, + onSelectImage: (image: string) => void + currentSelectedArtwork: string, + onToggleDrawer: () => void } - export function ArtworkPicker({isOpen, currentSelectedArtwork, onSelectImage, onToggleDrawer}:IArtworkPicker){ - - const currentHashes = communityHashes - - return( - -
- {/* artwork for lineskip */} - { - currentHashes.map((image:string)=>( -
onSelectImage(image)} style={{border:`4px solid ${currentSelectedArtwork === image? '#1677ff':'#eeeeee'}`,borderRadius:'4px', display:'inline-block', marginRight:'1rem', padding:'.5rem'}}> - artwork for community -
- )) - } - -
-
- ) +export function ArtworkPicker({ isOpen, currentSelectedArtwork, onSelectImage, onToggleDrawer }: IArtworkPicker) { + + const currentHashes = communityHashes + + return ( + +
+ {/* artwork for lineskip */} + { + currentHashes.map((image: string) => ( +
onSelectImage(image)} style={{ border: `4px solid ${currentSelectedArtwork === image ? '#1677ff' : '#eeeeee'}`, borderRadius: '4px', display: 'inline-block', marginRight: '1rem', padding: '.5rem' }}> + artwork for community +
+ )) + } + +
+
+ ) } @@ -218,6 +217,5 @@ const communityHashes = [ 'bafybeihkfzmeegpiz67fxn2i3rmohdddjcoyk5y45rmvaqvv5sotrdxypm', 'bafybeif66cmurjviz35rid5morzsnp277cs3qhjdgquvpe6n54ntuolnnu', 'bafybeibbyfj22f3wdrgu4dzsnpfixtn7zfmrxn7i3efavfdhnczz2sqala' - ] - - \ No newline at end of file +] + diff --git a/components/Header/CurrentUser/CurrentUser.tsx b/components/Header/CurrentUser/CurrentUser.tsx index e6822502..b1dfbc2a 100644 --- a/components/Header/CurrentUser/CurrentUser.tsx +++ b/components/Header/CurrentUser/CurrentUser.tsx @@ -1,185 +1,181 @@ import React, { useEffect, useState } from 'react' -import {Typography,Avatar,Button, Dropdown, Badge, Tag} from 'antd' -import {DownOutlined,LogoutOutlined} from '@ant-design/icons' +import { Typography, Avatar, Button, Dropdown, Tag } from 'antd' import { useAuthContext } from '../../../context/AuthContext' -import { useOrgContext } from '../../../context/OrgContext' -const {Text,Title} = Typography -import type { MenuProps } from 'antd'; -import { useServicesContext } from '../../../context/ServicesContext' +const { Text } = Typography import { useRouter } from 'next/router' import utils from '../../../utils/env' -interface CurrentUserProps{ - user?: {email:string, role:string} - openOrgSwitcher?: ()=>void +interface CurrentUserProps { + user?: { email: string, role: string } + openOrgSwitcher?: () => void } -const venueRoutes = ['serviceItems','dashboard','staff','bookings'] - - -export default function CurrentUser({openOrgSwitcher}:CurrentUserProps){ - - const {logout,currentUser} = useAuthContext() - const {currentService} = useServicesContext() - const router = useRouter() - const {orgUserRole} = useOrgContext() - const [isManagerRoute, setIsManagerRoute] = useState(false) - const [isVenueRoute,setIsVenueRoute] = useState(false) - - // move this into a hook - const borderColor = currentUser.role == 1 ? 'purple': currentUser.role == 2 ? 'volcano': currentUser.role == 3? 'cyan': currentUser.role == 0?'blue':'green' - - useEffect(() => { - const isManagerRoute = router.isReady? router.asPath.includes('/manager'): false - if(router.isReady){ - let exist = false - venueRoutes.forEach(route=>{ - if(router.asPath.includes(route) === true){ - exist = true - return - } - }) - setIsVenueRoute(exist) - } - - setIsManagerRoute(isManagerRoute) - }, []) - - const navigateBackToServices=()=>{ - router.replace(`/organizations/venues`) - } - const navigateBackToOrgs=()=>{ - router.replace(`/organizations`) - } - - const navigateToProfile=()=>{ +const venueRoutes = ['serviceItems', 'dashboard', 'staff', 'bookings'] + + +export default function CurrentUser({ openOrgSwitcher }: CurrentUserProps) { + + const { logout, currentUser } = useAuthContext() + const router = useRouter() + const [isManagerRoute, setIsManagerRoute] = useState(false) + const [isVenueRoute, setIsVenueRoute] = useState(false) + + // move this into a hook + const borderColor = currentUser.role == 1 ? 'purple' : currentUser.role == 2 ? 'volcano' : currentUser.role == 3 ? 'cyan' : currentUser.role == 0 ? 'blue' : 'green' + + useEffect(() => { + const isManagerRoute = router.isReady ? router.asPath.includes('/manager') : false + if (router.isReady) { + let exist = false + venueRoutes.forEach(route => { + if (router.asPath.includes(route) === true) { + exist = true + return + } + }) + setIsVenueRoute(exist) + } + + setIsManagerRoute(isManagerRoute) + }, []) + + const navigateBackToServices = () => { + router.replace(`/organizations/venues`) + } + const navigateBackToOrgs = () => { + router.replace(`/organizations`) + } + + const navigateToProfile = () => { router.push('/profile') - } - + } + // const items = currentUser.role == 1 ? getManagerMenu() :getAdminMenu() let items = [] - if(currentUser && currentUser.role == 2){ - if(isVenueRoute){ - items = getVenueRoutes() - }else{ + if (currentUser && currentUser.role == 2) { + if (isVenueRoute) { + items = getVenueRoutes() + } else { items = getAdminMenu() } - }else if(currentUser && currentUser.role == 1) { - if(isVenueRoute){ + } else if (currentUser && currentUser.role == 1) { + if (isVenueRoute) { items = getManagerVenueRoutes() - }else{ + } else { items = getManagerMenu() } - }else if(currentUser && currentUser.role == 0){ + } else if (currentUser && currentUser.role == 0) { items = getSuperAdminRoutes() - }else{ + } else { items = getManagerMenu() } // console.log(isVenueRoute) - function getAdminMenu(){ - return[ + function getAdminMenu() { + return [ // {label:Back to launchpad, key:'servicesPage'}, - // {label:Back to organizations, key:'organizationsPage'}, - // {type:'divider', key:'divider0'}, - // {label:Switch organization, key:'switchOrganizations'}, - {type:'divider', key:'divider1'}, - {label:Profile, key:'profile'}, - {type:'divider', key:'divider2'}, - {label:, key:'logout'}, + // {label:Back to organizations, key:'organizationsPage'}, + // {type:'divider', key:'divider0'}, + // {label:Switch organization, key:'switchOrganizations'}, + { type: 'divider', key: 'divider1' }, + { label: Profile, key: 'profile' }, + { type: 'divider', key: 'divider2' }, + { label: , key: 'logout' }, ] } - function getVenueRoutes(){ - return[ - {label:Back to launchpad, key:'venuesPage'}, - {label:Back to organizations, key:'organizationsPage'}, - {type:'divider', key:'divider0'}, - {label:Switch organization, key:'switchOrganizations'}, - {type:'divider', key:'divider1'}, - {label:Profile, key:'profile'}, - {type:'divider', key:'divider2'}, - {label:, key:'logout'}, + function getVenueRoutes() { + return [ + { label: Back to launchpad, key: 'venuesPage' }, + { label: Back to organizations, key: 'organizationsPage' }, + { type: 'divider', key: 'divider0' }, + { label: Switch organization, key: 'switchOrganizations' }, + { type: 'divider', key: 'divider1' }, + { label: Profile, key: 'profile' }, + { type: 'divider', key: 'divider2' }, + { label: , key: 'logout' }, ] } - - - function getManagerVenueRoutes(){ - return[ - {label:Back to launchpad, key:'venuesPage'}, - {label:router.replace('/manager/organizations')} >Back to organizations, key:'organizationsPage'}, - {type:'divider', key:'divider0'}, - {label:Profile, key:'profile'}, - {type:'divider', key:'divider2'}, - {label:, key:'logout'}, + + + function getManagerVenueRoutes() { + return [ + { label: Back to launchpad, key: 'venuesPage' }, + { label: router.replace('/manager/organizations')} >Back to organizations, key: 'organizationsPage' }, + { type: 'divider', key: 'divider0' }, + { label: Profile, key: 'profile' }, + { type: 'divider', key: 'divider2' }, + { label: , key: 'logout' }, ] } - function getSuperAdminRoutes(){ - return[ - {label:Back to launchpad, key:'venuesPage'}, - {label:router.replace('/manager/organizations')} >Back to organizations, key:'organizationsPage'}, - {type:'divider', key:'divider0'}, - {label:Profile, key:'profile'}, - {type:'divider', key:'divider2'}, - {label:, key:'logout'}, + function getSuperAdminRoutes() { + return [ + { label: Back to launchpad, key: 'venuesPage' }, + { label: router.replace('/manager/organizations')} >Back to organizations, key: 'organizationsPage' }, + { type: 'divider', key: 'divider0' }, + { label: Profile, key: 'profile' }, + { type: 'divider', key: 'divider2' }, + { label: , key: 'logout' }, ] } - - - - - function getManagerMenu(){ - return[ - // {label:Back to launchpad, key:'servicesPage'}, - // {label:router.push('/manager/organizations')} >Back to organizations, key:'organizationsPage'}, - // {type:'divider', key:'divider0'}, - {label: -
-
- {currentUser && currentUser.name} - {currentUser && currentUser.userRoleName} -
- {currentUser && currentUser.email} -
, - key:'userData'}, - {type:'divider', key:'divider23'}, - {label:Profile, key:'profile'}, - {type:'divider', key:'divider2'}, - {label:, key:'logout'}, + + + + + function getManagerMenu() { + return [ + // {label:Back to launchpad, key:'servicesPage'}, + // {label:router.push('/manager/organizations')} >Back to organizations, key:'organizationsPage'}, + // {type:'divider', key:'divider0'}, + { + label: +
+
+ {currentUser && currentUser.name} + {currentUser && currentUser.userRoleName} +
+ {currentUser && currentUser.email} +
, + key: 'userData' + }, + { type: 'divider', key: 'divider23' }, + { label: Profile, key: 'profile' }, + { type: 'divider', key: 'divider2' }, + { label: , key: 'logout' }, ] } - - return( - //@ts-ignore - + + return ( + //@ts-ignore +
- - - - {/* */} - {/*
*/} - {/* {currentUser && currentUser.name} */} - {/* {currentUser && currentUser.email} */} - {/*
*/} - {/*
*/} -
+ + + + {/* */} + {/*
*/} + {/* {currentUser && currentUser.name} */} + {/* {currentUser && currentUser.email} */} + {/*
*/} + {/*
*/} +
- ) + ) } diff --git a/components/Header/OrgSwitcherButton/OrgSwitcherButton.tsx b/components/Header/OrgSwitcherButton/OrgSwitcherButton.tsx index 9b2ea6af..2861f106 100644 --- a/components/Header/OrgSwitcherButton/OrgSwitcherButton.tsx +++ b/components/Header/OrgSwitcherButton/OrgSwitcherButton.tsx @@ -1,31 +1,32 @@ -import React,{useState} from 'react'; -import {Typography,Avatar,Button} from 'antd' +import React from 'react'; +import { Typography, Avatar, Button } from 'antd' import { useOrgContext } from '../../../context/OrgContext'; -const {Text,Title,Paragraph} = Typography; +const { Title } = Typography; -interface OrgSwitcherProps{ - onOpenSwitcher: ()=> void +interface OrgSwitcherProps { + onOpenSwitcher: () => void } -export default function OrgSwitcher({onOpenSwitcher}:OrgSwitcherProps){ +export default function OrgSwitcher({ onOpenSwitcher }: OrgSwitcherProps) { - const {currentOrg} = useOrgContext() - - return ( -
- -
- {currentOrg.name} - -
-
- ) + const { currentOrg } = useOrgContext() + + return ( +
+ +
+ {currentOrg.name} + +
+
+ ) } diff --git a/components/Header/ServicesSwitcherButton/ServicesSwitcherButton.tsx b/components/Header/ServicesSwitcherButton/ServicesSwitcherButton.tsx index 2b88e86b..07f2f4b6 100644 --- a/components/Header/ServicesSwitcherButton/ServicesSwitcherButton.tsx +++ b/components/Header/ServicesSwitcherButton/ServicesSwitcherButton.tsx @@ -1,9 +1,8 @@ -import React,{useState} from 'react'; +import React from 'react'; import {Typography,Avatar,Button} from 'antd' import { useServicesContext } from '../../../context/ServicesContext'; -import { useAuthContext } from '../../../context/AuthContext'; import useRole from '../../../hooks/useRole'; -const {Text,Title,Paragraph} = Typography; +const {Text} = Typography; interface ServiceSwitcherProps{ onOpenSwitcher: ()=> void diff --git a/components/Layout/BillingsLayout.tsx b/components/Layout/BillingsLayout.tsx index 3d105e41..92b193f1 100644 --- a/components/Layout/BillingsLayout.tsx +++ b/components/Layout/BillingsLayout.tsx @@ -1,5 +1,5 @@ import { ReactNode, useEffect, useState } from "react" -import {Typography, Row, Col, Button, Skeleton, Layout, Segmented, Menu, MenuProps} from 'antd' +import {Typography, Row, Col, Button, Skeleton, Layout, Menu, MenuProps} from 'antd' import CurrentUser from "../Header/CurrentUser/CurrentUser" import { useOrgContext } from "../../context/OrgContext" import { useRouter } from "next/router" diff --git a/components/Layout/CommunitiesLayout.tsx b/components/Layout/CommunitiesLayout.tsx index 4b259bd6..55f765be 100644 --- a/components/Layout/CommunitiesLayout.tsx +++ b/components/Layout/CommunitiesLayout.tsx @@ -1,11 +1,7 @@ import { - - UserOutlined, - VideoCameraOutlined, - LeftOutlined - } from '@ant-design/icons'; - import { Menu, Breadcrumb, Typography ,Button, Layout, MenuProps, Spin, Col, Row} from 'antd'; -import Link from 'next/link'; + LeftOutlined +} from '@ant-design/icons'; +import { Menu, Typography, Button, Layout, MenuProps, Spin, Col, Row } from 'antd'; import { useRouter } from 'next/router'; import React, { ReactNode, useState, useEffect } from 'react'; import { useAuthContext } from '../../context/AuthContext'; @@ -21,132 +17,132 @@ import utils from '../../utils/env'; const { Header, Sider, Content } = Layout; -const {Text, Title} = Typography +const { Text, Title } = Typography + +interface LayoutProps { + children: ReactNode, + width?: number +} + +type PageRoute = { + basePath: string, + selectedRoute: string +} + +const CommunitiesLayout: React.FC = ({ children }) => { + + const { asPath, isReady } = useRouter() + const { isAuthenticated } = useAuthContext() + const { currentCommunity } = useCommunity() + const [showSwitcherModal, setSwitcherModal] = useState(false) + const [showOrgSwitcher, setShowOrgSwitcher] = useState(false) + const [pageRoutes, setPageRoutes] = useState({ basePath: '', selectedRoute: 'dashboard' }) + const [currentPage, setCurrentPage] = useState('communityVenues') + const [isHydrated, setIsHydrated] = useState(false) + + const router = useRouter() + + + // console.log('from layout',asPath)\\ + + const items: MenuProps['items'] = [ + { + key: 'communityVenues', + label: 'Community Venues' + }, + { + key: 'bookings', + label: 'Bookings' + }, + { + key: 'staff', + label: 'Staff' + } + ] - interface LayoutProps{ - children: ReactNode, - width?: number - } + const splittedRoutes = asPath.split('/') + // console.log('is re-rendering layout') + const selectedRoute = splittedRoutes && splittedRoutes[3] + console.log(selectedRoute) + splittedRoutes.pop() + + function onClickNavItemHandler(e: any) { + + router.push(`/organizations/communities/${e.key}`) + + setCurrentPage(e.key) - type PageRoute = { - basePath: string, - selectedRoute: string } - - const CommunitiesLayout: React.FC = ({children}) => { - - const {asPath, isReady} = useRouter() - const {isAuthenticated, currentUser, paseto} = useAuthContext() - const {currentCommunity} = useCommunity() - const [showSwitcherModal, setSwitcherModal] = useState(false) - const [showOrgSwitcher, setShowOrgSwitcher] = useState(false) - const [pageRoutes, setPageRoutes] = useState({basePath:'',selectedRoute:'dashboard'}) - const [currentPage, setCurrentPage] = useState('communityVenues') - const [isHydrated, setIsHydrated] = useState(false) - - const router = useRouter() - - - // console.log('from layout',asPath)\\ - - const items: MenuProps['items'] = [ - { - key:'communityVenues', - label: 'Community Venues' - }, - { - key:'bookings', - label: 'Bookings' - }, - { - key:'staff', - label: 'Staff' - } - ] - - const splittedRoutes = asPath.split('/') - // console.log('is re-rendering layout') - const selectedRoute = splittedRoutes && splittedRoutes[3] - console.log(selectedRoute) - splittedRoutes.pop() - - function onClickNavItemHandler(e:any){ - - router.push(`/organizations/communities/${e.key}`) - - setCurrentPage(e.key) - - } - useEffect(() => { - setIsHydrated(true) - if(isReady){ - // const basePath =splittedRoutes.join('/') - // setPageRoutes({ - // basePath:basePath, - // selectedRoute:selectedRoute, - // }) - setCurrentPage(selectedRoute) - } - }, [isReady]) - - - - if(!isReady){ -
- return -
+ useEffect(() => { + setIsHydrated(true) + if (isReady) { + // const basePath =splittedRoutes.join('/') + // setPageRoutes({ + // basePath:basePath, + // selectedRoute:selectedRoute, + // }) + setCurrentPage(selectedRoute) } - - return ( - - - { showOrgSwitcher? + return +
+ } + + return ( + + + {showOrgSwitcher ? setShowOrgSwitcher(!showOrgSwitcher)} - />:null} - {showSwitcherModal?setSwitcherModal(!showSwitcherModal)} - />:null} - - -
- - -
-
-
- -
- -
- { - !isAuthenticated ? - :( -
- {/* setSwitcherModal(!showSwitcherModal)}/> */} - setShowOrgSwitcher(!showOrgSwitcher)} user={{email:'mbappai@yahoo.com',role:'admin'}}/> -
- ) - } + onCloseModal={() => setShowOrgSwitcher(!showOrgSwitcher)} + /> : null} + {showSwitcherModal ? setSwitcherModal(!showSwitcherModal)} + /> : null} + + +
+ + +
+
+
+ +
+ +
+ { + !isAuthenticated ? + : ( +
+ {/* setSwitcherModal(!showSwitcherModal)}/> */} + setShowOrgSwitcher(!showOrgSwitcher)} user={{ email: 'mbappai@yahoo.com', role: 'admin' }} /> +
+ ) + } +
-
- - - - {isAuthenticated? children : } - - -
+
+ + + + {isAuthenticated ? children : } + + +
-
- ); - }; + + ); +}; export default CommunitiesLayout diff --git a/components/Layout/EventsLayout.tsx b/components/Layout/EventsLayout.tsx index 377e2e94..10afe32c 100644 --- a/components/Layout/EventsLayout.tsx +++ b/components/Layout/EventsLayout.tsx @@ -1,11 +1,7 @@ import { - - UserOutlined, - VideoCameraOutlined, - LeftOutlined - } from '@ant-design/icons'; - import { Menu, Breadcrumb, Typography ,Button, Layout, MenuProps, Spin, Col, Row} from 'antd'; -import Link from 'next/link'; + LeftOutlined +} from '@ant-design/icons'; +import { Menu, Typography, Button, Layout, MenuProps, Spin, Col, Row } from 'antd'; import { useRouter } from 'next/router'; import React, { ReactNode, useState, useEffect } from 'react'; import { useAuthContext } from '../../context/AuthContext'; @@ -14,137 +10,136 @@ import ErrorBoundary from '../shared/ErrorBoundary/ErrorBoundary'; import OrgSwitcherModal from '../shared/OrgSwitcherModal/OrgSwitcherModal'; import ServicesSwitcherModal from '../shared/ServicesSwitcherModal/ServicesSwitcherModal'; import UnAuthenticatedView from '../shared/UnAuthenticated/UnAuthenticatedView'; -import useCommunity from '../../hooks/useCommunity'; import useEvent from '../../hooks/useEvents'; import utils from '../../utils/env'; -const { Header, Sider, Content } = Layout; -const {Text, Title} = Typography +const { Header } = Layout; +const { Text, Title } = Typography - interface LayoutProps{ - children: ReactNode, - width?: number - } +interface LayoutProps { + children: ReactNode, + width?: number +} - type PageRoute = { - basePath: string, - selectedRoute: string - } - - const EventsLayout: React.FC = ({children}) => { - - const {asPath, isReady} = useRouter() - const {isAuthenticated, currentUser, paseto} = useAuthContext() - const {currentEvent} = useEvent() - const [showSwitcherModal, setSwitcherModal] = useState(false) - const [showOrgSwitcher, setShowOrgSwitcher] = useState(false) - const [pageRoutes, setPageRoutes] = useState({basePath:'',selectedRoute:'dashboard'}) - const [currentPage, setCurrentPage] = useState('communityVenues') - const [isHydrated, setIsHydrated] = useState(false) - - const router = useRouter() - - - // console.log('from layout',asPath)\\ - - const items: MenuProps['items'] = [ - - { - key:'bookings', - label: 'Bookings' - }, - { - key:'staff', - label: 'Staff' - } - ] - - const splittedRoutes = asPath.split('/') - // console.log('is re-rendering layout') - const selectedRoute = splittedRoutes && splittedRoutes[3] - console.log(selectedRoute) - splittedRoutes.pop() - - function onClickNavItemHandler(e:any){ - - router.push(`/organizations/events/${e.key}`) - - setCurrentPage(e.key) - +type PageRoute = { + basePath: string, + selectedRoute: string +} + +const EventsLayout: React.FC = ({ children }) => { + + const { asPath, isReady } = useRouter() + const { isAuthenticated, currentUser, paseto } = useAuthContext() + const { currentEvent } = useEvent() + const [showSwitcherModal, setSwitcherModal] = useState(false) + const [showOrgSwitcher, setShowOrgSwitcher] = useState(false) + const [pageRoutes, setPageRoutes] = useState({ basePath: '', selectedRoute: 'dashboard' }) + const [currentPage, setCurrentPage] = useState('communityVenues') + const [isHydrated, setIsHydrated] = useState(false) + + const router = useRouter() + + + // console.log('from layout',asPath)\\ + + const items: MenuProps['items'] = [ + + { + key: 'bookings', + label: 'Bookings' + }, + { + key: 'staff', + label: 'Staff' } + ] + + const splittedRoutes = asPath.split('/') + // console.log('is re-rendering layout') + const selectedRoute = splittedRoutes && splittedRoutes[3] + console.log(selectedRoute) + splittedRoutes.pop() - useEffect(() => { - setIsHydrated(true) - if(isReady){ - // const basePath =splittedRoutes.join('/') - // setPageRoutes({ - // basePath:basePath, - // selectedRoute:selectedRoute, - // }) - setCurrentPage(selectedRoute) - } - }, [isReady]) - - - - if(!isReady){ -
- return -
+ function onClickNavItemHandler(e: any) { + + router.push(`/organizations/events/${e.key}`) + + setCurrentPage(e.key) + + } + + useEffect(() => { + setIsHydrated(true) + if (isReady) { + // const basePath =splittedRoutes.join('/') + // setPageRoutes({ + // basePath:basePath, + // selectedRoute:selectedRoute, + // }) + setCurrentPage(selectedRoute) } - - return ( - - - { showOrgSwitcher? + return +
+ } + + return ( + + + {showOrgSwitcher ? setShowOrgSwitcher(!showOrgSwitcher)} - />:null} - {showSwitcherModal?setSwitcherModal(!showSwitcherModal)} - />:null} - - -
- - -
-
-
- -
- -
- { - !isAuthenticated ? - :( -
- {/* setSwitcherModal(!showSwitcherModal)}/> */} - setShowOrgSwitcher(!showOrgSwitcher)} user={{email:'mbappai@yahoo.com',role:'admin'}}/> -
- ) - } + onCloseModal={() => setShowOrgSwitcher(!showOrgSwitcher)} + /> : null} + {showSwitcherModal ? setSwitcherModal(!showSwitcherModal)} + /> : null} + + +
+ + +
+
+
+ +
+ +
+ { + !isAuthenticated ? + : ( +
+ {/* setSwitcherModal(!showSwitcherModal)}/> */} + setShowOrgSwitcher(!showOrgSwitcher)} user={{ email: 'mbappai@yahoo.com', role: 'admin' }} /> +
+ ) + } +
-
- - - - {isAuthenticated? children : } - - -
+
+ + + + {isAuthenticated ? children : } + + +
-
- ); - }; + + ); +}; export default EventsLayout diff --git a/components/Layout/ManagerBookingsLayout.tsx b/components/Layout/ManagerBookingsLayout.tsx index 87ce34da..35540501 100644 --- a/components/Layout/ManagerBookingsLayout.tsx +++ b/components/Layout/ManagerBookingsLayout.tsx @@ -8,11 +8,11 @@ const {Content} = Layout const {Title} = Typography interface Props{ - children: ReactNode + children: ReactNode } export default function ManagerBookingsLayout({children}:Props){ - const {asPath,push,query,isReady} = useRouter() + const {asPath,isReady} = useRouter() const [selectedPage, setSelectedPage] = useState('service-types') diff --git a/components/Layout/ManagerLayout.tsx b/components/Layout/ManagerLayout.tsx index 0edcc059..09c7e534 100644 --- a/components/Layout/ManagerLayout.tsx +++ b/components/Layout/ManagerLayout.tsx @@ -1,106 +1,101 @@ import { - UserOutlined, - BankOutlined, - BranchesOutlined, - PieChartOutlined, - BookOutlined - } from '@ant-design/icons'; - import { Menu, Breadcrumb, Typography ,Button, Layout, MenuProps, Spin, Col, Row} from 'antd'; + UserOutlined, + BankOutlined, + BranchesOutlined, + BookOutlined +} from '@ant-design/icons'; +import { Menu, Typography, Button, Layout, Spin, Col, Row } from 'antd'; import Link from 'next/link'; import { useRouter } from 'next/router'; import React, { ReactNode, useState, useEffect } from 'react'; import { useAuthContext } from '../../context/AuthContext'; import CurrentUser from '../Header/CurrentUser/CurrentUser'; -import OrgSwitcher from '../Header/OrgSwitcherButton/OrgSwitcherButton'; -import ServiceSwitcherButton from '../Header/ServicesSwitcherButton/ServicesSwitcherButton'; import ErrorBoundary from '../shared/ErrorBoundary/ErrorBoundary'; -// import OrgSwitcherModal from '../OrgSwitcherModal/OrgSwitcherModal'; -// import ServicesSwitcherModal from '../ServicesSwitcherModal/ServicesSwitcherModal'; import UnAuthenticatedView from '../shared/UnAuthenticated/UnAuthenticatedView'; import utils from '../../utils/env'; -const { Header, Sider, Content } = Layout; -const {Text} = Typography +const { Header } = Layout; +const { Text } = Typography - interface LayoutProps{ - children: ReactNode, - width?: number - } +interface LayoutProps { + children: ReactNode, + width?: number +} + +type PageRoute = { + basePath: string, + selectedRoute: string +} + +const ManagerLayout: React.FC = ({ children }) => { + + const { asPath, isReady } = useRouter() + const { isAuthenticated } = useAuthContext() + // const [showSwitcherModal, setSwitcherModal] = useState(false) + const [showOrgSwitcher, setShowOrgSwitcher] = useState(false) + const [pageRoutes, setPageRoutes] = useState({ basePath: '', selectedRoute: 'dashboard' }) + const [selectedPage, setSelectedPage] = useState('organizations') - type PageRoute = { - basePath: string, - selectedRoute: string - } - - const ManagerLayout: React.FC = ({children}) => { - - const {asPath,push,query,isReady} = useRouter() - const {isAuthenticated} = useAuthContext() - // const [showSwitcherModal, setSwitcherModal] = useState(false) - const [showOrgSwitcher, setShowOrgSwitcher] = useState(false) - const [pageRoutes, setPageRoutes] = useState({basePath:'',selectedRoute:'dashboard'}) - const [selectedPage, setSelectedPage] = useState('organizations') - - - - const splittedRoutes = asPath.split('/') - const routeFromURl = splittedRoutes && splittedRoutes[2] - splittedRoutes.pop() - - - useEffect(() => { - if(isReady){ - const basePath =splittedRoutes.join('/') - // setPageRoutes({ - // basePath:basePath, - // selectedRoute:selectedRoute, - // }) - setSelectedPage(routeFromURl) - } - }, [isReady]) - - - - if(!isReady){ -
- return -
- } - function onClickNavItemHandler(e:any){ - // push(`/manager/${e.key}`) - setSelectedPage(e.key) - + const splittedRoutes = asPath.split('/') + const routeFromURl = splittedRoutes && splittedRoutes[2] + splittedRoutes.pop() + + + useEffect(() => { + if (isReady) { + const basePath = splittedRoutes.join('/') + // setPageRoutes({ + // basePath:basePath, + // selectedRoute:selectedRoute, + // }) + setSelectedPage(routeFromURl) } - - return ( - - - -
- -
- {/* + }, [isReady]) + + + + if (!isReady) { +
+ return +
+ } + + function onClickNavItemHandler(e: any) { + + // push(`/manager/${e.key}`) + setSelectedPage(e.key) + + } + + return ( + + + +
+ + - -
- - { !isAuthenticated ? : - setShowOrgSwitcher(!showOrgSwitcher)} user={{email:'mbappai@yahoo.com',role:'admin'}}/> - } -
- - -
- - {/* + +
+ +
+ + {!isAuthenticated ? : + setShowOrgSwitcher(!showOrgSwitcher)} user={{ email: 'mbappai@yahoo.com', role: 'admin' }} /> + } +
+ + +
+ + {/* */} - - - - - {isAuthenticated? children : } - + + + + + {isAuthenticated ? children : } + - - ); - }; + + ); +}; export default ManagerLayout -const navItems=[ +const navItems = [ // { // key:'dashboard', // label: Dashboard, // icon: // }, { - key:'organizations', - label:Organizations, + key: 'organizations', + label: Organizations, icon: }, { - key:'bookings', - label:Bookings, + key: 'bookings', + label: Bookings, icon: }, { - key:'users', - label:Users, + key: 'users', + label: Users, icon: }, { - key:'platform', - label:Platform, + key: 'platform', + label: Platform, icon: }, ] \ No newline at end of file diff --git a/components/Layout/PlatformLayout.tsx b/components/Layout/PlatformLayout.tsx index 7b38a46a..349714f5 100644 --- a/components/Layout/PlatformLayout.tsx +++ b/components/Layout/PlatformLayout.tsx @@ -9,11 +9,11 @@ const {Title} = Typography interface PlatformLayoutProps{ - children: ReactNode + children: ReactNode } export default function PlatformLayout({children}:PlatformLayoutProps){ - const {asPath,push,query,isReady} = useRouter() + const {asPath,isReady} = useRouter() const [selectedPage, setSelectedPage] = useState('venues') diff --git a/components/Layout/ServiceLayout.tsx b/components/Layout/ServiceLayout.tsx index 6f78ac88..cef5f877 100644 --- a/components/Layout/ServiceLayout.tsx +++ b/components/Layout/ServiceLayout.tsx @@ -1,5 +1,5 @@ import { ReactNode, useEffect, useState } from "react" -import {Typography, Row, Col, Button, Skeleton, Layout, Segmented, Menu, MenuProps} from 'antd' +import {Typography, Row, Col, Button, Skeleton, Layout, Menu, MenuProps} from 'antd' import CurrentUser from "../Header/CurrentUser/CurrentUser" import { useOrgContext } from "../../context/OrgContext" import { useRouter } from "next/router" diff --git a/components/Layout/VenuesLayout.tsx b/components/Layout/VenuesLayout.tsx index c6139c9f..8fa8bba1 100644 --- a/components/Layout/VenuesLayout.tsx +++ b/components/Layout/VenuesLayout.tsx @@ -1,11 +1,7 @@ import { - - UserOutlined, - VideoCameraOutlined, LeftOutlined } from '@ant-design/icons'; - import { Menu, Breadcrumb, Typography ,Button, Layout, MenuProps, Spin, Col, Row} from 'antd'; -import Link from 'next/link'; + import { Menu, Typography ,Button, Layout, MenuProps, Spin, Col, Row} from 'antd'; import { useRouter } from 'next/router'; import React, { ReactNode, useState, useEffect } from 'react'; import { useAuthContext } from '../../context/AuthContext'; @@ -14,7 +10,6 @@ import ErrorBoundary from '../shared/ErrorBoundary/ErrorBoundary'; import OrgSwitcherModal from '../shared/OrgSwitcherModal/OrgSwitcherModal'; import ServicesSwitcherModal from '../shared/ServicesSwitcherModal/ServicesSwitcherModal'; import UnAuthenticatedView from '../shared/UnAuthenticated/UnAuthenticatedView'; -import useCommunity from '../../hooks/useCommunity'; import useServices from '../../hooks/useServices'; import utils from '../../utils/env'; diff --git a/components/Layout/layout.tsx b/components/Layout/layout.tsx index 0f1ad89a..2c7fc09a 100644 --- a/components/Layout/layout.tsx +++ b/components/Layout/layout.tsx @@ -1,15 +1,10 @@ -import { - UserOutlined, - VideoCameraOutlined, - } from '@ant-design/icons'; - import { Menu, Breadcrumb, Typography ,Button, Layout, MenuProps, Spin, Col, Row} from 'antd'; +import { Typography ,Button, Layout, Spin, Col, Row} from 'antd'; import Link from 'next/link'; import { useRouter } from 'next/router'; import React, { ReactNode, useState, useEffect } from 'react'; import { useAuthContext } from '../../context/AuthContext'; import CurrentUser from '../Header/CurrentUser/CurrentUser'; -import OrgSwitcher from '../Header/OrgSwitcherButton/OrgSwitcherButton'; import ServiceSwitcherButton from '../Header/ServicesSwitcherButton/ServicesSwitcherButton'; import ErrorBoundary from '../shared/ErrorBoundary/ErrorBoundary'; import OrgSwitcherModal from '../shared/OrgSwitcherModal/OrgSwitcherModal'; @@ -36,7 +31,7 @@ const {Text} = Typography const AppLayout: React.FC = ({children}) => { const {asPath, isReady} = useRouter() - const {isAuthenticated, currentUser, paseto} = useAuthContext() + const {isAuthenticated} = useAuthContext() const [showSwitcherModal, setSwitcherModal] = useState(false) const [showOrgSwitcher, setShowOrgSwitcher] = useState(false) const [pageRoutes, setPageRoutes] = useState({basePath:'',selectedRoute:'dashboard'}) diff --git a/components/LoungePage/RegisterOrgForm/RegisterOrgForm.tsx b/components/LoungePage/RegisterOrgForm/RegisterOrgForm.tsx index 191004f2..eef3e0e7 100644 --- a/components/LoungePage/RegisterOrgForm/RegisterOrgForm.tsx +++ b/components/LoungePage/RegisterOrgForm/RegisterOrgForm.tsx @@ -1,4 +1,4 @@ -import { Form, Input, Upload, Button, Divider } from "antd"; +import { Form, Input, Upload, Button } from "antd"; import {UploadOutlined} from '@ant-design/icons' import {OrgFormData} from '../../../types/OrganisationTypes' import { usePlacesWidget } from "react-google-autocomplete"; diff --git a/components/Manager/Banks/BanksView.tsx b/components/Manager/Banks/BanksView.tsx index 7f795950..5933056a 100644 --- a/components/Manager/Banks/BanksView.tsx +++ b/components/Manager/Banks/BanksView.tsx @@ -1,15 +1,12 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; const {Text} = Typography -import { SearchOutlined } from '@ant-design/icons'; import React, { useRef, useState } from 'react' -import {Typography,Button,Avatar, Upload, Tag, Image, Descriptions, Table, InputRef, Input, Space, DatePicker, Radio, Dropdown, MenuProps, Drawer, Row, Col, Divider, Form} from 'antd' +import {Typography,Button, Image, Table, Input, Space, Radio, Dropdown, Drawer, Row, Col, Divider, Form} from 'antd' import axios from 'axios'; import {MoreOutlined,ReloadOutlined} from '@ant-design/icons' -import { FilterDropdownProps, FilterValue, SorterResult } from 'antd/lib/table/interface'; - import { useAuthContext } from '../../../context/AuthContext'; import dayjs from 'dayjs' -import { ColumnsType, ColumnType, TableProps } from 'antd/lib/table'; +import { ColumnsType, TableProps } from 'antd/lib/table'; import { Bank } from "./Banks.types"; import { usePlacesWidget } from "react-google-autocomplete"; import useUrlPrefix from "../../../hooks/useUrlPrefix"; @@ -357,7 +354,7 @@ function EditableName({selectedBank}:EditableProp){ - @@ -514,7 +513,7 @@ function EditableRole({selectedServiceItemType}:EditableProp){ - @@ -503,7 +503,7 @@ function EditableRole({selectedServiceType}:EditableProp){ - diff --git a/components/StaffPage/index.tsx b/components/StaffPage/index.tsx index a09a97ac..178287ac 100644 --- a/components/StaffPage/index.tsx +++ b/components/StaffPage/index.tsx @@ -337,7 +337,7 @@ function handleSubmit(formData:any){ - @@ -539,7 +539,7 @@ export function EditableRadio({id, options, selectedItem, fieldName, currentFiel - + + + {/* OTP input (only if email is entered) */} + {email && ( +
+ Enter OTP + setOtp(e.target.value)} + /> +
+ )} + + {/* Verify & Continue Button */} + + + + + + ); +} diff --git a/components/shared/Editables/index.tsx b/components/shared/Editables/index.tsx index 044ea6d6..fbd10d8c 100644 --- a/components/shared/Editables/index.tsx +++ b/components/shared/Editables/index.tsx @@ -9,9 +9,9 @@ import { usePlacesWidget } from "react-google-autocomplete" import { useAuthContext } from "../../../context/AuthContext" import useUrlPrefix from "../../../hooks/useUrlPrefix" import utils from "../../../utils/env" -const countryList = require('country-list') - +import countryList from 'country-list'; + interface EditableProps{ id: string, @@ -101,7 +101,7 @@ interface EditableProps{ -
- ) + ) } \ No newline at end of file diff --git a/pages/_app.tsx b/pages/_app.tsx index 761af1a9..da52bc80 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -9,6 +9,9 @@ import ErrorBoundary from '../components/shared/ErrorBoundary/ErrorBoundary'; import {ConfigProvider} from 'antd' import Head from 'next/head' import { ComponentType, ReactNode } from 'react'; +import AppWalletProvider from '../components/AppWalletProvider'; +import { AppKit } from '../context/appkit'; +import { ChakraProvider } from '@chakra-ui/react'; type ComponentWithPageLayout = AppProps & { Component: AppProps['Component'] & { @@ -40,6 +43,8 @@ function MyApp({ Component, pageProps }: ComponentWithPageLayout) { + + @@ -57,7 +62,10 @@ function MyApp({ Component, pageProps }: ComponentWithPageLayout) { - : + : + + + } {/* */} @@ -66,6 +74,8 @@ function MyApp({ Component, pageProps }: ComponentWithPageLayout) { + + diff --git a/pages/index.tsx b/pages/index.tsx index d3d975dd..eb6b21e2 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -6,9 +6,10 @@ import { useAuthContext } from '../context/AuthContext'; import Logo from './logo.svg' import Image from 'next/image' import utils from '../utils/env'; +import { AuthButton } from '../components/AuthButton'; const {Title,Text} = Typography; - + export default function Login(){ const {replace} = useRouter() @@ -63,7 +64,9 @@ function LoginView({handleLogin}: LoginViewProps) { Start creating and managing <br/> events • communities • services Flexable provides the easiest and fastest way to create and manage events, communities and services - + {/* */} + + ; } diff --git a/pages/manager/banks.tsx b/pages/manager/banks.tsx index c25dac78..baf9f2fe 100644 --- a/pages/manager/banks.tsx +++ b/pages/manager/banks.tsx @@ -13,7 +13,7 @@ export default function ManagerOrganizations(){ return( - + {/*
diff --git a/pages/manager/bookings/events.tsx b/pages/manager/bookings/events.tsx index ab47a56e..8557bc33 100644 --- a/pages/manager/bookings/events.tsx +++ b/pages/manager/bookings/events.tsx @@ -9,7 +9,7 @@ import useUrlPrefix from "../../../hooks/useUrlPrefix"; import { EventOrder } from "../../../types/Booking"; import { numberFormatter } from "../../../utils/numberFormatter"; // import converter from 'json-2-csv' -import * as converter from 'json-2-csv'; +import * as converter from 'json-2-csv'; // import { json2csv } from 'json-2-csv' const {Title,Text} = Typography diff --git a/pages/manager/dashboard.tsx b/pages/manager/dashboard.tsx index feacf6e0..1676ebfc 100644 --- a/pages/manager/dashboard.tsx +++ b/pages/manager/dashboard.tsx @@ -8,7 +8,7 @@ import AdminLayout from '../../components/Manager/Layout/Layout'; // import AwaitingOrgsStats from '../components/AdminDashboard/AwaitingOrgsStats/AwaitingOrgs'; // import ApprovedOrgsStats from '../components/AdminDashboard/ApprovedOrgsStats/ApprovedOrgsStats'; const {Title} = Typography -export default function Dashboard(){ +export default function Dashboard(){ return( diff --git a/pages/manager/organizations/new.tsx b/pages/manager/organizations/new.tsx index abfe438c..d32258d3 100644 --- a/pages/manager/organizations/new.tsx +++ b/pages/manager/organizations/new.tsx @@ -350,7 +350,7 @@ export default function NewOrgForm(){ {/* onCancelFormCreation */} - diff --git a/pages/organizations/billings/new.tsx b/pages/organizations/billings/new.tsx index 9defaa5b..0761c5f1 100644 --- a/pages/organizations/billings/new.tsx +++ b/pages/organizations/billings/new.tsx @@ -11,13 +11,14 @@ import axios from 'axios' import { useAuthContext } from '../../../context/AuthContext' import useUrlPrefix from '../../../hooks/useUrlPrefix' import utils from '../../../utils/env' -const countryList = require('country-list') - +import getNames from 'country-list'; + const {Title} = Typography; + const {Option} = Select -const list = countryList.getNames() -const america = countryList.getName('US') +const list = getNames.getNames() +const america = getNames.getName('US') const sortedList = list.sort() const prioritizedList = [america, ...sortedList] diff --git a/pages/organizations/communities/bookings/index.tsx b/pages/organizations/communities/bookings/index.tsx index ffcbf591..64af778a 100644 --- a/pages/organizations/communities/bookings/index.tsx +++ b/pages/organizations/communities/bookings/index.tsx @@ -11,7 +11,7 @@ import { CommunityOrder, Order } from "../../../../types/Booking"; import { ServiceItem } from "../../../../types/Services"; import { numberFormatter } from "../../../../utils/numberFormatter"; -const {Title} = Typography +const {Title} = Typography import {ReloadOutlined, CheckOutlined,StopOutlined,MoreOutlined} from '@ant-design/icons' diff --git a/pages/organizations/communities/communityVenues/index.tsx b/pages/organizations/communities/communityVenues/index.tsx index 09b1be07..1f8d89bf 100644 --- a/pages/organizations/communities/communityVenues/index.tsx +++ b/pages/organizations/communities/communityVenues/index.tsx @@ -684,7 +684,7 @@ const {isLoading:isEditing} = mutation - diff --git a/pages/organizations/communities/index.tsx b/pages/organizations/communities/index.tsx index bcdad20b..79fe7a60 100644 --- a/pages/organizations/communities/index.tsx +++ b/pages/organizations/communities/index.tsx @@ -1,20 +1,15 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import useOrgs from "../../../hooks/useOrgs"; -const {Text, Title} = Typography; -import React, { ReactNode, useEffect, useRef, useState } from 'react' -import {Typography,Button, Skeleton, Badge, Image, Table, Input, Radio, Drawer, Row, Col, Form, Modal, Alert, notification, Dropdown, MenuProps, Tag, Space, Upload, Popover} from 'antd' +const { Text, Title } = Typography; +import React, { useEffect, useState } from 'react' +import { Typography, Button, Image, Table, Input, Radio, Drawer, Row, Col, Form, Modal, notification, Space, Upload, Popover, Spin, message } from 'antd' import { useRouter } from 'next/router' import axios from 'axios'; -import { MoreOutlined, ReloadOutlined, ArrowLeftOutlined,CopyOutlined, PlusOutlined} from '@ant-design/icons' - +import { MoreOutlined, ReloadOutlined, CopyOutlined, PlusOutlined } from '@ant-design/icons' import { useAuthContext } from '../../../context/AuthContext'; -import { useServicesContext } from '../../../context/ServicesContext'; import dayjs from 'dayjs' -import { ColumnsType, ColumnType, TableProps } from 'antd/lib/table'; +import { ColumnsType, TableProps } from 'antd/lib/table'; import { useOrgContext } from "../../../context/OrgContext"; - - import useUrlPrefix from "../../../hooks/useUrlPrefix"; import ServiceLayout from "../../../components/Layout/ServiceLayout"; import { Community } from "../../../types/Community"; @@ -24,273 +19,389 @@ import { uploadToPinata } from "../../../utils/nftStorage"; import { IMAGE_PLACEHOLDER_HASH } from "../../../constants"; import useRole from "../../../hooks/useRole"; import utils from "../../../utils/env"; +import relativeTime from 'dayjs/plugin/relativeTime'; +import contractABI from '../../../analyze/FlexableVendor.json'; +import { ethers ,Eip1193Provider} from "ethers"; +const CONTRACT_ADDRESS = '0xbCAF57c030cFb333fd37dc3662a81DaA76AAF1f5'; // Replace with your contract address -const {TextArea} = Input +const { TextArea } = Input -var relativeTime = require('dayjs/plugin/relativeTime') dayjs.extend(relativeTime) -function Communities(){ +function Communities() { - const {paseto,currentUser} = useAuthContext() - const {currentOrg} = useOrgContext() // coming from local storage - const queryClient = useQueryClient() - const router = useRouter() - const {switchCommunity} = useCommunity() - // const [items, setItems] = useState([]) + const { paseto } = useAuthContext() + const { currentOrg } = useOrgContext() // coming from local storage + const queryClient = useQueryClient() + const router = useRouter() + const { switchCommunity } = useCommunity() + const [isDrawerOpen, setIsDrawerOpen] = useState(false) + const [pageNumber, setPageNumber] = useState(1) + const [pageSize, setPageSize] = useState(10) + const [vendorName, setVendorName] = useState(''); + const [vendorURI, setVendorURI] = useState(''); + const [isVendorCreated, setIsVendorCreated] = useState(false); // track vendor status + const [creating, setCreating] = useState(false); + const [selectedRecord, setSelectedRecord] = useState({}) + const [currentFilter, setCurrentFilter] = useState({ id: '1', name: 'Active' }) + const [loadingVendorStatus, setLoadingVendorStatus] = useState(true); - const isBankConnected = currentOrg?.isBankConnected + const urlPrefix = useUrlPrefix() + const getContract = async () => { + if (!window.ethereum ) throw new Error('MetaMask is not installed'); + const provider = new ethers.BrowserProvider(window.ethereum as unknown as ethers.Eip1193Provider); + const signer = await provider.getSigner(); + return new ethers.Contract(CONTRACT_ADDRESS, contractABI.abi, signer); + }; + + const handleCreateVendor = async () => { + try { + setCreating(true); + const contract = await getContract(); + const provider = new ethers.BrowserProvider(window.ethereum as unknown as ethers.Eip1193Provider); + const signer = await provider.getSigner(); + const userAddress = await signer.getAddress(); + + const vendor = await contract.createVendor(userAddress, vendorName, vendorURI); + if (vendor.vendorName && vendor.vendorName !== '') { + message.info('Vendor already exists.'); + setIsVendorCreated(true); + return; + } - const [isDrawerOpen, setIsDrawerOpen] = useState(false) - const [pageNumber, setPageNumber] = useState(1) - const [pageSize, setPageSize] = useState(10) + const tx = await contract.createVendor(userAddress, vendorName, vendorURI); + await tx.wait(); - + message.success('Vendor created!'); + setIsVendorCreated(true); // ✅ hide form after creation + localStorage.setItem('vendorCreated', 'true'); + } catch (error: any) { + console.error('Error creating vendor:', error); - const [selectedRecord, setSelectedRecord] = useState({}) - const [currentFilter, setCurrentFilter] = useState({id:'1',name: 'Active'}) - const [isHydrated, setIsHydrated] = useState(false) + const alreadyExists = error?.reason?.toLowerCase().includes('already') || + error?.message?.toLowerCase().includes('already'); - - const urlPrefix = useUrlPrefix() + if (alreadyExists) { + message.info('Vendor already exists.'); + setIsVendorCreated(true); // ✅ allow UI update + } else { + message.error(error?.reason || error?.message || 'Transaction failed'); + } + } finally { + setCreating(false); + } + }; + const checkVendorStatus = async () => { + try { + const contract = await getContract(); + const provider = new ethers.BrowserProvider(window.ethereum as unknown as ethers.Eip1193Provider); + const signer = await provider.getSigner(); + const userAddress = await signer.getAddress(); - - async function fetchCommunities(){ - const res = await axios({ - method:'get', - //@ts-ignore - url:`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community?orgId=${currentOrg.orgId}&pageNumber=${pageNumber}&pageSize=${pageSize}&status=${currentFilter.id}`, + console.log('Checking vendor for address:', userAddress); - headers:{ - "Authorization": paseto - } - }) + const vendor = await contract.vendors(userAddress); + console.log('Vendor from contract:', vendor); - return res.data.data; - + if (vendor?.vendorName && vendor.vendorName !== '') { + setIsVendorCreated(true); + } else { + setIsVendorCreated(false); + } + } catch (err) { + console.error('Vendor check failed:', err); + setIsVendorCreated(false); + } finally { + setLoadingVendorStatus(false); } + }; - async function reActivateCommunityHandler(record:Community){ - const res = await axios({ - method:'patch', - url:`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, - data:{ - // key:'status', - status: '1', - id: record.id - }, - headers:{ - "Authorization": paseto - } - }) - return res; - } - + useEffect(() => { + checkVendorStatus(); + }, []); - const reactivateCommunity = useMutation(reActivateCommunityHandler,{ - onSettled:()=>{ - queryClient.invalidateQueries({queryKey:['community']}) + +useEffect(() => { + const isAlreadyCreated = localStorage.getItem('vendorCreated') === 'true'; + if (isAlreadyCreated) { + setIsVendorCreated(true); + setLoadingVendorStatus(false); + } else { + checkVendorStatus(); + } +}, []); + + + async function fetchCommunities() { + const res = await axios({ + method: 'get', + //@ts-ignore + url: `${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community?orgId=${currentOrg.orgId}&pageNumber=${pageNumber}&pageSize=${pageSize}&status=${currentFilter.id}`, + + headers: { + "Authorization": paseto } }) - + return res.data.data; - - // @ts-ignore - const communityQuery = useQuery({queryKey:['community', currentOrg.orgId, currentFilter.name, pageNumber ], queryFn:fetchCommunities, enabled: paseto !== ''}) - const data = communityQuery.data && communityQuery.data - // const totalLength = communityQuery.data && communityQuery.data; - const totalLength = 0; + } + async function reActivateCommunityHandler(record: Community) { + const res = await axios({ + method: 'patch', + url: `${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, + data: { + // key:'status', + status: '1', + id: record.id + }, + headers: { + "Authorization": paseto + } + }) + return res; + } - const handleChange: TableProps['onChange'] = (data) => { - setPageSize(data.pageSize) - //@ts-ignore - setPageNumber(data.current); // Subtracting 1 because pageSize param in url starts counting from 0 - }; - - -function gotoCommunityItemsPage(community:Community){ - // switch org - // get community switcher here - switchCommunity(community) - // navigate user to services page - router.push('/organizations/communities/communityVenues') // -} + const reactivateCommunity = useMutation(reActivateCommunityHandler, { + onSettled: () => { + queryClient.invalidateQueries({ queryKey: ['community'] }) + } + }) - function viewCommunityDetails(service:Community){ - // set state - setSelectedRecord(service) - // opne drawer - setIsDrawerOpen(true) - } - - - const onMenuClick=( record:Community) => { - viewCommunityDetails(record) - console.log('click', record); - }; - - - - const columns: ColumnsType = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name', - fixed:'left', - width:'250px', - ellipsis:true, - render:(_,record)=>{ - return( -
- Organization logo -
- -
-
- ) - }, - }, - { - title: 'Number of Venues', - dataIndex: 'communityVenuesCount', - key: 'communityVenuesCount', - width:'100px', - }, - { - title: 'Platform Fee', - dataIndex: 'platformFee', - // hidden:true, - key: 'platformFee', - width:'100px', - render: (platformFee)=>( -
- {${platformFee}} -
- ) - }, - { - title: 'Price', - dataIndex: 'price', - key: 'price', - width:'100px', - render: (price)=>( -
- $ - {price/100} + + + // @ts-ignore + const communityQuery = useQuery({ queryKey: ['community', currentOrg.orgId, currentFilter.name, pageNumber], queryFn: fetchCommunities, enabled: paseto !== '' }) + const data = communityQuery.data && communityQuery.data + // const totalLength = communityQuery.data && communityQuery.data; + const totalLength = 0; + + + + const handleChange: TableProps['onChange'] = (data) => { + setPageSize(data.pageSize) + //@ts-ignore + setPageNumber(data.current); // Subtracting 1 because pageSize param in url starts counting from 0 + }; + + + function gotoCommunityItemsPage(community: Community) { + // switch org + // get community switcher here + switchCommunity(community) + // navigate user to services page + router.push('/organizations/communities/communityVenues') // + } + + + function viewCommunityDetails(service: Community) { + // set state + setSelectedRecord(service) + // opne drawer + setIsDrawerOpen(true) + + } + + + const onMenuClick = (record: Community) => { + viewCommunityDetails(record) + console.log('click', record); + }; + + + + const columns: ColumnsType = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + fixed: 'left', + width: '250px', + ellipsis: true, + render: (_, record) => { + return ( +
+ Organization logo +
+ +
) }, - { - title: 'Market Value', - dataIndex: 'totalMarketValue', - key: 'totalMarketValue', - width:'100px', - render: (totalMarketValue)=>( -
- $ - {totalMarketValue/100} -
+ }, + { + title: 'Number of Venues', + dataIndex: 'communityVenuesCount', + key: 'communityVenuesCount', + width: '100px', + }, + { + title: 'Platform Fee', + dataIndex: 'platformFee', + // hidden:true, + key: 'platformFee', + width: '100px', + render: (platformFee) => ( +
+ {${platformFee}} +
+ ) + }, + { + title: 'Price', + dataIndex: 'price', + key: 'price', + width: '100px', + render: (price) => ( +
+ $ + {price / 100} +
+ ) + }, + { + title: 'Market Value', + dataIndex: 'totalMarketValue', + key: 'totalMarketValue', + width: '100px', + render: (totalMarketValue) => ( +
+ $ + {totalMarketValue / 100} +
+ ) + }, + { + title: 'Created On', + dataIndex: 'createdAt', + key: 'createdAt', + width: '120px', + render: (_, record) => { + const date = dayjs(record.createdAt).format('MMM DD, YYYY') + return ( + {date} ) }, - { - title: 'Created On', - dataIndex: 'createdAt', - key: 'createdAt', - width:'120px', - render: (_,record)=>{ - const date = dayjs(record.createdAt).format('MMM DD, YYYY') - return( - {date} - ) - }, }, { - dataIndex: 'actions', + dataIndex: 'actions', key: 'actions', fixed: 'right', - width:currentFilter.name === 'Inactive'?'150px':'50px', + width: currentFilter.name === 'Inactive' ? '150px' : '50px', //@ts-ignore - render:(_,record:Community)=>{ - if(currentFilter.name === 'Inactive'){ - return () - }else{ - return ) + } else { + return - -
-
- - - {/* } */} - - {/* { - allCommunitysQuery.data && allCommunitysLength === 0 - ? - - - : */} - record.id} - // @ts-ignore - onChange={handleChange} - loading={communityQuery.isLoading || communityQuery.isRefetching} - // @ts-ignore - columns={columns} - dataSource={data} - pagination={{ - total:totalLength, - showTotal:(total) => `Total: ${total} items`, - }} - /> - {/* } */} - - { - isDrawerOpen - ? - :null - } - - - ) + + return ( +
+
+ Communities +
+
+
+ {/* filters */} + + {filters.map((filter: any) => ( + setCurrentFilter(filter)} value={filter.id}>{filter.name} + ) + )} + +
+ + + + {loadingVendorStatus ? ( + + ) : isVendorCreated ? ( + <> + Vendor created ✅ + + + ) : ( + <> + setVendorName(e.target.value)} + style={{ width: 180 }} + /> + setVendorURI(e.target.value)} + style={{ width: 200 }} + /> + + + )} + + +
+
+ +
+ {/* } */} + + +
record.id} + // @ts-ignore + onChange={handleChange} + loading={communityQuery.isLoading || communityQuery.isRefetching} + // @ts-ignore + columns={columns} + dataSource={data} + pagination={{ + total: totalLength, + showTotal: (total) => `Total: ${total} items`, + }} + /> + {/* } */} + + { + isDrawerOpen + ? + : null + } + + + ) } @@ -301,227 +412,212 @@ Communities.PageLayout = ServiceLayout -interface DrawerProps{ +interface DrawerProps { selectedRecord: Community, isDrawerOpen: boolean, - closeDrawer: (value:boolean)=>void + closeDrawer: (value: boolean) => void } -function DetailDrawer({selectedRecord,isDrawerOpen,closeDrawer}:DrawerProps){ +function DetailDrawer({ selectedRecord, isDrawerOpen, closeDrawer }: DrawerProps) { -const queryClient = useQueryClient() -const router = useRouter() -const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false) -const {currentOrg} = useOrgContext() + const queryClient = useQueryClient() + const router = useRouter() + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false) + const { currentOrg } = useOrgContext() -const isBankConnected = currentOrg?.isBankConnected + const isBankConnected = currentOrg?.isBankConnected -const {isManager, isSuperAdmin} = useRole() + const { isManager, isSuperAdmin } = useRole() -const {switchCommunity} = useCommunity() -const {paseto} = useAuthContext() + const { switchCommunity } = useCommunity() + const { paseto } = useAuthContext() -const urlPrefix = useUrlPrefix() + const urlPrefix = useUrlPrefix() -function closeDrawerHandler(){ - queryClient.invalidateQueries(['community']) - closeDrawer(!isDrawerOpen) -} + function closeDrawerHandler() { + queryClient.invalidateQueries(['community']) + closeDrawer(!isDrawerOpen) + } -function gotoCommunity(community:Community){ - switchCommunity(community) - // navigate user to services page - router.push('/organizations/communities/communityVenues') -} + function gotoCommunity(community: Community) { + switchCommunity(community) + // navigate user to services page + router.push('/organizations/communities/communityVenues') + } -function toggleDeleteModal(){ - setIsDeleteModalOpen(!isDeleteModalOpen) -} + function toggleDeleteModal() { + setIsDeleteModalOpen(!isDeleteModalOpen) + } -function deleteCommunity(){ + function deleteCommunity() { - // mutate record - deleteData.mutate(selectedRecord,{ - onSuccess:()=>{ - notification['success']({ - message: 'Successfully deactivated community!' - }) - queryClient.invalidateQueries(['community']) - toggleDeleteModal() - closeDrawerHandler() - }, - onSettled:()=>{ - queryClient.invalidateQueries(['community']) - }, - onError:(err)=>{ + // mutate record + deleteData.mutate(selectedRecord, { + onSuccess: () => { + notification['success']({ + message: 'Successfully deactivated community!' + }) + queryClient.invalidateQueries(['community']) + toggleDeleteModal() + closeDrawerHandler() + }, + onSettled: () => { + queryClient.invalidateQueries(['community']) + }, + onError: (err) => { console.log(err) notification['error']({ - message: 'Encountered an error while deleting record custom custom dates', - }); + message: 'Encountered an error while deleting record custom custom dates', + }); // leave modal open - } - }) -} + } + }) + } -const deleteDataHandler = async(record:Community)=>{ - const {data} = await axios({ - method:'patch', - url:`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, - data: { - id:record.id, + const deleteDataHandler = async (record: Community) => { + const { data } = await axios({ + method: 'patch', + url: `${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, + data: { + id: record.id, status: "0" }, - headers:{ - "Authorization": paseto - }}) - return data -} + headers: { + "Authorization": paseto + } + }) + return data + } -const deleteData = useMutation(deleteDataHandler) - -const{isLoading:isDeletingItem} = deleteData - - async function publishCommunityHandler(record:Community){ - const res = await axios({ - method:'patch', - url:`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, - data:{ - status: '1', - id: record.id - }, - headers:{ - "Authorization": paseto - } - }) - return res; - } + const deleteData = useMutation(deleteDataHandler) + const { isLoading: isDeletingItem } = deleteData - const publishCommunity = useMutation(publishCommunityHandler,{ - onSettled:()=>{ - queryClient.invalidateQueries({queryKey:['community']}) + async function publishCommunityHandler(record: Community) { + const res = await axios({ + method: 'patch', + url: `${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, + data: { + status: '1', + id: record.id + }, + headers: { + "Authorization": paseto } }) + return res; + } function copyLink(selectedRecord:any){ navigator.clipboard.writeText('') const eventId = selectedRecord.id - const marketplaceLink = `https://marketplace.staging.flexabledats.com/communities/${eventId}` + const marketplaceLink = `https://marketplace.dev.flexabledats.com/communities/${eventId}` // Copy the text inside the text field navigator.clipboard.writeText(marketplaceLink); } -return( - - - - - { !isBankConnected && selectedRecord?.status == 4 - ? - : + const publishCommunity = useMutation(publishCommunityHandler, { + onSettled: () => { + queryClient.invalidateQueries({ queryKey: ['community'] }) } - } - closable={true} - onClose={closeDrawerHandler} - open={isDrawerOpen} -> - {/* {!isBankConnected && selectedRecord?.status == 4 - ? router.push('/organizations/billings')} size="small"> - Add account - + }) + + return ( + + + + + {!isBankConnected && selectedRecord?.status == 4 + ? + : } + } + closable={true} + onClose={closeDrawerHandler} + open={isDrawerOpen} + > + + + + + + + + + {isManager || isSuperAdmin ? : null} + +
+ Danger zone + +
+ + + - : null - } */} - - - - - - - - - {isManager || isSuperAdmin ?:null} - -
- Danger zone - -
- - - - -
-) + +
+ ) } -interface EditableProp{ +interface EditableProp { selectedRecord: Community } -export function EditableDescription({selectedRecord}:EditableProp){ - +export function EditableDescription({ selectedRecord }: EditableProp) { + const [state, setState] = useState(selectedRecord) const [isEditMode, setIsEditMode] = useState(false) - const {paseto} = useAuthContext() + const { paseto } = useAuthContext() const queryClient = useQueryClient() - function toggleEdit(){ + function toggleEdit() { setIsEditMode(!isEditMode) } - - const [form] = Form.useForm() + + const [form] = Form.useForm() const urlPrefix = useUrlPrefix() - const recordMutationHandler = async(updatedItem:any)=>{ - const {data} = await axios.patch(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`,updatedItem,{ - headers:{ - //@ts-ignore - "Authorization": paseto + const recordMutationHandler = async (updatedItem: any) => { + const { data } = await axios.patch(`${utils.NEXT_PUBLIC_NEW_API_URL}/${urlPrefix}/community`, updatedItem, { + headers: { + //@ts-ignore + "Authorization": paseto } }) - return data; + return data; } const recordMutation = useMutation({ - mutationKey:['description'], + mutationKey: ['description'], mutationFn: recordMutationHandler, - onSuccess:(data:any)=>{ + onSuccess: (data: any) => { console.log(data) toggleEdit() }, - onSettled:()=>{ + onSettled: () => { queryClient.invalidateQueries(['community']) } }) - function onFinish(updatedItem:any){ + function onFinish(updatedItem: any) { const payload = { // key:'description', description: updatedItem.description, @@ -535,97 +631,97 @@ export function EditableDescription({selectedRecord}:EditableProp){ recordMutation.mutate(payload) } - const {isLoading:isEditing} = recordMutation + const { isLoading: isEditing } = recordMutation const readOnly = ( -
+
{state.description}
-) + ) const editable = (
+ style={{ marginTop: '.5rem' }} + name="editableDescription" + initialValues={selectedRecord} + onFinish={onFinish} + form={form} + > -
- + -