mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-30 12:55:02 +00:00
Merge branch 'main' of https://github.com/Hestia-Homes/assessment-model into remote-assessment-ui
This commit is contained in:
commit
f034fb2735
12 changed files with 4297 additions and 37 deletions
1
generate_migration.sh
Normal file
1
generate_migration.sh
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
npx drizzle-kit generate
|
||||||
154
package-lock.json
generated
154
package-lock.json
generated
|
|
@ -12,6 +12,7 @@
|
||||||
"@headlessui/react": "^2.2.7",
|
"@headlessui/react": "^2.2.7",
|
||||||
"@heroicons/react": "^2.0.18",
|
"@heroicons/react": "^2.0.18",
|
||||||
"@hookform/resolvers": "^3.9.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
|
"@hubspot/api-client": "^13.4.0",
|
||||||
"@radix-ui/react-accordion": "^1.2.12",
|
"@radix-ui/react-accordion": "^1.2.12",
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
|
|
@ -41,6 +42,7 @@
|
||||||
"drizzle-orm": "^0.44.5",
|
"drizzle-orm": "^0.44.5",
|
||||||
"esbuild": "^0.25.8",
|
"esbuild": "^0.25.8",
|
||||||
"eslint-config-next": "13.4.3",
|
"eslint-config-next": "13.4.3",
|
||||||
|
"framer-motion": "^12.23.24",
|
||||||
"lucide-react": "^0.233.0",
|
"lucide-react": "^0.233.0",
|
||||||
"next": "^15.4.2",
|
"next": "^15.4.2",
|
||||||
"next-auth": "^4.22.1",
|
"next-auth": "^4.22.1",
|
||||||
|
|
@ -49,6 +51,7 @@
|
||||||
"pg": "^8.11.1",
|
"pg": "^8.11.1",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
|
"react-confetti": "^6.4.0",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-hook-form": "^7.53.2",
|
"react-hook-form": "^7.53.2",
|
||||||
"tailwind-merge": "^1.13.2",
|
"tailwind-merge": "^1.13.2",
|
||||||
|
|
@ -2614,6 +2617,24 @@
|
||||||
"react-hook-form": "^7.0.0"
|
"react-hook-form": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@hubspot/api-client": {
|
||||||
|
"version": "13.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hubspot/api-client/-/api-client-13.4.0.tgz",
|
||||||
|
"integrity": "sha512-B2Bu/F/nxzqvF0LlEIgA28G6ObANXkYosJSFLW3bdYXOOgH9kbVLJwPGze0H6L+dQJ+vmzZ1LeRpl5REXyHShA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/node-fetch": "^2.5.7",
|
||||||
|
"bottleneck": "^2.19.5",
|
||||||
|
"es6-promise": "^4.2.4",
|
||||||
|
"form-data": "^4.0.4",
|
||||||
|
"lodash.merge": "^4.6.2",
|
||||||
|
"node-fetch": "^2.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.13.0",
|
"version": "0.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
||||||
|
|
@ -5874,6 +5895,16 @@
|
||||||
"integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==",
|
"integrity": "sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node-fetch": {
|
||||||
|
"version": "2.6.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz",
|
||||||
|
"integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"form-data": "^4.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/nodemailer": {
|
"node_modules/@types/nodemailer": {
|
||||||
"version": "7.0.2",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-7.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-7.0.2.tgz",
|
||||||
|
|
@ -6805,7 +6836,6 @@
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/at-least-node": {
|
"node_modules/at-least-node": {
|
||||||
|
|
@ -7098,6 +7128,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/bottleneck": {
|
||||||
|
"version": "2.19.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||||
|
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/bowser": {
|
"node_modules/bowser": {
|
||||||
"version": "2.12.0",
|
"version": "2.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.0.tgz",
|
||||||
|
|
@ -7588,7 +7624,6 @@
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
|
|
@ -8109,7 +8144,6 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
|
|
@ -8624,6 +8658,12 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es6-promise": {
|
||||||
|
"version": "4.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||||
|
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.25.8",
|
"version": "0.25.8",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
|
||||||
|
|
@ -9543,7 +9583,6 @@
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
|
|
@ -9578,6 +9617,33 @@
|
||||||
"url": "https://github.com/sponsors/rawify"
|
"url": "https://github.com/sponsors/rawify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/framer-motion": {
|
||||||
|
"version": "12.23.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz",
|
||||||
|
"integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"motion-dom": "^12.23.23",
|
||||||
|
"motion-utils": "^12.23.6",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/is-prop-valid": "*",
|
||||||
|
"react": "^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/is-prop-valid": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/from": {
|
"node_modules/from": {
|
||||||
"version": "0.1.7",
|
"version": "0.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
|
||||||
|
|
@ -11181,7 +11247,6 @@
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
|
|
@ -11191,7 +11256,6 @@
|
||||||
"version": "2.1.35",
|
"version": "2.1.35",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mime-db": "1.52.0"
|
"mime-db": "1.52.0"
|
||||||
|
|
@ -11257,6 +11321,21 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/motion-dom": {
|
||||||
|
"version": "12.23.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
|
||||||
|
"integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"motion-utils": "^12.23.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/motion-utils": {
|
||||||
|
"version": "12.23.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
|
||||||
|
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
|
@ -11481,6 +11560,26 @@
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"encoding": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"encoding": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.19",
|
"version": "2.0.19",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||||
|
|
@ -12601,6 +12700,21 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-confetti": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-5MdGUcqxrTU26I2EU7ltkWPwxvucQTuqMm8dUz72z2YMqTD6s9vMcDUysk7n9jnC+lXuCPeJJ7Knf98VEYE9Rg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tween-functions": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-day-picker": {
|
"node_modules/react-day-picker": {
|
||||||
"version": "8.10.1",
|
"version": "8.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz",
|
||||||
|
|
@ -14224,6 +14338,12 @@
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tree-kill": {
|
"node_modules/tree-kill": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||||
|
|
@ -14311,6 +14431,12 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tween-functions": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==",
|
||||||
|
"license": "BSD"
|
||||||
|
},
|
||||||
"node_modules/tweetnacl": {
|
"node_modules/tweetnacl": {
|
||||||
"version": "0.14.5",
|
"version": "0.14.5",
|
||||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||||
|
|
@ -14761,12 +14887,28 @@
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
"node_modules/whatwg-fetch": {
|
"node_modules/whatwg-fetch": {
|
||||||
"version": "3.6.20",
|
"version": "3.6.20",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
|
||||||
"integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
|
"integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"@headlessui/react": "^2.2.7",
|
"@headlessui/react": "^2.2.7",
|
||||||
"@heroicons/react": "^2.0.18",
|
"@heroicons/react": "^2.0.18",
|
||||||
"@hookform/resolvers": "^3.9.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
|
"@hubspot/api-client": "^13.4.0",
|
||||||
"@radix-ui/react-accordion": "^1.2.12",
|
"@radix-ui/react-accordion": "^1.2.12",
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
|
|
@ -47,6 +48,7 @@
|
||||||
"drizzle-orm": "^0.44.5",
|
"drizzle-orm": "^0.44.5",
|
||||||
"esbuild": "^0.25.8",
|
"esbuild": "^0.25.8",
|
||||||
"eslint-config-next": "13.4.3",
|
"eslint-config-next": "13.4.3",
|
||||||
|
"framer-motion": "^12.23.24",
|
||||||
"lucide-react": "^0.233.0",
|
"lucide-react": "^0.233.0",
|
||||||
"next": "^15.4.2",
|
"next": "^15.4.2",
|
||||||
"next-auth": "^4.22.1",
|
"next-auth": "^4.22.1",
|
||||||
|
|
@ -55,6 +57,7 @@
|
||||||
"pg": "^8.11.1",
|
"pg": "^8.11.1",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
|
"react-confetti": "^6.4.0",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-hook-form": "^7.53.2",
|
"react-hook-form": "^7.53.2",
|
||||||
"tailwind-merge": "^1.13.2",
|
"tailwind-merge": "^1.13.2",
|
||||||
|
|
|
||||||
1
push_to_db.sh
Normal file
1
push_to_db.sh
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
npx drizzle-kit push
|
||||||
81
src/app/api/book-survey/route.ts
Normal file
81
src/app/api/book-survey/route.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
// app/api/book-survey/route.ts
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import { db } from "@/app/db/db";
|
||||||
|
import { propertyStatusTracker } from "@/app/db/schema/crm/property_status_tracker";
|
||||||
|
import { eq, and } from "drizzle-orm";
|
||||||
|
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
const { dealName, pipelineId, dealStageId, propertyId, portfolioId } =
|
||||||
|
await req.json();
|
||||||
|
|
||||||
|
// 1️⃣ Create HubSpot deal
|
||||||
|
const hsRes = await fetch("https://api.hubapi.com/crm/v3/objects/deals", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
properties: {
|
||||||
|
dealname: dealName,
|
||||||
|
pipeline: pipelineId,
|
||||||
|
dealstage: dealStageId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hsRes.ok) {
|
||||||
|
const err = await hsRes.text();
|
||||||
|
throw new Error(`HubSpot error: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hsData = await hsRes.json();
|
||||||
|
const hubspotDealId = hsData.id;
|
||||||
|
|
||||||
|
// 2️⃣ Check if record exists for property + portfolio
|
||||||
|
const existing = await db
|
||||||
|
.select()
|
||||||
|
.from(propertyStatusTracker)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(propertyStatusTracker.propertyId, propertyId),
|
||||||
|
eq(propertyStatusTracker.portfolioId, portfolioId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existing.length > 0) {
|
||||||
|
// 3️⃣ Update existing record
|
||||||
|
await db
|
||||||
|
.update(propertyStatusTracker)
|
||||||
|
.set({
|
||||||
|
hubspotDealId,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
})
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(propertyStatusTracker.propertyId, propertyId),
|
||||||
|
eq(propertyStatusTracker.portfolioId, portfolioId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 4️⃣ Create new record
|
||||||
|
await db.insert(propertyStatusTracker).values({
|
||||||
|
hubspotDealId: hubspotDealId,
|
||||||
|
propertyId: propertyId,
|
||||||
|
portfolioId: portfolioId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
message: existing.length > 0 ? "Updated existing tracker" : "Created new tracker",
|
||||||
|
dealId: hubspotDealId,
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error("❌ Error creating or updating HubSpot deal:", error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: error.message || "Internal Server Error" },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/app/db/migrations/0120_flashy_puck.sql
Normal file
1
src/app/db/migrations/0120_flashy_puck.sql
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE "property_status_tracker" DROP COLUMN "hubspot_pipeline_id";
|
||||||
3829
src/app/db/migrations/meta/0120_snapshot.json
Normal file
3829
src/app/db/migrations/meta/0120_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -841,6 +841,13 @@
|
||||||
"when": 1760711090309,
|
"when": 1760711090309,
|
||||||
"tag": "0119_marvelous_blur",
|
"tag": "0119_marvelous_blur",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 120,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1761146299937,
|
||||||
|
"tag": "0120_flashy_puck",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,14 @@ export const propertyStatusTracker = pgTable("property_status_tracker", {
|
||||||
hubspotDealId: text("hubspot_deal_id").notNull(),
|
hubspotDealId: text("hubspot_deal_id").notNull(),
|
||||||
|
|
||||||
// foreign keys
|
// foreign keys
|
||||||
propertyId: bigint("property_id", { mode: "bigint" })
|
propertyId: bigint("property_id", { mode: "number" })
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => property.id, { onDelete: "cascade" }),
|
.references(() => property.id, { onDelete: "cascade" }),
|
||||||
portfolioId: bigint("portfolio_id", { mode: "bigint" })
|
|
||||||
|
portfolioId: bigint("portfolio_id", { mode: "number" })
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => portfolio.id, { onDelete: "cascade" }),
|
.references(() => portfolio.id, { onDelete: "cascade" }),
|
||||||
|
|
||||||
hubspotPipelineId: text("hubspot_pipeline_id").notNull(),
|
|
||||||
|
|
||||||
createdAt: timestamp("created_at", { precision: 6, withTimezone: true })
|
createdAt: timestamp("created_at", { precision: 6, withTimezone: true })
|
||||||
.defaultNow()
|
.defaultNow()
|
||||||
|
|
|
||||||
96
src/app/portfolio/[slug]/components/BookSurveyModal.tsx
Normal file
96
src/app/portfolio/[slug]/components/BookSurveyModal.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogFooter,
|
||||||
|
} from "@/app/shadcn_components/ui/dialog";
|
||||||
|
import { Button } from "@/app/shadcn_components/ui/button";
|
||||||
|
import { Input } from "@/app/shadcn_components/ui/input";
|
||||||
|
import { Label } from "@/app/shadcn_components/ui/label";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
interface BookSurveyModalProps {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
propertyId: bigint;
|
||||||
|
portfolioId: bigint;
|
||||||
|
address: string;
|
||||||
|
onSuccess?: () => void; // ✅ fix: properly declare optional callback
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BookSurveyModal({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
propertyId,
|
||||||
|
portfolioId,
|
||||||
|
address,
|
||||||
|
onSuccess, // ✅ fix: remove “?:” here, we already declared it optional in interface
|
||||||
|
}: BookSurveyModalProps) {
|
||||||
|
// 🧠 Simple mutation to call your HubSpot API
|
||||||
|
const bookSurveyMutation = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
const res = await fetch("/api/book-survey", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
dealName: address,
|
||||||
|
pipelineId: "2400089278",
|
||||||
|
dealStageId: "3288115388",
|
||||||
|
propertyId: propertyId.toString(),
|
||||||
|
portfolioId: portfolioId.toString(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) throw new Error("Failed to create HubSpot deal");
|
||||||
|
return res.json();
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
console.log("✅ Deal created successfully:", data);
|
||||||
|
console.log("HUBSPOT DEAL ID MADE", data.dealId);
|
||||||
|
onOpenChange(false);
|
||||||
|
if (onSuccess) onSuccess(); // 👈 trigger confetti toast
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.error("❌ Deal creation failed:", error);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 🚀 Submit
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
bookSurveyMutation.mutate();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
|
<DialogContent className="sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Confirm Booking a Survey</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className="w-full"
|
||||||
|
disabled={bookSurveyMutation.isPending}
|
||||||
|
>
|
||||||
|
{bookSurveyMutation.isPending ? "Creating..." : "Submit"}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: check if bug is happening and why.
|
||||||
|
// TODO: Ask khalim what we want to do, maybe a list of Hubspot DB record? if someone presses twice, currently just updates
|
||||||
|
// TODO: Make a sexy toast that the deal has been processed
|
||||||
|
// TODO: Show khalim a demo and other clean ups for good user experience
|
||||||
66
src/app/portfolio/[slug]/components/BookingSuccessToast.tsx
Normal file
66
src/app/portfolio/[slug]/components/BookingSuccessToast.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
import Confetti from "react-confetti";
|
||||||
|
import { CheckCircle } from "lucide-react";
|
||||||
|
|
||||||
|
interface BookingSuccessToastProps {
|
||||||
|
show: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
message?: string;
|
||||||
|
subtext?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BookingSuccessToast({
|
||||||
|
show,
|
||||||
|
onClose,
|
||||||
|
message = "Booking Confirmed!",
|
||||||
|
subtext = "You’re all set. 🎉",
|
||||||
|
}: BookingSuccessToastProps) {
|
||||||
|
const [confetti, setConfetti] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (show) {
|
||||||
|
setConfetti(true);
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setConfetti(false);
|
||||||
|
onClose();
|
||||||
|
}, 4000);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}
|
||||||
|
}, [show, onClose]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AnimatePresence>
|
||||||
|
{show && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 50, scale: 0.9 }}
|
||||||
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, y: 50, scale: 0.9 }}
|
||||||
|
transition={{ type: "spring", stiffness: 300, damping: 25 }}
|
||||||
|
className="fixed bottom-8 right-8 z-50 bg-white shadow-2xl rounded-2xl p-4 pr-6 flex items-center gap-3 border border-green-100"
|
||||||
|
>
|
||||||
|
<div className="p-2 bg-green-100 rounded-full">
|
||||||
|
<CheckCircle className="text-green-600 w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-semibold text-green-700 text-lg">{message}</p>
|
||||||
|
<p className="text-sm text-gray-500">{subtext}</p>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
{confetti && (
|
||||||
|
<Confetti
|
||||||
|
numberOfPieces={180}
|
||||||
|
gravity={0.4}
|
||||||
|
recycle={false}
|
||||||
|
colors={["#10B981", "#34D399", "#6EE7B7", "#ECFDF5"]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,10 @@ import {
|
||||||
PropertyToRecommendation,
|
PropertyToRecommendation,
|
||||||
PropertyWithRelations,
|
PropertyWithRelations,
|
||||||
} from "@/app/db/schema/property";
|
} from "@/app/db/schema/property";
|
||||||
|
import BookSurveyModal from "./BookSurveyModal";
|
||||||
|
import BookingSuccessToast from "./BookingSuccessToast";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
|
||||||
interface DataTableColumnHeaderProps<TData, TValue>
|
interface DataTableColumnHeaderProps<TData, TValue>
|
||||||
extends React.HTMLAttributes<HTMLDivElement> {
|
extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
|
|
@ -40,11 +44,13 @@ const EpcLetterBubble = ({ letter }: { letter: string }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export function DataTableFilterHeader<TData, TValue>({
|
export function DataTableFilterHeader<TData, TValue>({
|
||||||
column,
|
column,
|
||||||
title,
|
title,
|
||||||
className,
|
className,
|
||||||
}: DataTableColumnHeaderProps<TData, TValue>) {
|
}: DataTableColumnHeaderProps<TData, TValue>) {
|
||||||
|
|
||||||
if (!column.getCanSort()) {
|
if (!column.getCanSort()) {
|
||||||
return <div className={cn(className)}>{title}</div>;
|
return <div className={cn(className)}>{title}</div>;
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +218,10 @@ export const columns: ColumnDef<PropertyWithRelations>[] = [
|
||||||
{
|
{
|
||||||
id: "actions",
|
id: "actions",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
|
const [openModal, setOpenModal] = useState(false);
|
||||||
|
const [showToast, setShowToast] = useState(false);
|
||||||
const property = row.original;
|
const property = row.original;
|
||||||
|
const address = String(row.getValue("address"));
|
||||||
const propertyId = property.id;
|
const propertyId = property.id;
|
||||||
const portfolioId = property.portfolioId;
|
const portfolioId = property.portfolioId;
|
||||||
|
|
||||||
|
|
@ -226,35 +235,59 @@ export const columns: ColumnDef<PropertyWithRelations>[] = [
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center">
|
<>
|
||||||
<DropdownMenu>
|
<div className="flex justify-center">
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenu>
|
||||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
<DropdownMenuTrigger asChild>
|
||||||
<span className="sr-only">Open menu</span>
|
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
<span className="sr-only">Open menu</span>
|
||||||
</Button>
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
</DropdownMenuTrigger>
|
</Button>
|
||||||
<DropdownMenuContent align="end">
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
<DropdownMenuContent align="end">
|
||||||
<DropdownMenuItem
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
// onClick={() => navigator.clipboard.writeText(payment.id)}
|
<DropdownMenuItem onClick={()=> setOpenModal(true)}>
|
||||||
className="text-gray-700 cursor-pointer"
|
Book a survey
|
||||||
>
|
</DropdownMenuItem>
|
||||||
<a href={`${portfolioId}/building-passport/${propertyId}`}>
|
<DropdownMenuItem
|
||||||
Building Passport
|
// onClick={() => navigator.clipboard.writeText(payment.id)}
|
||||||
</a>
|
className="text-gray-700 cursor-pointer"
|
||||||
</DropdownMenuItem>
|
>
|
||||||
|
<a href={`${portfolioId}/building-passport/${propertyId}`}>
|
||||||
|
Building Passport
|
||||||
|
</a>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
|
||||||
<DropdownMenuItem className="text-gray-700 cursor-pointer">
|
<DropdownMenuItem className="text-gray-700 cursor-pointer">
|
||||||
Settings
|
Settings
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem className="text-red-500 focus:text-red-700 cursor-pointer">
|
<DropdownMenuItem className="text-red-500 focus:text-red-700 cursor-pointer">
|
||||||
Delete Property
|
Delete Property
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
{/* ✅ Render modal outside dropdown context */}
|
||||||
|
{openModal && (
|
||||||
|
<BookSurveyModal
|
||||||
|
open={openModal}
|
||||||
|
onOpenChange={setOpenModal}
|
||||||
|
propertyId={propertyId}
|
||||||
|
portfolioId={portfolioId}
|
||||||
|
address={address}
|
||||||
|
onSuccess={() => setShowToast(true)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 💥 Toast */}
|
||||||
|
<BookingSuccessToast
|
||||||
|
show={showToast}
|
||||||
|
onClose={() => setShowToast(false)}
|
||||||
|
message="Survey Booked Successfully!"
|
||||||
|
subtext="Your Survey Request is with Domna and will be in contact with you shortly. 🎉"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue