This commit is contained in:
VincentAlamelle 2024-06-13 16:35:25 +02:00 committed by GitHub
commit 9e186d3e72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 981 additions and 288 deletions

View File

@ -33,6 +33,9 @@ jobs:
username: nologin
password: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
registry: ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}
- name: Get Git Commit SHA
id: vars
run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Build the Docker Image
run: docker build . -t ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}/${{ env.IMAGE_NAME }}
- name: Push the Docker Image to Scaleway Container Registry

View File

@ -34,6 +34,9 @@ jobs:
username: nologin
password: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
registry: ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}
- name: Get Git Commit SHA
id: vars
run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Build the Docker Image
run: docker build . -t ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}/${{ env.IMAGE_NAME }}
- name: Push the Docker Image to Scaleway Container Registry

View File

@ -1,75 +1,74 @@
name: Staging - Build & Deploy to Scaleway
on:
push:
branches: [staging]
push:
branches: [staging]
env:
PROJECT_ID_LECOFFRE: 72d08499-37c2-412b-877e-f8af0471654a
NAMESPACE_ID_LECOFFRE: f8137e85-47ad-46a5-9e2e-18af5de829c5
CONTAINER_REGISTRY_ENDPOINT_LECOFFRE: rg.fr-par.scw.cloud/funcscwlecoffrestgbqbfhtv6
PROJECT_ID_LECOFFRE: 72d08499-37c2-412b-877e-f8af0471654a
NAMESPACE_ID_LECOFFRE: f8137e85-47ad-46a5-9e2e-18af5de829c5
CONTAINER_REGISTRY_ENDPOINT_LECOFFRE: rg.fr-par.scw.cloud/funcscwlecoffrestgbqbfhtv6
IMAGE_NAME: front
CONTAINER_NAME: front
IMAGE_NAME: front
CONTAINER_NAME: front
jobs:
build-and-push-image-lecoffre:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Copy SSH
run: cp ~/.ssh/id_rsa id_rsa
- name: Login to Scaleway Container Registry
uses: docker/login-action@v3
with:
username: nologin
password: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
registry: ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}
- name: Build the Docker Image
run: docker build . -t ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}/${{ env.IMAGE_NAME }}
- name: Push the Docker Image to Scaleway Container Registry
run: docker push ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}/${{ env.IMAGE_NAME }}
deploy-to-scaleway-lecoffre:
needs: build-and-push-image-lecoffre
runs-on: ubuntu-latest
environment: staging
steps:
- name: Install CLI
uses: scaleway/action-scw@v0
- name: Get container ID
run: |
echo "CONTAINER_ID=$(scw container container list namespace-id=${{env.NAMESPACE_ID_LECOFFRE}} -o json | jq -r '.[] | select(.name == "${{ env.CONTAINER_NAME }}") | .id')" >> $GITHUB_ENV
env:
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID_LECOFFRE }}
- name: Deploy the container based on the new image
run: |
env_string=""
while IFS= read -r line; do
if [[ "$line" == *"="* ]]; then
key=$(echo "$line" | cut -d '=' -f 1)
value=$(echo "$line" | cut -d '=' -f 2-)
if [[ -n "$key" ]]; then
env_string+="environment-variables.$key=$value "
fi
fi
done <<< "$ENV_VARS"
env_string=$(echo $env_string | sed 's/ $//')
scw container container update ${{ env.CONTAINER_ID }} $env_string
env:
ENV_VARS: ${{ secrets.ENV }}
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID_LECOFFRE }}
build-and-push-image-lecoffre:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Copy SSH
run: cp ~/.ssh/id_rsa id_rsa
- name: Login to Scaleway Container Registry
uses: docker/login-action@v3
with:
username: nologin
password: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
registry: ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}
- name: Build the Docker Image
run: docker build . -t ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}/${{ env.IMAGE_NAME }}
- name: Push the Docker Image to Scaleway Container Registry
run: docker push ${{ env.CONTAINER_REGISTRY_ENDPOINT_LECOFFRE }}/${{ env.IMAGE_NAME }}
deploy-to-scaleway-lecoffre:
needs: build-and-push-image-lecoffre
runs-on: ubuntu-latest
environment: staging
steps:
- name: Install CLI
uses: scaleway/action-scw@v0
- name: Get container ID
run: |
echo "CONTAINER_ID=$(scw container container list namespace-id=${{env.NAMESPACE_ID_LECOFFRE}} -o json | jq -r '.[] | select(.name == "${{ env.CONTAINER_NAME }}") | .id')" >> $GITHUB_ENV
env:
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID_LECOFFRE }}
- name: Deploy the container based on the new image
run: |
env_string=""
while IFS= read -r line; do
if [[ "$line" == *"="* ]]; then
key=$(echo "$line" | cut -d '=' -f 1)
value=$(echo "$line" | cut -d '=' -f 2-)
if [[ -n "$key" ]]; then
env_string+="environment-variables.$key=$value "
fi
fi
done <<< "$ENV_VARS"
env_string=$(echo $env_string | sed 's/ $//')
scw container container update ${{ env.CONTAINER_ID }} $env_string
env:
ENV_VARS: ${{ secrets.ENV }}
SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY_LECOFFRE }}
SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY_LECOFFRE }}
SCW_DEFAULT_PROJECT_ID: ${{ env.PROJECT_ID_LECOFFRE }}
SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_ORGANIZATION_ID_LECOFFRE }}

381
package-lock.json generated
View File

@ -24,7 +24,7 @@
"eslint-config-next": "13.2.4",
"form-data": "^4.0.0",
"jwt-decode": "^3.1.2",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.136",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.151",
"next": "^14.2.3",
"prettier": "^2.8.7",
"react": "18.2.0",
@ -42,20 +42,12 @@
"@types/react-gtm-module": "^2.0.3"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@babel/code-frame": {
"version": "7.24.2",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
"integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz",
"integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==",
"dependencies": {
"@babel/highlight": "^7.24.2",
"@babel/highlight": "^7.24.6",
"picocolors": "^1.0.0"
},
"engines": {
@ -63,38 +55,38 @@
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.24.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz",
"integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz",
"integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==",
"dependencies": {
"@babel/types": "^7.24.0"
"@babel/types": "^7.24.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.24.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
"integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz",
"integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz",
"integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
"version": "7.24.2",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
"integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz",
"integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==",
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.20",
"@babel/helper-validator-identifier": "^7.24.6",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
@ -168,9 +160,9 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@ -179,12 +171,12 @@
}
},
"node_modules/@babel/types": {
"version": "7.24.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
"integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz",
"integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==",
"dependencies": {
"@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20",
"@babel/helper-string-parser": "^7.24.6",
"@babel/helper-validator-identifier": "^7.24.6",
"to-fast-properties": "^2.0.0"
},
"engines": {
@ -339,9 +331,9 @@
}
},
"node_modules/@eslint-community/regexpp": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
"integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz",
"integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
@ -377,28 +369,28 @@
}
},
"node_modules/@floating-ui/core": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz",
"integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==",
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz",
"integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==",
"dependencies": {
"@floating-ui/utils": "^0.2.1"
"@floating-ui/utils": "^0.2.0"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz",
"integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==",
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz",
"integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==",
"dependencies": {
"@floating-ui/core": "^1.0.0",
"@floating-ui/utils": "^0.2.0"
}
},
"node_modules/@floating-ui/react-dom": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz",
"integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz",
"integrity": "sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==",
"dependencies": {
"@floating-ui/dom": "^1.6.1"
"@floating-ui/dom": "^1.0.0"
},
"peerDependencies": {
"react": ">=16.8.0",
@ -406,9 +398,9 @@
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
},
"node_modules/@heroicons/react": {
"version": "2.1.3",
@ -480,22 +472,22 @@
}
},
"node_modules/@mui/core-downloads-tracker": {
"version": "5.15.15",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.15.tgz",
"integrity": "sha512-aXnw29OWQ6I5A47iuWEI6qSSUfH6G/aCsW9KmW3LiFqr7uXZBK4Ks+z8G+qeIub8k0T5CMqlT2q0L+ZJTMrqpg==",
"version": "5.15.19",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.19.tgz",
"integrity": "sha512-tCHSi/Tomez9ERynFhZRvFO6n9ATyrPs+2N80DMDzp6xDVirbBjEwhPcE+x7Lj+nwYw0SqFkOxyvMP0irnm55w==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
}
},
"node_modules/@mui/material": {
"version": "5.15.15",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.15.tgz",
"integrity": "sha512-3zvWayJ+E1kzoIsvwyEvkTUKVKt1AjchFFns+JtluHCuvxgKcLSRJTADw37k0doaRtVAsyh8bz9Afqzv+KYrIA==",
"version": "5.15.19",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.19.tgz",
"integrity": "sha512-lp5xQBbcRuxNtjpWU0BWZgIrv2XLUz4RJ0RqFXBdESIsKoGCQZ6P3wwU5ZPuj5TjssNiKv9AlM+vHopRxZhvVQ==",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/base": "5.0.0-beta.40",
"@mui/core-downloads-tracker": "^5.15.15",
"@mui/core-downloads-tracker": "^5.15.19",
"@mui/system": "^5.15.15",
"@mui/types": "^7.2.14",
"@mui/utils": "^5.15.14",
@ -870,9 +862,9 @@
}
},
"node_modules/@rushstack/eslint-patch": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz",
"integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw=="
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz",
"integrity": "sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg=="
},
"node_modules/@swc/counter": {
"version": "0.1.3",
@ -951,9 +943,9 @@
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="
},
"node_modules/@types/validator": {
"version": "13.11.9",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.9.tgz",
"integrity": "sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw=="
"version": "13.11.10",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.10.tgz",
"integrity": "sha512-e2PNXoXLr6Z+dbfx5zSh9TRlXJrELycxiaXznp4S5+D2M3b9bqJEitNHA5923jhnB2zzFiZHa2f0SI1HoIahpg=="
},
"node_modules/@typescript-eslint/parser": {
"version": "5.62.0",
@ -1258,15 +1250,18 @@
}
},
"node_modules/array.prototype.tosorted": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz",
"integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
"integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
"dependencies": {
"call-bind": "^1.0.5",
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
"es-abstract": "^1.22.3",
"es-errors": "^1.1.0",
"es-abstract": "^1.23.3",
"es-errors": "^1.3.0",
"es-shim-unscopables": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/arraybuffer.prototype.slice": {
@ -1355,20 +1350,20 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/bare-events": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz",
"integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.3.1.tgz",
"integrity": "sha512-sJnSOTVESURZ61XgEleqmP255T6zTYwHPwE4r6SssIh0U9/uDvfpdoJYpVUerJJZH2fueO+CdT8ZT+OC/7aZDA==",
"optional": true
},
"node_modules/bare-fs": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.0.tgz",
"integrity": "sha512-TNFqa1B4N99pds2a5NYHR15o0ZpdNKbAeKTE/+G6ED/UeOavv8RY3dr/Fu99HW3zU3pXpo2kDNO8Sjsm2esfOw==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz",
"integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==",
"optional": true,
"dependencies": {
"bare-events": "^2.0.0",
"bare-path": "^2.0.0",
"bare-stream": "^1.0.0"
"bare-stream": "^2.0.0"
}
},
"node_modules/bare-os": {
@ -1378,21 +1373,21 @@
"optional": true
},
"node_modules/bare-path": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.2.tgz",
"integrity": "sha512-o7KSt4prEphWUHa3QUwCxUI00R86VdjiuxmJK0iNVDHYPGo+HsDaVCnqCmPbf/MiW1ok8F4p3m8RTHlWk8K2ig==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz",
"integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==",
"optional": true,
"dependencies": {
"bare-os": "^2.1.0"
}
},
"node_modules/bare-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-1.0.0.tgz",
"integrity": "sha512-KhNUoDL40iP4gFaLSsoGE479t0jHijfYdIcxRn/XtezA2BaUD0NRf/JGRpsMq6dMNM+SrCrB0YSSo/5wBY4rOQ==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.0.1.tgz",
"integrity": "sha512-ubLyoDqPnUf5o0kSFp709HC0WRZuxVuh4pbte5eY95Xvx5bdvz07c2JFmXBfqqe60q+9PJ8S4X5GRvmcNSKMxg==",
"optional": true,
"dependencies": {
"streamx": "^2.16.1"
"streamx": "^2.18.0"
}
},
"node_modules/base64-js": {
@ -1445,11 +1440,11 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@ -1516,9 +1511,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001612",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
"version": "1.0.30001628",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001628.tgz",
"integrity": "sha512-S3BnR4Kh26TBxbi5t5kpbcUlLJb9lhtDXISDPwOfI+JoC+ik0QksvkZtUVyikw3hjnkgkMPSJ8oIM9yMm9vflA==",
"funding": [
{
"type": "opencollective",
@ -1780,9 +1775,9 @@
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dependencies": {
"ms": "2.1.2"
},
@ -1934,9 +1929,9 @@
}
},
"node_modules/enhanced-resolve": {
"version": "5.16.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
"integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==",
"version": "5.17.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz",
"integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@ -2348,28 +2343,28 @@
}
},
"node_modules/eslint-plugin-react": {
"version": "7.34.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz",
"integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==",
"version": "7.34.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.2.tgz",
"integrity": "sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==",
"dependencies": {
"array-includes": "^3.1.7",
"array.prototype.findlast": "^1.2.4",
"array-includes": "^3.1.8",
"array.prototype.findlast": "^1.2.5",
"array.prototype.flatmap": "^1.3.2",
"array.prototype.toreversed": "^1.1.2",
"array.prototype.tosorted": "^1.1.3",
"doctrine": "^2.1.0",
"es-iterator-helpers": "^1.0.17",
"es-iterator-helpers": "^1.0.19",
"estraverse": "^5.3.0",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.1.2",
"object.entries": "^1.1.7",
"object.fromentries": "^2.0.7",
"object.hasown": "^1.1.3",
"object.values": "^1.1.7",
"object.entries": "^1.1.8",
"object.fromentries": "^2.0.8",
"object.hasown": "^1.1.4",
"object.values": "^1.2.0",
"prop-types": "^15.8.1",
"resolve": "^2.0.0-next.5",
"semver": "^6.3.1",
"string.prototype.matchall": "^4.0.10"
"string.prototype.matchall": "^4.0.11"
},
"engines": {
"node": ">=4"
@ -2379,9 +2374,9 @@
}
},
"node_modules/eslint-plugin-react-hooks": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.1.tgz",
"integrity": "sha512-Ck77j8hF7l9N4S/rzSLOWEKpn994YH6iwUK8fr9mXIaQvGpQYmOnQLbiue1u5kI5T1y+gdgqosnEAO9NCz0DBg==",
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz",
"integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==",
"engines": {
"node": ">=10"
},
@ -2578,9 +2573,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -2738,9 +2733,9 @@
}
},
"node_modules/get-tsconfig": {
"version": "4.7.3",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz",
"integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==",
"version": "4.7.5",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz",
"integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==",
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
},
@ -2757,6 +2752,7 @@
"version": "7.1.7",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
"integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@ -2809,11 +2805,12 @@
}
},
"node_modules/globalthis": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
"integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
"dependencies": {
"define-properties": "^1.1.3"
"define-properties": "^1.2.1",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
@ -2977,9 +2974,9 @@
}
},
"node_modules/immutable": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz",
"integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw=="
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz",
"integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ=="
},
"node_modules/import-fresh": {
"version": "3.3.0",
@ -3008,6 +3005,7 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@ -3478,9 +3476,9 @@
}
},
"node_modules/language-subtag-registry": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
"integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w=="
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
"integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="
},
"node_modules/language-tags": {
"version": "1.0.9",
@ -3494,7 +3492,7 @@
}
},
"node_modules/le-coffre-resources": {
"resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#14df7a44f4e8f339725ce6b0eb931372a95e1650",
"resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#67348c776c8319ed8707ade406a2ce454e7adc2e",
"license": "MIT",
"dependencies": {
"class-transformer": "^0.5.1",
@ -3515,9 +3513,9 @@
}
},
"node_modules/libphonenumber-js": {
"version": "1.10.61",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.61.tgz",
"integrity": "sha512-TsQsyzDttDvvzWNkbp/i0fVbzTGJIG0mUu/uNalIaRQEYeJxVQ/FPg+EJgSqfSXezREjM0V3RZ8cLVsKYhhw0Q=="
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.2.tgz",
"integrity": "sha512-V9mGLlaXN1WETzqQvSu6qf6XVAr3nFuJvWsHcuzCCCo6xUKawwSxOPTpan5CGOSKTn5w/bQuCZcLPJkyysgC3w=="
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
@ -3554,17 +3552,6 @@
"loose-envify": "cli.js"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
@ -3579,11 +3566,11 @@
}
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
"dependencies": {
"braces": "^3.0.2",
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@ -3726,9 +3713,9 @@
}
},
"node_modules/node-abi": {
"version": "3.62.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.62.0.tgz",
"integrity": "sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==",
"version": "3.63.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.63.0.tgz",
"integrity": "sha512-vAszCsOUrUxjGAmdnM/pq7gUgie0IRteCQMX6d4A534fQCR93EJU5qgzBvU6EkFfK27s0T3HEV3BOyJIr7OMYw==",
"dependencies": {
"semver": "^7.3.5"
},
@ -3874,16 +3861,16 @@
}
},
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dependencies": {
"@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
"type-check": "^0.4.0"
"type-check": "^0.4.0",
"word-wrap": "^1.2.5"
},
"engines": {
"node": ">= 0.8.0"
@ -3983,9 +3970,9 @@
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@ -4218,9 +4205,9 @@
"integrity": "sha512-EwMqL+ROSlKzatMhT/aqRq7XWWfzlnHynSBSTJh5M2O78mBiPohiSl4Ysls3HOQkkD9y6L22BW0c9bxK2JguwQ=="
},
"node_modules/react-is": {
"version": "18.3.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.0.tgz",
"integrity": "sha512-wRiUsea88TjKDc4FBEn+sLvIDesp6brMbGWnJGjew2waAc9evdhja/2LvePc898HJbHw0L+MTWy7NhpnELAvLQ=="
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
"node_modules/react-select": {
"version": "5.8.0",
@ -4393,6 +4380,7 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dependencies": {
"glob": "^7.1.3"
},
@ -4478,9 +4466,9 @@
}
},
"node_modules/sass": {
"version": "1.75.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.75.0.tgz",
"integrity": "sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==",
"version": "1.77.4",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz",
"integrity": "sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==",
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0",
@ -4494,20 +4482,17 @@
}
},
"node_modules/scheduler": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.1.tgz",
"integrity": "sha512-5GKS5JGfiah1O38Vfa9srZE4s3wdHbwjlCrvIookrg2FO9aIwKLOJXuJQFlEfNcVSOXuaL2hzDeY20uVXcUtrw==",
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/semver": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"bin": {
"semver": "bin/semver.js"
},
@ -4692,12 +4677,13 @@
}
},
"node_modules/streamx": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz",
"integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==",
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz",
"integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==",
"dependencies": {
"fast-fifo": "^1.1.0",
"queue-tick": "^1.0.1"
"fast-fifo": "^1.3.2",
"queue-tick": "^1.0.1",
"text-decoder": "^1.1.0"
},
"optionalDependencies": {
"bare-events": "^2.2.0"
@ -4870,9 +4856,9 @@
}
},
"node_modules/tar-fs": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz",
"integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz",
"integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==",
"dependencies": {
"pump": "^3.0.0",
"tar-stream": "^3.1.5"
@ -4892,6 +4878,14 @@
"streamx": "^2.15.0"
}
},
"node_modules/text-decoder": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz",
"integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==",
"dependencies": {
"b4a": "^1.6.4"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -4933,9 +4927,9 @@
}
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
},
"node_modules/tsutils": {
"version": "3.21.0",
@ -5128,9 +5122,9 @@
}
},
"node_modules/validator": {
"version": "13.11.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
"version": "13.12.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
"engines": {
"node": ">= 0.10"
}
@ -5224,16 +5218,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",

View File

@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "PORT=5005 next dev",
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
@ -26,7 +26,7 @@
"eslint-config-next": "13.2.4",
"form-data": "^4.0.0",
"jwt-decode": "^3.1.2",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.136",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.151",
"next": "^14.2.3",
"prettier": "^2.8.7",
"react": "18.2.0",

Binary file not shown.

View File

@ -1,4 +1,5 @@
import { type OfficeFolder } from "le-coffre-resources/dist/Customer";
import { type OfficeFolder as OfficeFolderNotary } from "le-coffre-resources/dist/Notary";
import BaseCustomer from "../BaseCustomer";
@ -45,11 +46,11 @@ export default class Folders extends BaseCustomer {
/**
* @description : Get a folder by uid
*/
public async getByUid(uid: string, q?: any): Promise<OfficeFolder> {
public async getByUid(uid: string, q?: any): Promise<OfficeFolderNotary> {
const url = new URL(this.baseURl.concat(`/${uid}`));
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
try {
return await this.getRequest<OfficeFolder>(url);
return await this.getRequest<OfficeFolderNotary>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);

View File

@ -0,0 +1,69 @@
import BaseCustomer from "../BaseCustomer";
import Note from "le-coffre-resources/dist/Customer/Note";
// TODO Type get query params -> Where + inclue + orderby
export interface IGetFoldersParams {
q?: {
select?: {};
where?: {};
orderBy?: {}[];
include?: {};
};
}
export default class Notes extends BaseCustomer {
private static instance: Notes;
private readonly baseURl = this.namespaceUrl.concat("/notes");
private constructor() {
super();
}
public static getInstance() {
if (!this.instance) {
return new this();
} else {
return this.instance;
}
}
/**
* @description : Get a note by uid
*/
public async getByUid(uid: string, q?: any): Promise<Note> {
const url = new URL(this.baseURl.concat(`/${uid}`));
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
try {
return await this.getRequest<Note>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
/**
* @description : Create a note
*/
public async post(note: Partial<Note>): Promise<Note> {
const url = new URL(this.baseURl);
try {
return await this.postRequest(url, note);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
/**
* @description : Update the note
*/
public async put(uid: string, body: Partial<Note>): Promise<Note> {
const url = new URL(this.baseURl.concat(`/${uid}`));
try {
return await this.putRequest(url, body);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
}

View File

@ -9,18 +9,22 @@ import React from "react";
import Typography, { ITypo } from "../Typography";
import classes from "./classes.module.scss";
import { AnchorStatus } from "@Front/Components/Layouts/Folder/FolderInformation";
import Note from "le-coffre-resources/dist/Customer/Note";
type IProps = {
folder: OfficeFolder;
type: EFolderBoxInformationType;
isArchived?: boolean;
anchorStatus: AnchorStatus;
customerUid?: string;
note?: Note | null;
};
export enum EFolderBoxInformationType {
INFORMATIONS = "informations",
DESCRIPTION = "description",
ARCHIVED_DESCRIPTION = "archivedDescription",
NOTE = "note",
}
export default function FolderBoxInformation(props: IProps) {
@ -32,10 +36,27 @@ export default function FolderBoxInformation(props: IProps) {
.get()
.modules.pages.Folder.pages.EditInformations.props.path.replace("[folderUid]", props.folder.uid ?? "");
const path = type === EFolderBoxInformationType.DESCRIPTION ? editDescriptionPath : editInformationsPath;
let createOrUpdateNotePath = Module.getInstance()
.get()
.modules.pages.Notes.pages.EditNote.props.path.replace("[noteUid]", props.note?.uid ?? "");
if (!props.note) {
createOrUpdateNotePath = Module.getInstance()
.get()
.modules.pages.Notes.pages.CreateNote.props.path.replace("[folderUid]", props.folder.uid ?? "");
createOrUpdateNotePath = createOrUpdateNotePath.replace("[customerUid]", props.customerUid ?? "");
}
let path = editInformationsPath;
if (type === EFolderBoxInformationType.DESCRIPTION) {
path = editDescriptionPath;
} else if (type === EFolderBoxInformationType.NOTE) {
path = createOrUpdateNotePath;
}
return (
<div className={classNames(classes["root"], type !== EFolderBoxInformationType.INFORMATIONS && classes["single-information"])}>
<div className={classes["content"]}>{renderContentByType(props.folder, type)}</div>
<div className={classes["content"]}>{renderContentByType(props.folder, type, props.note)}</div>
{!isArchived && props.anchorStatus === AnchorStatus.NOT_ANCHORED && (
<Link href={path} className={classes["edit-icon-container"]}>
<Image src={PenICon} alt="edit informations" />
@ -44,7 +65,7 @@ export default function FolderBoxInformation(props: IProps) {
</div>
);
function renderContentByType(folder: OfficeFolder, type: EFolderBoxInformationType) {
function renderContentByType(folder: OfficeFolder, type: EFolderBoxInformationType, note?: Note | null) {
switch (type) {
case EFolderBoxInformationType.DESCRIPTION:
return (
@ -53,6 +74,13 @@ export default function FolderBoxInformation(props: IProps) {
<Typography typo={ITypo.P_18}>{folder.description ?? ""}</Typography>
</div>
);
case EFolderBoxInformationType.NOTE:
return (
<div className={classes["text-container"]}>
<Typography typo={ITypo.NAV_INPUT_16}>Note client</Typography>
<Typography typo={ITypo.P_18}>{note?.content ?? ""}</Typography>
</div>
);
case EFolderBoxInformationType.ARCHIVED_DESCRIPTION:
return (
<div className={classes["text-container"]}>

View File

@ -159,8 +159,8 @@ export default class BurgerModal extends React.Component<IProps, IState> {
/>
<div className={classes["separator"]} />
<NavigationLink path={Module.getInstance().get().modules.pages.MyAccount.props.path} text="Mon compte" />
<NavigationLink target="blank" path="/Onboarding_Le_Coffre.pdf" text="Guide de Prise en Main" />
<NavigationLink target="blank" path="https://tally.so/r/mBGaNY" text="Support" />
<NavigationLink target="blank" path="/CGU_LeCoffre_io.pdf" text="CGU" />
<LogOutButton />
</div>

View File

@ -35,7 +35,7 @@
left: 0;
transform: translateX(-25%);
width: 300px;
top: 112px;
top: 84px;
display: flex;
flex-direction: column;
background: white;

View File

@ -20,6 +20,7 @@ export default class ProfileModal extends React.Component<IProps, IState> {
<div className={classes["background"]} onClick={this.props.closeModal} />
<div className={classes["root"]}>
<NavigationLink path={Module.getInstance().get().modules.pages.MyAccount.props.path} text="Mon compte" />
<NavigationLink target="_blank" path="/Onboarding_Le_Coffre.pdf" text="Guide de Prise en Main" />
<NavigationLink target="_blank" path="/CGU_LeCoffre_io.pdf" text="CGU" />
<div className={classes["separator"]} />
<LogOutButton />

View File

@ -36,7 +36,7 @@
}
.icons {
display: grid;
display: flex;
grid-template-columns: 1fr 1fr;
gap: 64px;

View File

@ -1,4 +1,6 @@
import PenIcon from "@Assets/Icons/pen.svg";
import Trash from "@Assets/Icons/trash.svg";
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
import Module from "@Front/Config/Module";
import { Customer } from "le-coffre-resources/dist/Notary";
@ -10,6 +12,7 @@ import Typography, { ITypo } from "../../Typography";
import WarningBadge from "../../WarningBadge";
import classes from "./classes.module.scss";
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
type IProps = {
customer: Customer;
@ -23,6 +26,9 @@ export default class UserFolderHeader extends React.Component<IProps, IState> {
isArchived: false,
};
public override render(): JSX.Element | null {
const redirectCurrent = Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folder.uid ?? "");
const redirectPath = Module.getInstance()
.get()
.modules.pages.Folder.pages.EditClient.props.path.replace("[folderUid]", this.props.folder.uid ?? "")
@ -60,6 +66,14 @@ export default class UserFolderHeader extends React.Component<IProps, IState> {
<Link href={redirectPath}>
<Image src={PenIcon} alt="edit" className={classes["edit-icon"]} onClick={this.onEditClick} />
</Link>
<Link href={redirectCurrent}>
<Image
src={Trash}
alt="delete"
className={classes["edit-icon"]}
onClick={() => this.removeCustomer(this.props.customer.uid!)}
/>
</Link>
</div>
)}
</div>
@ -73,6 +87,26 @@ export default class UserFolderHeader extends React.Component<IProps, IState> {
return notAskedDocuments.length > 0;
}
private async removeCustomer(uid: string) {
try {
//use folder put to remove customer from folder
const query = {
q: {
customers: "true",
},
};
const folder = await Folders.getInstance().getByUid(this.props.folder.uid!, query);
if (!folder.customers) return;
const customers = folder.customers.filter((customer) => customer.uid !== uid);
folder.customers = customers;
await Folders.getInstance().put(this.props.folder.uid!, folder);
//redirect on the same page
window.location.reload();
} catch (e) {
console.error(e);
}
}
private formatPhoneNumber(phoneNumber: string): string {
if (!phoneNumber) return "";
phoneNumber = phoneNumber.replace(/ /g, "");
@ -101,10 +135,11 @@ export default class UserFolderHeader extends React.Component<IProps, IState> {
return phoneNumber;
}
const output = phoneNumber.split("").map((char, index) => {
if (index % 2) return char + " ";
if (index % 2) return char + ".";
return char;
});
return output.join("");
const joinedOutput = output.join("");
return joinedOutput.substring(0, joinedOutput.length - 1);
}
private onEditClick(): void {}

View File

@ -79,5 +79,10 @@
}
}
}
.notes {
margin-top: 15px;
width: 50%;
}
}
}

View File

@ -17,6 +17,7 @@ import classes from "./classes.module.scss";
import DocumentList from "./DocumentList";
import UserFolderHeader from "./UserFolderHeader";
import { AnchorStatus } from "@Front/Components/Layouts/Folder/FolderInformation";
import FolderBoxInformation, { EFolderBoxInformationType } from "../FolderBoxInformation";
type IProps = {
customer: Customer;
@ -28,6 +29,7 @@ type IProps = {
anchorStatus: AnchorStatus;
getFolderCallback: () => Promise<void>;
};
type IState = {
isOpenDeletionModal: boolean;
selectedDocumentToDelete: string;
@ -72,6 +74,9 @@ export default class UserFolder extends React.Component<IProps, IState> {
documentAskedSubtitle = "Aucun document en attente";
}
}
//get the note of the folder that has customer_uid = this.props.customer.uid
const folderNote = this.props.folder.notes?.find((note) => note.customer?.uid === this.props.customer.uid);
return (
<div className={classes["root"]} data-opened={this.props.isOpened.toString()}>
<Confirm
@ -84,7 +89,6 @@ export default class UserFolder extends React.Component<IProps, IState> {
confirmText={"Confirmer"}>
Êtes-vous vous de vouloir supprimer la demande de document ?
</Confirm>
<div className={classes["header"]} onClick={this.changeUserFolder}>
<UserFolderHeader customer={this.props.customer} folder={this.props.folder} isArchived={this.props.isArchived} />
<Image
@ -94,7 +98,6 @@ export default class UserFolder extends React.Component<IProps, IState> {
onClick={this.changeUserFolder}
/>
</div>
{this.props.isOpened && (
<div className={classes["container"]} ref={this.rootRefElement}>
<QuantityProgressBar
@ -142,6 +145,15 @@ export default class UserFolder extends React.Component<IProps, IState> {
</div>
)}
</div>
<div className={classes["content"]}>
<FolderBoxInformation
anchorStatus={AnchorStatus.NOT_ANCHORED}
folder={this.props.folder}
type={EFolderBoxInformationType.NOTE}
note={folderNote}
customerUid={this.props.customer.uid}
/>
</div>
</div>
)}
</div>

View File

@ -38,6 +38,37 @@
.subtitle {
margin: 64px 0 32px 0;
}
.contact {
display: flex;
gap: 20px;
}
.contact-text {
text-align: right;
line-height: 15px;
}
.contact-button {
margin-top: 4%;
}
.separator {
width: 20px;
height: 50px; /* Adjust the height as needed */
background-color: gray;
margin: 0 20px; /* Adjust the margin as needed */
}
.note-box {
border: 1px solid #e0e0e0; /* Light grey border */
margin-top: 25px;
padding: 10px;
width: 100%;
height: 100px; /* Adjust height as needed */
box-sizing: border-box;
position: relative;
}
}
.sub-container {

View File

@ -4,7 +4,7 @@ import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import DepositDocument from "@Front/Components/DesignSystem/DepositDocument";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
import Customer, { Document, DocumentType, OfficeFolder } from "le-coffre-resources/dist/Customer";
import Customer, { Document, DocumentType, Note, OfficeFolder } from "le-coffre-resources/dist/Customer";
import React, { useCallback, useEffect, useState } from "react";
import classes from "./classes.module.scss";
@ -22,7 +22,9 @@ export default function ClientDashboard(props: IProps) {
const [documents, setDocuments] = useState<Document[] | null>(null);
const [customer, setCustomer] = useState<Customer | null>(null);
const [contact, setContact] = useState<Customer["contact"] | null>(null);
const [folder, setFolder] = useState<OfficeFolder | null>(null);
const [note, setNote] = useState<Note | null>(null);
const [isAddDocumentModalVisible, setIsAddDocumentModalVisible] = useState<boolean>(false);
const getDocuments = useCallback(async () => {
@ -31,10 +33,40 @@ export default function ClientDashboard(props: IProps) {
jwt = JwtService.getInstance().decodeCustomerJwt();
}
const folder = await Folders.getInstance().getByUid(folderUid as string, { q: { office: true, customers: true } });
const folder = await Folders.getInstance().getByUid(folderUid as string, {
q: {
office: true,
customers: true,
notes: {
include: {
customer: true,
},
},
stakeholders: {
include: {
contact: true,
office_role: true,
},
},
},
});
//Loop through the folder stakeholders, if there is at least one stakeholder that role is "Collaborateur" set contact to this stakeholders.contact, else, take the first stakeholders of the list
const contact = folder.stakeholders!.find((stakeholder) => stakeholder.office_role?.name === "Collaborateur")?.contact;
setContact(contact ?? folder.stakeholders![0]!.contact);
const actualCustomer = folder?.customers?.find((customer) => customer.contact?.email === jwt?.email);
if (!actualCustomer) throw new Error("Customer not found");
let note = folder.notes?.find((note) => note.customer?.uid === actualCustomer.uid);
// if (!note) throw new Error("Note not found");
if (!note) {
note = {
content: "Aucune note",
created_at: new Date(),
updated_at: new Date(),
};
}
const query: IGetDocumentsparams = {
where: { depositor: { uid: actualCustomer.uid }, folder_uid: folderUid as string },
include: {
@ -61,6 +93,7 @@ export default function ClientDashboard(props: IProps) {
setFolder(folder);
setDocuments(documentList);
setCustomer(actualCustomer);
setNote(note);
}, [folderUid]);
const onCloseModalAddDocument = useCallback(() => {
@ -119,11 +152,29 @@ export default function ClientDashboard(props: IProps) {
sélectionnez le document correspondant. <br /> En déposant un document, celui-ci est automatiquement enregistré et
transmis à votre notaire.
</Typography>
<div className={classes["note-box"]}>
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
{note?.content}
</Typography>
</div>
</div>
<div className={classes["contact"]}>
<Typography typo={ITypo.P_SB_18} className={classes["contact-text"]} color={ITypoColor.GREY}>
<p>
{contact?.first_name} {contact?.last_name}
</p>
<p>{contact?.phone_number ?? contact?.cell_phone_number}</p>
<p>{contact?.email}</p>
</Typography>
<div className="separator"></div>
{folder?.office?.rib_name && (
//Div to avoid the button to be on the same line as the text
<Button className={classes["contact-button"]} onClick={downloadFile}>
Télécharger le RIB de votre notaire
</Button>
)}
</div>
{folder?.office?.rib_name && (
//Div to avoid the button to be on the same line as the text
<Button onClick={downloadFile}>Télécharger le RIB de votre notaire</Button>
)}
</div>
);
}, [

View File

@ -231,6 +231,7 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
try {
// remove every space from the phone number
values["cell_phone_number"] = values["cell_phone_number"].replace(/\s/g, "");
values["cell_phone_number"] = values["cell_phone_number"].replace(/\./g, "");
if (values["cell_phone_number"] && values["cell_phone_number"].length === 10) {
// get the first digit of the phone number
const firstDigit = values["cell_phone_number"].charAt(0);

View File

@ -0,0 +1,56 @@
@import "@Themes/constants.scss";
.root {
display: flex;
flex-direction: column;
min-height: 100%;
align-items: flex-start;
width: fit-content;
.back-arrow {
margin-bottom: 24px;
}
.form {
width: 100%;
.content {
margin-top: 32px;
>:not(:last-child) {
margin-bottom: 24px;
}
}
.button-container {
width: 100%;
display: flex;
text-align: center;
margin-top: 24px;
.cancel-button {
display: flex;
margin-right: 32px;
}
@media (max-width: $screen-m) {
display: flex;
flex-direction: column-reverse;
.cancel-button {
margin-left: 0;
margin-top: 12px;
>* {
flex: 1;
}
}
>* {
width: 100%;
}
}
}
}
}

View File

@ -0,0 +1,114 @@
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Module from "@Front/Config/Module";
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
import Link from "next/link";
import { NextRouter, useRouter } from "next/router";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import Customer from "le-coffre-resources/dist/Customer";
import Note from "le-coffre-resources/dist/Customer/Note";
import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders";
import Notes from "@Front/Api/LeCoffreApi/Customer/Notes/Notes";
import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers";
type IProps = {};
type IPropsClass = IProps & {
folderUid: string;
customerUid: string;
router: NextRouter;
};
type IState = {
folder: OfficeFolder | null;
customer: Customer | null;
note: Note | null;
};
class CreateCustomerNoteClass extends BasePage<IPropsClass, IState> {
private backwardPath = Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folderUid!);
constructor(props: IPropsClass) {
super(props);
this.state = {
folder: null,
customer: null,
note: null,
};
this.onFormSubmit = this.onFormSubmit.bind(this);
}
public override render(): JSX.Element {
return (
<DefaultNotaryDashboard title={"Modifier la note client"}>
<div className={classes["root"]}>
<div className={classes["back-arrow"]}>
<BackArrow url={this.backwardPath} />
</div>
<Typography typo={ITypo.H1Bis}>Modifier la note du client</Typography>
<Form className={classes["form"]} onSubmit={this.onFormSubmit}>
<div className={classes["content"]}>
<TextAreaField
name="content"
placeholder="Note à l'attention du client"
defaultValue={this.state.note?.content ?? ""}
/>
</div>
<div className={classes["button-container"]}>
<Link href={this.backwardPath} className={classes["cancel-button"]}>
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
</Link>
<Button type="submit">Enregistrer</Button>
</div>
</Form>
</div>
</DefaultNotaryDashboard>
);
}
public override async componentDidMount() {
// const note = await Notes.getInstance().getByUid(this.props.noteUid, query);
const folder = await Folders.getInstance().getByUid(this.props.folderUid, { note: true });
const customer = await Customers.getInstance().getByUid(this.props.customerUid);
//get the note of the folder that has customer_uid = this.props.customer.uid
// const folderNote = folder.notes?.find((note) => note.customer?.uid === this.props.customerUid);
// this.setState({ note, folder: note.office_folder || null, customer: note.customer || null });
this.setState({ note: null, folder: folder, customer: customer });
}
private async onFormSubmit(e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) {
try {
if (!this.state.folder || !this.state.customer) {
throw new Error("Folder or customer not found");
}
const note = {
content: values["content"],
folder: this.state.folder,
customer: this.state.customer,
};
await Notes.getInstance().post(note);
this.props.router.push(this.backwardPath);
} catch (error) {
console.error(error);
}
}
}
export default function UpdateCustomerNote(props: IProps) {
const router = useRouter();
let { folderUid, customerUid } = router.query;
folderUid = folderUid as string;
customerUid = customerUid as string;
return <CreateCustomerNoteClass folderUid={folderUid} customerUid={customerUid} router={router} />;
}

View File

@ -176,7 +176,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
)}
</>
)}
{!this.doesFolderHaveCustomer() && (
{this.canDeleteFolder() && (
<span className={classes["delete-folder"]} onClick={this.openVerifDeleteFolder}>
<Button variant={EButtonVariant.SECONDARY}>Supprimer le dossier</Button>
</span>
@ -405,6 +405,10 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
return this.props.selectedFolder?.customers!.length > 0;
}
private canDeleteFolder(): boolean {
return (this.props.selectedFolder?.customers?.length ?? 0) === 0 && (this.props.selectedFolder?.documents?.length ?? 0) === 0;
}
private openArchivedModal(): void {
if (this.everyDocumentValidated() && this.props.isAnchored === AnchorStatus.VERIFIED_ON_CHAIN) {
this.setState({ isArchivedModalOpen: true });
@ -485,6 +489,11 @@ export default function FolderInformation(props: IProps) {
},
},
folder_anchor: true,
notes: {
include: {
customer: true,
},
},
},
};

View File

@ -179,6 +179,7 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
if (!values["cell_phone_number"]) return;
// remove every space from the phone number
values["cell_phone_number"] = values["cell_phone_number"].replace(/\s/g, "");
values["cell_phone_number"] = values["cell_phone_number"].replace(/\./g, "");
if (values["cell_phone_number"] && values["cell_phone_number"].length === 10) {
// get the first digit of the phone number
const firstDigit = values["cell_phone_number"].charAt(0);

View File

@ -0,0 +1,56 @@
@import "@Themes/constants.scss";
.root {
display: flex;
flex-direction: column;
min-height: 100%;
align-items: flex-start;
width: fit-content;
.back-arrow {
margin-bottom: 24px;
}
.form {
width: 100%;
.content {
margin-top: 32px;
>:not(:last-child) {
margin-bottom: 24px;
}
}
.button-container {
width: 100%;
display: flex;
text-align: center;
margin-top: 24px;
.cancel-button {
display: flex;
margin-right: 32px;
}
@media (max-width: $screen-m) {
display: flex;
flex-direction: column-reverse;
.cancel-button {
margin-left: 0;
margin-top: 12px;
>* {
flex: 1;
}
}
>* {
width: 100%;
}
}
}
}
}

View File

@ -0,0 +1,109 @@
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Module from "@Front/Config/Module";
import Link from "next/link";
import { NextRouter, useRouter } from "next/router";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import Note from "le-coffre-resources/dist/Customer/Note";
import Notes from "@Front/Api/LeCoffreApi/Customer/Notes/Notes";
type IProps = {};
type IPropsClass = IProps & {
noteUid: string;
router: NextRouter;
};
type IState = {
note: Note | null;
backwardPath: string;
};
class UpdateCustomerNoteClass extends BasePage<IPropsClass, IState> {
constructor(props: IPropsClass) {
super(props);
this.state = {
note: null,
backwardPath: "",
};
this.onFormSubmit = this.onFormSubmit.bind(this);
}
public override render(): JSX.Element {
return (
<DefaultNotaryDashboard title={"Modifier la note client"}>
<div className={classes["root"]}>
<div className={classes["back-arrow"]}>
<BackArrow url={this.state.backwardPath} />
</div>
<Typography typo={ITypo.H1Bis}>Modifier la note du client</Typography>
<Form className={classes["form"]} onSubmit={this.onFormSubmit}>
<div className={classes["content"]}>
<TextAreaField
name="content"
placeholder="Note à l'attention du client"
defaultValue={this.state.note?.content ?? ""}
/>
</div>
<div className={classes["button-container"]}>
<Link href={this.state.backwardPath} className={classes["cancel-button"]}>
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
</Link>
<Button type="submit">Enregistrer</Button>
</div>
</Form>
</div>
</DefaultNotaryDashboard>
);
}
public override async componentDidMount() {
const query = {
q: {
customer: "true",
folder: "true",
},
};
const note = await Notes.getInstance().getByUid(this.props.noteUid, query);
// const folder = await Folders.getInstance().getByUid(this.props.folderUid, { note: true });
//get the note of the folder that has customer_uid = this.props.customer.uid
// const folderNote = folder.notes?.find((note) => note.customer?.uid === this.props.customerUid);
this.setState({
note,
backwardPath: Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", note.folder?.uid!),
});
}
private async onFormSubmit(e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) {
try {
const note = {
content: values["content"],
};
await Notes.getInstance().put(this.props.noteUid, note);
this.props.router.push(this.state.backwardPath);
// await Folders.getInstance().put(this.props.folderUid, values);
// this.props.router.push(this.backwardPath);
} catch (error) {
console.error(error);
}
}
}
export default function UpdateCustomerNote(props: IProps) {
const router = useRouter();
let { noteUid } = router.query;
noteUid = noteUid as string;
return <UpdateCustomerNoteClass noteUid={noteUid} router={router} />;
}

View File

@ -16,16 +16,16 @@
justify-content: space-between;
align-items: center;
.arrow-container{
.arrow-container {
cursor: pointer;
&[data-disabled="true"]{
&[data-disabled="true"] {
opacity: 0.3;
cursor: not-allowed;
}
}
.file-container{
.file-container {
max-width: 1000px;
margin: auto;
min-height: 700px;
@ -33,12 +33,17 @@
}
}
.footer{
width: fit-content;
.footer {
margin: auto;
.ocr-container{
.ocr-container {
margin-top: 42px;
}
.alert {
margin-top: 24px;
width: 100%;
}
.buttons-container {
display: flex;
gap: 24px;

View File

@ -17,6 +17,7 @@ import BasePage from "../../Base";
import classes from "./classes.module.scss";
import Files from "@Front/Api/LeCoffreApi/Notary/Files/Files";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
import MessageBox from "@Front/Components/Elements/MessageBox";
type IProps = {};
type IPropsClass = {
@ -104,6 +105,9 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
)}
</div>
<div className={classes["footer"]}>
<div className={classes["alert"]}>
<MessageBox type={"info"}>Veuillez valider le document afin de pouvoir le télécharger.</MessageBox>
</div>
{/* {this.state.document?.document_type?.name === "Document d'identité" && (
<div className={classes["ocr-container"]}>
<OcrResult percentage={this.state.validatedPercentage} />

View File

@ -215,6 +215,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
deed: { include: { deed_type: "true" } },
office: "true",
customers: { include: { contact: true } },
notes: "true",
},
};
const folder = await Folders.getInstance().getByUid(this.props.selectedFolderUid, query);

View File

@ -118,7 +118,7 @@ export default function Login() {
return;
}
const passwordRegex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d@$!%*?&]{8,}$/);
const passwordRegex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d@$!%*?&_\\-]{8,}$/);
if (!passwordRegex.test(values["password"])) {
setValidationErrors([
{

View File

@ -360,6 +360,29 @@
}
}
}
},
"Notes": {
"enabled": true,
"props": {
"path": "/notes",
"labelKey": "notes"
},
"pages": {
"EditNote": {
"enabled": true,
"props": {
"path": "/notes/[noteUid]/edit",
"labelKey": "edit_note"
}
},
"CreateNote": {
"enabled": true,
"props": {
"path": "/notes/folder/[folderUid]/customer/[customerUid]/create",
"labelKey": "create_note"
}
}
}
}
}
}

View File

@ -360,6 +360,29 @@
}
}
}
},
"Notes": {
"enabled": true,
"props": {
"path": "/notes",
"labelKey": "notes"
},
"pages": {
"EditNote": {
"enabled": true,
"props": {
"path": "/notes/[noteUid]/edit",
"labelKey": "edit_note"
}
},
"CreateNote": {
"enabled": true,
"props": {
"path": "/notes/folder/[folderUid]/customer/[customerUid]/create",
"labelKey": "create_note"
}
}
}
}
}
}

View File

@ -360,6 +360,29 @@
}
}
}
},
"Notes": {
"enabled": true,
"props": {
"path": "/notes",
"labelKey": "notes"
},
"pages": {
"EditNote": {
"enabled": true,
"props": {
"path": "/notes/[noteUid]/edit",
"labelKey": "edit_note"
}
},
"CreateNote": {
"enabled": true,
"props": {
"path": "/notes/folder/[folderUid]/customer/[customerUid]/create",
"labelKey": "create_note"
}
}
}
}
}
}

View File

@ -360,6 +360,29 @@
}
}
}
},
"Notes": {
"enabled": true,
"props": {
"path": "/notes",
"labelKey": "notes"
},
"pages": {
"EditNote": {
"enabled": true,
"props": {
"path": "/notes/[noteUid]/edit",
"labelKey": "edit_note"
}
},
"CreateNote": {
"enabled": true,
"props": {
"path": "/notes/folder/[folderUid]/customer/[customerUid]/create",
"labelKey": "create_note"
}
}
}
}
}
}

View File

@ -1,3 +1,3 @@
{
"version": "v0.5.0"
"version": "v2.2.0"
}

View File

@ -0,0 +1,5 @@
import UpdateCustomerNote from "@Front/Components/Layouts/Folder/UpdateCustomerNote";
export default function Route() {
return <UpdateCustomerNote />;
}

View File

@ -0,0 +1,5 @@
import CreateCustomerNote from "@Front/Components/Layouts/Folder/CreateCustomerNote";
export default function Route() {
return <CreateCustomerNote />;
}