diff --git a/.env.development b/.env.development index 7409632..479fff3 100644 --- a/.env.development +++ b/.env.development @@ -2,3 +2,7 @@ VITE_APP_ENV=development VITE_API_URL=http://localhost:3000/api VITE_APP_NAME=Bright Career Solution (Dev) +VITE_SUPABASE_PROJECT_ID="nttzqpcruzzsmtyimuth" +VITE_SUPABASE_PUBLISHABLE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im50dHpxcGNydXp6c210eWltdXRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzIxNDU2NTMsImV4cCI6MjA4NzcyMTY1M30.8otj0Pz0wRzdHLhhR4fn-YRSUDzhtnFQ0ca_3C4NTvY" +VITE_SUPABASE_URL="https://nttzqpcruzzsmtyimuth.supabase.co" +SUPABASE_SERVICE_ROLE_KEY="sb_secret_TZpsw8un8r7ffQ1SPbFWwg_fE1aTpdS" \ No newline at end of file diff --git a/.env.production b/.env.production index cf041ad..432dc4a 100644 --- a/.env.production +++ b/.env.production @@ -2,3 +2,7 @@ VITE_APP_ENV=production VITE_API_URL=https://api.brightcareer.com/api VITE_APP_NAME=Bright Career Solution +VITE_SUPABASE_PROJECT_ID="nttzqpcruzzsmtyimuth" +VITE_SUPABASE_PUBLISHABLE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im50dHpxcGNydXp6c210eWltdXRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzIxNDU2NTMsImV4cCI6MjA4NzcyMTY1M30.8otj0Pz0wRzdHLhhR4fn-YRSUDzhtnFQ0ca_3C4NTvY" +VITE_SUPABASE_URL="https://nttzqpcruzzsmtyimuth.supabase.co" +SUPABASE_SERVICE_ROLE_KEY="sb_secret_TZpsw8un8r7ffQ1SPbFWwg_fE1aTpdS" \ No newline at end of file diff --git a/assets/listing_spirit.svg b/assets/listing_spirit.svg new file mode 100644 index 0000000..d6861bc --- /dev/null +++ b/assets/listing_spirit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/listing_spirit_2.svg b/assets/listing_spirit_2.svg new file mode 100644 index 0000000..8370883 --- /dev/null +++ b/assets/listing_spirit_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/components.json b/components.json index fb6ac7a..e26ef78 100644 --- a/components.json +++ b/components.json @@ -19,8 +19,10 @@ "hooks": "@/src/hooks" }, "registries": { + "@reui": "https://reui.io/r/{style}/{name}.json", "@react-bits": "https://reactbits.dev/r/{name}.json", "@magicui": "https://magicui.design/r/{name}", - "@fab-ui": "https://fab-ui.com/r/{name}.json" + "@fab-ui": "https://fab-ui.com/r/{name}.json", + "@blocks": "https://blocks.so/r/{name}.json" } } diff --git a/index.html b/index.html index 173f427..d64aa3d 100644 --- a/index.html +++ b/index.html @@ -129,8 +129,8 @@ "@tanstack/react-virtual": "https://esm.sh/@tanstack/react-virtual@3.1.3?deps=react@18.3.1,react-dom@18.3.1", "@tanstack/react-table": "https://esm.sh/@tanstack/react-table@8.13.2?deps=react@18.3.1,react-dom@18.3.1", "react-dom/": "https://esm.sh/react-dom@^19.2.4/", - "react/": "https://esm.sh/react@^19.2.4/" - "react-markdown": "https://esm.sh/react-markdown@9" + "react/": "https://esm.sh/react@^19.2.4/", + "react-markdown": "https://esm.sh/react-markdown@9" } } diff --git a/package-lock.json b/package-lock.json index a11a611..00049fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,9 @@ "@radix-ui/react-toggle": "^1.1.10", "@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.8", + "@radix-ui/react-visually-hidden": "^1.2.4", "@react-three/fiber": "^9.5.0", + "@supabase/supabase-js": "^2.98.0", "@tanstack/react-query": "^5.62.7", "@tanstack/react-query-devtools": "^5.62.7", "@tanstack/react-router": "^1.91.3", @@ -84,16 +86,19 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@tanstack/router-plugin": "^1.91.2", + "@types/fs-extra": "^11.0.4", "@types/node": "^22.14.0", "@types/react": "^19.0.6", "@types/react-dom": "^19.0.2", "@vitejs/plugin-react": "^5.0.0", "autoprefixer": "^10.4.24", + "fs-extra": "^11.3.3", "postcss": "^8.5.6", "tailwindcss": "^3.4.19", "tailwindcss-animate": "^1.0.7", "typescript": "~5.8.2", "vite": "^7.3.1", + "vite-plugin-static-copy": "^3.2.0", "zod": "^3.24.2" } }, @@ -2154,6 +2159,29 @@ } } }, + "node_modules/@radix-ui/react-navigation-menu/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popover": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", @@ -2547,6 +2575,29 @@ } } }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-separator": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", @@ -2737,6 +2788,29 @@ } } }, + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-toggle": { "version": "1.1.10", "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", @@ -2843,6 +2917,29 @@ } } }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", @@ -2998,12 +3095,35 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.4.tgz", + "integrity": "sha512-kaeiyGCe844dkb9AVF+rb4yTyb1LiLN/e3es3nLiRyN4dC8AduBYPMnnNlDjX2VDOcvDEiPnRNMJeWCfsX0txg==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", @@ -3443,6 +3563,86 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, + "node_modules/@supabase/auth-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.98.0.tgz", + "integrity": "sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.98.0.tgz", + "integrity": "sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.98.0.tgz", + "integrity": "sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.98.0.tgz", + "integrity": "sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==", + "license": "MIT", + "dependencies": { + "@types/phoenix": "^1.6.6", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.98.0.tgz", + "integrity": "sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.98.0.tgz", + "integrity": "sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==", + "license": "MIT", + "dependencies": { + "@supabase/auth-js": "2.98.0", + "@supabase/functions-js": "2.98.0", + "@supabase/postgrest-js": "2.98.0", + "@supabase/realtime-js": "2.98.0", + "@supabase/storage-js": "2.98.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@tanstack/history": { "version": "1.154.14", "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.154.14.tgz", @@ -3981,6 +4181,17 @@ "@types/estree": "*" } }, + "node_modules/@types/fs-extra": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", + "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -3990,6 +4201,16 @@ "@types/unist": "*" } }, + "node_modules/@types/jsonfile": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", + "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -4014,6 +4235,12 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/phoenix": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", @@ -4054,6 +4281,15 @@ "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", "license": "MIT" }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -5354,6 +5590,21 @@ } } }, + "node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -5558,6 +5809,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/gtoken": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", @@ -5673,6 +5931,15 @@ "node": ">= 14" } }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -5979,6 +6246,19 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jwa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", @@ -7296,6 +7576,19 @@ "integrity": "sha512-kUpC154AFfxi16pmZUK4jk3J+8zxwTWGPo03EoYA8QPbzikHoaC82n6pNTbd+oEaJonaE8aPWBlX7ad9zrqLsA==", "license": "Unlicense" }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-retry": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-7.1.1.tgz", @@ -8880,6 +9173,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unplugin": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", @@ -9137,6 +9440,29 @@ } } }, + "node_modules/vite-plugin-static-copy": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.2.0.tgz", + "integrity": "sha512-g2k9z8B/1Bx7D4wnFjPLx9dyYGrqWMLTpwTtPHhcU+ElNZP2O4+4OsyaficiDClus0dzVhdGvoGFYMJxoXZ12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.6.0", + "p-map": "^7.0.4", + "picocolors": "^1.1.1", + "tinyglobby": "^0.2.15" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/sapphi-red" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, "node_modules/vite/node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", diff --git a/package.json b/package.json index 21a7fae..ee2b315 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,12 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite --port 3000", - "build": "vite build && tsc --noEmit", - "build:staging": "vite build --mode staging && tsc --noEmit", - "build:production": "vite build --mode production && tsc --noEmit", - "preview": "vite preview", - "start": "vite", + "dev": "node ./node_modules/vite/bin/vite.js --port 3000", + "build": "node ./node_modules/vite/bin/vite.js build && tsc --noEmit", + "build:staging": "node ./node_modules/vite/bin/vite.js build --mode staging && tsc --noEmit", + "build:production": "node ./node_modules/vite/bin/vite.js build --mode production && tsc --noEmit", + "preview": "node ./node_modules/vite/bin/vite.js preview", + "start": "node ./node_modules/vite/bin/vite.js", "lint": "biome check .", "lint:fix": "biome check --write .", "format": "biome format --write ." @@ -49,6 +49,7 @@ "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-visually-hidden": "^1.2.4", "@react-three/fiber": "^9.5.0", + "@supabase/supabase-js": "^2.98.0", "@tanstack/react-query": "^5.62.7", "@tanstack/react-query-devtools": "^5.62.7", "@tanstack/react-router": "^1.91.3", @@ -92,16 +93,19 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@tanstack/router-plugin": "^1.91.2", + "@types/fs-extra": "^11.0.4", "@types/node": "^22.14.0", "@types/react": "^19.0.6", "@types/react-dom": "^19.0.2", "@vitejs/plugin-react": "^5.0.0", "autoprefixer": "^10.4.24", + "fs-extra": "^11.3.3", "postcss": "^8.5.6", "tailwindcss": "^3.4.19", "tailwindcss-animate": "^1.0.7", "typescript": "~5.8.2", "vite": "^7.3.1", + "vite-plugin-static-copy": "^3.2.0", "zod": "^3.24.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 849c3d0..771aa77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -231,6 +231,9 @@ importers: '@biomejs/biome': specifier: ^1.9.4 version: 1.9.4 + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 '@types/node': specifier: ^22.14.0 version: 22.19.11 @@ -246,6 +249,9 @@ importers: autoprefixer: specifier: ^10.4.24 version: 10.4.24(postcss@8.5.6) + fs-extra: + specifier: ^11.3.3 + version: 11.3.3 postcss: specifier: ^8.5.6 version: 8.5.6 @@ -261,6 +267,9 @@ importers: vite: specifier: ^7.3.1 version: 7.3.1(@types/node@22.19.11)(jiti@1.21.7)(tsx@4.21.0) + vite-plugin-static-copy: + specifier: ^3.2.0 + version: 3.2.0(vite@7.3.1(@types/node@22.19.11)(jiti@1.21.7)(tsx@4.21.0)) zod: specifier: ^3.24.2 version: 3.25.76 @@ -1739,9 +1748,15 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/jsonfile@6.1.4': + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -2227,6 +2242,10 @@ packages: react-dom: optional: true + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + engines: {node: '>=14.14'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2292,6 +2311,9 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + gtoken@8.0.0: resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} engines: {node: '>=18'} @@ -2430,6 +2452,9 @@ packages: engines: {node: '>=6'} hasBin: true + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} @@ -2681,6 +2706,10 @@ packages: ogl@1.0.11: resolution: {integrity: sha512-kUpC154AFfxi16pmZUK4jk3J+8zxwTWGPo03EoYA8QPbzikHoaC82n6pNTbd+oEaJonaE8aPWBlX7ad9zrqLsA==} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + p-retry@7.1.1: resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==} engines: {node: '>=20'} @@ -3147,6 +3176,10 @@ packages: unist-util-visit@5.1.0: resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + unplugin@2.3.11: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} @@ -3200,6 +3233,12 @@ packages: victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vite-plugin-static-copy@3.2.0: + resolution: {integrity: sha512-g2k9z8B/1Bx7D4wnFjPLx9dyYGrqWMLTpwTtPHhcU+ElNZP2O4+4OsyaficiDClus0dzVhdGvoGFYMJxoXZ12Q==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + vite@7.3.1: resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4686,10 +4725,19 @@ snapshots: '@types/estree@1.0.8': {} + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 22.19.11 + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 + '@types/jsonfile@6.1.4': + dependencies: + '@types/node': 22.19.11 + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -5142,6 +5190,12 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + fs-extra@11.3.3: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fsevents@2.3.3: optional: true @@ -5227,6 +5281,8 @@ snapshots: gopd@1.2.0: {} + graceful-fs@4.2.11: {} + gtoken@8.0.0: dependencies: gaxios: 7.1.3 @@ -5359,6 +5415,12 @@ snapshots: json5@2.2.3: {} + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 @@ -5711,6 +5773,8 @@ snapshots: ogl@1.0.11: {} + p-map@7.0.4: {} + p-retry@7.1.1: dependencies: is-network-error: 1.3.0 @@ -6234,6 +6298,8 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 + universalify@2.0.1: {} + unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 @@ -6304,6 +6370,14 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + vite-plugin-static-copy@3.2.0(vite@7.3.1(@types/node@22.19.11)(jiti@1.21.7)(tsx@4.21.0)): + dependencies: + chokidar: 3.6.0 + p-map: 7.0.4 + picocolors: 1.1.1 + tinyglobby: 0.2.15 + vite: 7.3.1(@types/node@22.19.11)(jiti@1.21.7)(tsx@4.21.0) + vite@7.3.1(@types/node@22.19.11)(jiti@1.21.7)(tsx@4.21.0): dependencies: esbuild: 0.27.3 diff --git a/public/sprite-test.html b/public/sprite-test.html new file mode 100644 index 0000000..5fbc581 --- /dev/null +++ b/public/sprite-test.html @@ -0,0 +1,64 @@ + + + + + + +

listing_spirit.svg (Width: 1301px, Height: 44px)

+
+ +

listing_spirit_2.svg

+
+ + + + diff --git a/schema_output.json b/schema_output.json new file mode 100644 index 0000000..785f904 --- /dev/null +++ b/schema_output.json @@ -0,0 +1,33 @@ +{ + "id": "92deb33a-98f5-4a26-a93e-029ed03a7f15", + "session_id": "79ba906e-7100-46ae-b2fb-63369a5c619b", + "college_id": "25535", + "college_name": "Maharshi Dayanand University - [MDU]", + "college_short_form": "MDU", + "state": "Haryana", + "college_city": "Rohtak", + "rating": 9, + "created_at": "2026-03-01T20:34:50.066064+00:00", + "logo_url": null, + "cover_url": null, + "stream_ranking_logo_url": null, + "ranking_logos": [], + "listing_name": "MDU", + "state_id": 13, + "city_id": 173, + "logo": "https://nttzqpcruzzsmtyimuth.supabase.co/storage/v1/object/public/college-assets/25535/logo.jpg", + "cover": "https://nttzqpcruzzsmtyimuth.supabase.co/storage/v1/object/public/college-assets/25535/cover.png", + "tagline": "Best in Infrastructure", + "url": "university/25535-maharshi-dayanand-university-mdu-rohtak", + "major_stream_rating": 8.9914, + "naac_grading": "A+", + "is_compare": true, + "single_page": false, + "placement_percentage": 0, + "photo_count": 0, + "video_count": 0, + "course_count": 0, + "updated_at": "2026-03-01T20:34:50.066064+00:00", + "deleted_at": null, + "search_vector": "'best':8C 'dayanand':2A 'haryana':7B 'infrastructur':10C 'maharshi':1A 'mdu':4A,5A 'rohtak':6B 'univers':3A" +} \ No newline at end of file diff --git a/src/assets/Ahmedabad.svg b/src/assets/Ahmedabad.svg new file mode 100644 index 0000000..43c87ba --- /dev/null +++ b/src/assets/Ahmedabad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Andhra Pradesh.svg b/src/assets/Andhra Pradesh.svg new file mode 100644 index 0000000..88ad44a --- /dev/null +++ b/src/assets/Andhra Pradesh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Bangalore.svg b/src/assets/Bangalore.svg new file mode 100644 index 0000000..4b3a781 --- /dev/null +++ b/src/assets/Bangalore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Bhopal.svg b/src/assets/Bhopal.svg new file mode 100644 index 0000000..2430509 --- /dev/null +++ b/src/assets/Bhopal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Bhubaneswar.svg b/src/assets/Bhubaneswar.svg new file mode 100644 index 0000000..c5a319c --- /dev/null +++ b/src/assets/Bhubaneswar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Bihar.svg b/src/assets/Bihar.svg new file mode 100644 index 0000000..1a0ad12 --- /dev/null +++ b/src/assets/Bihar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Chennai.svg b/src/assets/Chennai.svg new file mode 100644 index 0000000..2d8db1a --- /dev/null +++ b/src/assets/Chennai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Coimbatore.svg b/src/assets/Coimbatore.svg new file mode 100644 index 0000000..0c99bdb --- /dev/null +++ b/src/assets/Coimbatore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Dehradun.svg b/src/assets/Dehradun.svg new file mode 100644 index 0000000..6249edf --- /dev/null +++ b/src/assets/Dehradun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Gujarat.svg b/src/assets/Gujarat.svg new file mode 100644 index 0000000..2d3a5bc --- /dev/null +++ b/src/assets/Gujarat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Gurgaon.svg b/src/assets/Gurgaon.svg new file mode 100644 index 0000000..058adfa --- /dev/null +++ b/src/assets/Gurgaon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Hyderabad.svg b/src/assets/Hyderabad.svg new file mode 100644 index 0000000..919891c --- /dev/null +++ b/src/assets/Hyderabad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/India.svg b/src/assets/India.svg new file mode 100644 index 0000000..439d54e --- /dev/null +++ b/src/assets/India.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Indore.svg b/src/assets/Indore.svg new file mode 100644 index 0000000..58541ab --- /dev/null +++ b/src/assets/Indore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Jaipur.svg b/src/assets/Jaipur.svg new file mode 100644 index 0000000..d9ebd61 --- /dev/null +++ b/src/assets/Jaipur.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Karnataka.svg b/src/assets/Karnataka.svg new file mode 100644 index 0000000..54314ee --- /dev/null +++ b/src/assets/Karnataka.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Kerala.svg b/src/assets/Kerala.svg new file mode 100644 index 0000000..2dc5612 --- /dev/null +++ b/src/assets/Kerala.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Kolkata.svg b/src/assets/Kolkata.svg new file mode 100644 index 0000000..989f2f5 --- /dev/null +++ b/src/assets/Kolkata.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Lucknow.svg b/src/assets/Lucknow.svg new file mode 100644 index 0000000..691b874 --- /dev/null +++ b/src/assets/Lucknow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Madhya Pradesh.svg b/src/assets/Madhya Pradesh.svg new file mode 100644 index 0000000..b4b01c8 --- /dev/null +++ b/src/assets/Madhya Pradesh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Maharashtra.svg b/src/assets/Maharashtra.svg new file mode 100644 index 0000000..27c5a36 --- /dev/null +++ b/src/assets/Maharashtra.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Mumbai.svg b/src/assets/Mumbai.svg new file mode 100644 index 0000000..810c839 --- /dev/null +++ b/src/assets/Mumbai.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Nagpur.svg b/src/assets/Nagpur.svg new file mode 100644 index 0000000..cc27996 --- /dev/null +++ b/src/assets/Nagpur.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/New Delhi.svg b/src/assets/New Delhi.svg new file mode 100644 index 0000000..b8bf643 --- /dev/null +++ b/src/assets/New Delhi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Noida.svg b/src/assets/Noida.svg new file mode 100644 index 0000000..4dc823a --- /dev/null +++ b/src/assets/Noida.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Pune.svg b/src/assets/Pune.svg new file mode 100644 index 0000000..1152eed --- /dev/null +++ b/src/assets/Pune.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Rajasthan.svg b/src/assets/Rajasthan.svg new file mode 100644 index 0000000..42adff8 --- /dev/null +++ b/src/assets/Rajasthan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Tamil Nadu.svg b/src/assets/Tamil Nadu.svg new file mode 100644 index 0000000..993ca62 --- /dev/null +++ b/src/assets/Tamil Nadu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Telangana.svg b/src/assets/Telangana.svg new file mode 100644 index 0000000..8be6de1 --- /dev/null +++ b/src/assets/Telangana.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/Uttar Pradesh.svg b/src/assets/Uttar Pradesh.svg new file mode 100644 index 0000000..e0f0527 --- /dev/null +++ b/src/assets/Uttar Pradesh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/common-header-sprite.svg b/src/assets/common-header-sprite.svg new file mode 100644 index 0000000..8bee98e --- /dev/null +++ b/src/assets/common-header-sprite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/currency.json b/src/assets/currency.json new file mode 100644 index 0000000..148af26 --- /dev/null +++ b/src/assets/currency.json @@ -0,0 +1,2248 @@ +{ + "AED": { + "name": "UAE Dirham", + "fractionSize": 2, + "symbol": { + "grapheme": ".د.إ", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": null + }, + "AFN": { + "name": "Afghani", + "fractionSize": 2, + "symbol": { + "grapheme": "؋", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": "؋", + "template": "1 $", + "rtl": true + } + }, + "ALL": { + "name": "Lek", + "fractionSize": 2, + "symbol": { + "grapheme": "L", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Lek", + "template": "$1", + "rtl": false + } + }, + "AMD": { + "name": "Armenian Dram", + "fractionSize": 2, + "symbol": { + "grapheme": "դր.", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "դր.", + "template": "1 $", + "rtl": false + } + }, + "ANG": { + "name": "Netherlands Antillean Guilder", + "fractionSize": 2, + "symbol": { + "grapheme": "ƒ", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "NAƒ", + "template": "$1", + "rtl": false + } + }, + "AOA": { + "name": "Kwanza", + "fractionSize": 2, + "symbol": { + "grapheme": "Kz", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "ARS": { + "name": "Argentine Peso", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "AUD": { + "name": "Australian Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "A$", + "template": "$1", + "rtl": false + } + }, + "AWG": { + "name": "Aruban Florin", + "fractionSize": 2, + "symbol": { + "grapheme": "ƒ", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Afl", + "template": "$1", + "rtl": false + } + }, + "AZN": { + "name": "Azerbaijanian Manat", + "fractionSize": 2, + "symbol": { + "grapheme": "₼", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₼", + "template": "$1", + "rtl": false + } + }, + "BAM": { + "name": "Convertible Mark", + "fractionSize": 2, + "symbol": { + "grapheme": "KM", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "KM", + "template": "$1", + "rtl": false + } + }, + "BBD": { + "name": "Barbados Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "BDT": { + "name": "Taka", + "fractionSize": 2, + "symbol": { + "grapheme": "৳", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "BGN": { + "name": "Bulgarian Lev", + "fractionSize": 2, + "symbol": { + "grapheme": "лв", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "лв", + "template": "$1", + "rtl": false + } + }, + "BHD": { + "name": "Bahraini Dinar", + "fractionSize": 3, + "symbol": { + "grapheme": ".د.ب", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".د.ب", + "template": "1 $", + "rtl": true + } + }, + "BIF": { + "name": "Burundi Franc", + "fractionSize": 0, + "symbol": { + "grapheme": "FBu", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "BMD": { + "name": "Bermudian Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "BD$", + "template": "$1", + "rtl": false + } + }, + "BND": { + "name": "Brunei Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "BOB": { + "name": "Boliviano", + "fractionSize": 2, + "symbol": { + "grapheme": "Bs.", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Bs.", + "template": "$1", + "rtl": false + } + }, + "BOV": { + "name": "Mvdol", + "fractionSize": 2, + "symbol": { + "grapheme": "Bov", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "BRL": { + "name": "Brazilian Real", + "fractionSize": 2, + "symbol": { + "grapheme": "R$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "R$", + "template": "$1", + "rtl": false + } + }, + "BSD": { + "name": "Bahamian Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "BTN": { + "name": "Ngultrum", + "fractionSize": 2, + "symbol": { + "grapheme": "Nu.", + "template": "$ 1", + "rtl": false + }, + "uniqSymbol": null + }, + "BWP": { + "name": "Pula", + "fractionSize": 2, + "symbol": { + "grapheme": "P", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "P", + "template": "$1", + "rtl": false + } + }, + "BYN": { + "name": "Belarussian Ruble", + "fractionSize": 2, + "symbol": { + "grapheme": "p.", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "р.", + "template": "1 $", + "rtl": false + } + }, + "BYR": { + "name": "Belarussian Ruble", + "fractionSize": 0, + "symbol": { + "grapheme": "p.", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "р.", + "template": "1 $", + "rtl": false + } + }, + "BZD": { + "name": "Belize Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "BZ$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "BZ$", + "template": "$1", + "rtl": false + } + }, + "CAD": { + "name": "Canadian Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "CA$", + "template": "$1", + "rtl": false + } + }, + "CDF": { + "name": "Congolese Franc", + "fractionSize": 2, + "symbol": { + "grapheme": "FC", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CHE": { + "name": "WIR Euro", + "fractionSize": 2, + "symbol": { + "grapheme": "CHE", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CHF": { + "name": "Swiss Franc", + "fractionSize": 2, + "symbol": { + "grapheme": "fr.", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CHW": { + "name": "WIR Franc", + "fractionSize": 2, + "symbol": { + "grapheme": "CHW", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CLF": { + "name": "Unidad de Fomento", + "fractionSize": 4, + "symbol": { + "grapheme": "UF", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CLP": { + "name": "Chilean Peso", + "fractionSize": 0, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "CNY": { + "name": "Yuan Renminbi", + "fractionSize": 2, + "symbol": { + "grapheme": "元", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "元", + "template": "1 $", + "rtl": false + } + }, + "COP": { + "name": "Colombian Peso", + "fractionSize": 0, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "COU": { + "name": "Unidad de Valor Real", + "fractionSize": 2, + "symbol": { + "grapheme": "COU", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CRC": { + "name": "Cost Rican Colon", + "fractionSize": 2, + "symbol": { + "grapheme": "₡", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₡", + "template": "$1", + "rtl": false + } + }, + "CUC": { + "name": "Peso Convertible", + "fractionSize": 2, + "symbol": { + "grapheme": "CUC", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CUP": { + "name": "Cuban Peso", + "fractionSize": 2, + "symbol": { + "grapheme": "$MN", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "$MN", + "template": "$1", + "rtl": false + } + }, + "CVE": { + "name": "Cabo Verde Escudo", + "fractionSize": 2, + "symbol": { + "grapheme": "esc", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "CZK": { + "name": "Czech Koruna", + "fractionSize": 2, + "symbol": { + "grapheme": "Kč", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Kč", + "template": "1 $", + "rtl": false + } + }, + "DJF": { + "name": "Djibouti Franc", + "fractionSize": 0, + "symbol": { + "grapheme": "Fdj", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "DKK": { + "name": "Danish Krone", + "fractionSize": 2, + "symbol": { + "grapheme": "kr", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "DOP": { + "name": "Dominican Peso", + "fractionSize": 2, + "symbol": { + "grapheme": "RD$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "RD$", + "template": "$1", + "rtl": false + } + }, + "DZD": { + "name": "Algerian Dinar", + "fractionSize": 2, + "symbol": { + "grapheme": ".د.ج", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".د.ج", + "template": "1 $", + "rtl": true + } + }, + "EEK": { + "name": "Estonian Kroon", + "fractionSize": 2, + "symbol": { + "grapheme": "kr", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "EGP": { + "name": "Egyptian Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": ".ج.م", + "template": "1 $", + "rtl": true + } + }, + "ERN": { + "name": "Nakfa", + "fractionSize": 2, + "symbol": { + "grapheme": "Nkf", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "ETB": { + "name": "Ethiopian Birr", + "fractionSize": 2, + "symbol": { + "grapheme": "Br", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "EUR": { + "name": "Euro", + "fractionSize": 2, + "symbol": { + "grapheme": "€", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "€", + "template": "$1", + "rtl": false + } + }, + "FJD": { + "name": "Fiji Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "FJ$", + "template": "$1", + "rtl": false + } + }, + "FKP": { + "name": "Falkland Islands Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "GBP": { + "name": "Pound Sterling", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + } + }, + "GEL": { + "name": "Lari", + "fractionSize": 2, + "symbol": { + "grapheme": "GEL", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "GGP": { + "name": "Guernsey Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "GHC": { + "name": "Ghanaian Cedi", + "fractionSize": 2, + "symbol": { + "grapheme": "¢", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "¢", + "template": "$1", + "rtl": false + } + }, + "GHS": { + "name": "Ghan Cedi", + "fractionSize": 2, + "symbol": { + "grapheme": "GH₵", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "GIP": { + "name": "Gibraltar Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "GMD": { + "name": "Dalasi", + "fractionSize": 2, + "symbol": { + "grapheme": "D", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "GNF": { + "name": "Guine Franc", + "fractionSize": 0, + "symbol": { + "grapheme": "GFr", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "GTQ": { + "name": "Quetzal", + "fractionSize": 2, + "symbol": { + "grapheme": "Q", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Q", + "template": "$1", + "rtl": false + } + }, + "GYD": { + "name": "Guyan Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "GY$", + "template": "$1", + "rtl": false + } + }, + "HKD": { + "name": "Hong Kong Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "HK$", + "template": "$1", + "rtl": false + } + }, + "HNL": { + "name": "Lempira", + "fractionSize": 2, + "symbol": { + "grapheme": "L", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "L", + "template": "$1", + "rtl": false + } + }, + "HRK": { + "name": "Croatian Kuna", + "fractionSize": 2, + "symbol": { + "grapheme": "kn", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "kn", + "template": "$1", + "rtl": false + } + }, + "HTG": { + "name": "Gourde", + "fractionSize": 2, + "symbol": { + "grapheme": "G", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "HUF": { + "name": "Forint", + "fractionSize": 0, + "symbol": { + "grapheme": "Ft", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Ft", + "template": "$1", + "rtl": false + } + }, + "IDR": { + "name": "Rupiah", + "fractionSize": 2, + "symbol": { + "grapheme": "Rp", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Rp", + "template": "$1", + "rtl": false + } + }, + "ILS": { + "name": "New Israeli Sheqel", + "fractionSize": 2, + "symbol": { + "grapheme": "₪", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₪", + "template": "$1", + "rtl": false + } + }, + "IMP": { + "name": "Manx Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "INR": { + "name": "Indian Rupee", + "fractionSize": 2, + "symbol": { + "grapheme": "₹", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₹", + "template": "$1", + "rtl": false + } + }, + "IQD": { + "name": "Iraqi Dinar", + "fractionSize": 3, + "symbol": { + "grapheme": ".د.ع", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".د.ع", + "template": "1 $", + "rtl": true + } + }, + "IRR": { + "name": "Iranian Rial", + "fractionSize": 0, + "symbol": { + "grapheme": "﷼", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": "﷼", + "template": "1 $", + "rtl": true + } + }, + "ISK": { + "name": "Iceland Krona", + "fractionSize": 2, + "symbol": { + "grapheme": "kr", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "JEP": { + "name": "Jersey Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "JMD": { + "name": "Jamaican Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "J$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "J$", + "template": "$1", + "rtl": false + } + }, + "JOD": { + "name": "Jordanian Dinar", + "fractionSize": 3, + "symbol": { + "grapheme": ".د.إ", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": null + }, + "JPY": { + "name": "Yen", + "fractionSize": 0, + "symbol": { + "grapheme": "¥", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "¥", + "template": "$1", + "rtl": false + } + }, + "KES": { + "name": "Kenyan Shilling", + "fractionSize": 2, + "symbol": { + "grapheme": "KSh", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "KSh", + "template": "$1", + "rtl": false + } + }, + "KGS": { + "name": "Som", + "fractionSize": 2, + "symbol": { + "grapheme": "сом", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "сом", + "template": "$1", + "rtl": false + } + }, + "KHR": { + "name": "Riel", + "fractionSize": 2, + "symbol": { + "grapheme": "៛", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "៛", + "template": "$1", + "rtl": false + } + }, + "KMF": { + "name": "Comoro Franc", + "fractionSize": 0, + "symbol": { + "grapheme": "CF", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "KPW": { + "name": "North Korean Won", + "fractionSize": 0, + "symbol": { + "grapheme": "₩", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "KRW": { + "name": "Won", + "fractionSize": 0, + "symbol": { + "grapheme": "₩", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₩", + "template": "$1", + "rtl": false + } + }, + "KWD": { + "name": "Kuwaiti Dinar", + "fractionSize": 3, + "symbol": { + "grapheme": ".د.ك", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".د.ك", + "template": "1 $", + "rtl": true + } + }, + "KYD": { + "name": "Cayman Islands Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "CI$", + "template": "$1", + "rtl": false + } + }, + "KZT": { + "name": "Tenge", + "fractionSize": 2, + "symbol": { + "grapheme": "₸", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₸", + "template": "$1", + "rtl": false + } + }, + "LAK": { + "name": "Kip", + "fractionSize": 2, + "symbol": { + "grapheme": "₭", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₭", + "template": "$1", + "rtl": false + } + }, + "LBP": { + "name": "Lebanese Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": ".ل.ل", + "template": "1 $", + "rtl": true + } + }, + "LKR": { + "name": "Sri Lank Rupee", + "fractionSize": 2, + "symbol": { + "grapheme": "₨", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "LRD": { + "name": "Liberian Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "L$", + "template": "$1", + "rtl": false + } + }, + "LSL": { + "name": "Loti", + "fractionSize": 2, + "symbol": { + "grapheme": "LSL", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "LTL": { + "name": "Lithuanian Litas", + "fractionSize": 2, + "symbol": { + "grapheme": "Lt", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Lt", + "template": "$1", + "rtl": false + } + }, + "LVL": { + "name": "Latvian Lats", + "fractionSize": 2, + "symbol": { + "grapheme": "Ls", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Ls", + "template": "1 $", + "rtl": false + } + }, + "LYD": { + "name": "Libyan Dinar", + "fractionSize": 3, + "symbol": { + "grapheme": ".د.ل", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".د.ل", + "template": "1 $", + "rtl": true + } + }, + "MAD": { + "name": "Moroccan Dirham", + "fractionSize": 2, + "symbol": { + "grapheme": ".د.م", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".د.م", + "template": "1 $", + "rtl": true + } + }, + "MDL": { + "name": "Moldovan Leu", + "fractionSize": 2, + "symbol": { + "grapheme": "lei", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "MGA": { + "name": "Malagasy ariary", + "fractionSize": 1, + "symbol": { + "grapheme": "Ar", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "MKD": { + "name": "Denar", + "fractionSize": 2, + "symbol": { + "grapheme": "ден", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "ден", + "template": "$1", + "rtl": false + } + }, + "MMK": { + "name": "Kyat", + "fractionSize": 2, + "symbol": { + "grapheme": "K", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "MNT": { + "name": "Tugrik", + "fractionSize": 2, + "symbol": { + "grapheme": "₮", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₮", + "template": "$1", + "rtl": false + } + }, + "MOP": { + "name": "Pataca", + "fractionSize": 2, + "symbol": { + "grapheme": "MOP$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "MRO": { + "name": "Ouguiya", + "fractionSize": 2, + "symbol": { + "grapheme": "ouguiya", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "MUR": { + "name": "Mauritius Rupee", + "fractionSize": 2, + "symbol": { + "grapheme": "₨", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "MVR": { + "name": "Rufiyaa", + "fractionSize": 2, + "symbol": { + "grapheme": "MVR", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "MWK": { + "name": "Kwacha", + "fractionSize": 2, + "symbol": { + "grapheme": "MK", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "MXN": { + "name": "Mexican Peso", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "MXV": { + "name": "Mexican Unidad de Inversion (UDI)", + "fractionSize": 2, + "symbol": { + "grapheme": "UDI", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "MYR": { + "name": "Malaysian Ringgit", + "fractionSize": 2, + "symbol": { + "grapheme": "RM", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "RM", + "template": "$1", + "rtl": false + } + }, + "MZN": { + "name": "Mozambique Metical", + "fractionSize": 2, + "symbol": { + "grapheme": "MT", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "MT", + "template": "$1", + "rtl": false + } + }, + "NAD": { + "name": "Namibi Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "N$", + "template": "$1", + "rtl": false + } + }, + "NGN": { + "name": "Naira", + "fractionSize": 2, + "symbol": { + "grapheme": "₦", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₦", + "template": "$1", + "rtl": false + } + }, + "NIO": { + "name": "Cordob Oro", + "fractionSize": 2, + "symbol": { + "grapheme": "C$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "C$", + "template": "$1", + "rtl": false + } + }, + "NOK": { + "name": "Norwegian Krone", + "fractionSize": 2, + "symbol": { + "grapheme": "kr", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "NPR": { + "name": "Nepalese Rupee", + "fractionSize": 2, + "symbol": { + "grapheme": "₨", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "NZD": { + "name": "New Zealand Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "NZ$", + "template": "$1", + "rtl": false + } + }, + "OMR": { + "name": "Rial Omani", + "fractionSize": 3, + "symbol": { + "grapheme": "﷼", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".ر.ع", + "template": "1 $", + "rtl": true + } + }, + "PAB": { + "name": "Balboa", + "fractionSize": 2, + "symbol": { + "grapheme": "B/.", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "B/.", + "template": "$1", + "rtl": false + } + }, + "PEN": { + "name": "Nuevo Sol", + "fractionSize": 2, + "symbol": { + "grapheme": "S/", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "S/", + "template": "$1", + "rtl": false + } + }, + "PGK": { + "name": "Kina", + "fractionSize": 2, + "symbol": { + "grapheme": "K", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "PHP": { + "name": "Philippine Peso", + "fractionSize": 2, + "symbol": { + "grapheme": "₱", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₱", + "template": "$1", + "rtl": false + } + }, + "PKR": { + "name": "Pakistan Rupee", + "fractionSize": 2, + "symbol": { + "grapheme": "₨", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "PLN": { + "name": "Zloty", + "fractionSize": 2, + "symbol": { + "grapheme": "zł", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "zł", + "template": "1 $", + "rtl": false + } + }, + "PYG": { + "name": "Guarani", + "fractionSize": 0, + "symbol": { + "grapheme": "Gs", + "template": "1$", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Gs", + "template": "1$", + "rtl": false + } + }, + "QAR": { + "name": "Qatari Rial", + "fractionSize": 2, + "symbol": { + "grapheme": "﷼", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".ر.ق", + "template": "1 $", + "rtl": true + } + }, + "RON": { + "name": "New Romanian Leu", + "fractionSize": 2, + "symbol": { + "grapheme": "lei", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "lei", + "template": "$1", + "rtl": false + } + }, + "RSD": { + "name": "Serbian Dinar", + "fractionSize": 2, + "symbol": { + "grapheme": "Дин.", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Дин.", + "template": "$1", + "rtl": false + } + }, + "RUB": { + "name": "Russian Ruble", + "fractionSize": 2, + "symbol": { + "grapheme": "₽", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₽", + "template": "1 $", + "rtl": false + } + }, + "RUR": { + "name": "Russian Ruble", + "fractionSize": 2, + "symbol": { + "grapheme": "₽", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₽", + "template": "1 $", + "rtl": false + } + }, + "RWF": { + "name": "Rwand Franc", + "fractionSize": 0, + "symbol": { + "grapheme": "R₣", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "SAR": { + "name": "Saudi Riyal", + "fractionSize": 2, + "symbol": { + "grapheme": "﷼", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".ر.س", + "template": "1 $", + "rtl": true + } + }, + "SBD": { + "name": "Solomon Islands Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "SI$", + "template": "$1", + "rtl": false + } + }, + "SCR": { + "name": "Seychelles Rupee", + "fractionSize": 2, + "symbol": { + "grapheme": "₨", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "SDG": { + "name": "Sudanese Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "SDG", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "SEK": { + "name": "Swedish Krona", + "fractionSize": 2, + "symbol": { + "grapheme": "kr", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "SGD": { + "name": "Singapore Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "S$", + "template": "$1", + "rtl": false + } + }, + "SHP": { + "name": "Saint Helen Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "SLL": { + "name": "Leone", + "fractionSize": 2, + "symbol": { + "grapheme": "Le", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "SOS": { + "name": "Somali Shilling", + "fractionSize": 2, + "symbol": { + "grapheme": "S", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "S", + "template": "$1", + "rtl": false + } + }, + "SRD": { + "name": "Surinam Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "SSP": { + "name": "South Sudanese Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "SS£", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "STD": { + "name": "Dobra", + "fractionSize": 2, + "symbol": { + "grapheme": "Db", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "SVC": { + "name": "El Salvador Colon", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "C", + "template": "$1", + "rtl": false + } + }, + "SYP": { + "name": "Syrian Pound", + "fractionSize": 2, + "symbol": { + "grapheme": "£", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": ".ل.س", + "template": "1 $", + "rtl": true + } + }, + "SZL": { + "name": "Lilangeni", + "fractionSize": 2, + "symbol": { + "grapheme": "L", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "THB": { + "name": "Baht", + "fractionSize": 2, + "symbol": { + "grapheme": "฿", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "฿", + "template": "$1", + "rtl": false + } + }, + "TJS": { + "name": "Somoni", + "fractionSize": 2, + "symbol": { + "grapheme": "SM", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "TMT": { + "name": "Turkmenistan New Manat", + "fractionSize": 2, + "symbol": { + "grapheme": "T", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "TND": { + "name": "Tunisian Dinar", + "fractionSize": 3, + "symbol": { + "grapheme": ".د.ت", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".د.ت", + "template": "1 $", + "rtl": true + } + }, + "TOP": { + "name": "Pa’anga", + "fractionSize": 2, + "symbol": { + "grapheme": "T$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "TRL": { + "name": "Turkish Lira", + "fractionSize": 2, + "symbol": { + "grapheme": "₤", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "TRY": { + "name": "Turkish Lira", + "fractionSize": 2, + "symbol": { + "grapheme": "₺", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₺", + "template": "$1", + "rtl": false + } + }, + "TTD": { + "name": "Trinidad and Tobago Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "TT$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "TT$", + "template": "$1", + "rtl": false + } + }, + "TWD": { + "name": "New Taiwan Dollar", + "fractionSize": 0, + "symbol": { + "grapheme": "NT$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "NT$", + "template": "$1", + "rtl": false + } + }, + "TZS": { + "name": "Tanzanian Shilling", + "fractionSize": 0, + "symbol": { + "grapheme": "TSh", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "TSh", + "template": "$1", + "rtl": false + } + }, + "UAH": { + "name": "Hryvnia", + "fractionSize": 2, + "symbol": { + "grapheme": "₴", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₴", + "template": "$1", + "rtl": false + } + }, + "UGX": { + "name": "Ugand Shilling", + "fractionSize": 0, + "symbol": { + "grapheme": "USh", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "USh", + "template": "$1", + "rtl": false + } + }, + "USD": { + "name": "US Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "US$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "US$", + "template": "$1", + "rtl": false + } + }, + "USN": { + "name": "US Dollar (Next day)", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "UYI": { + "name": "Uruguay Peso en Unidades Indexadas (URUIURUI)", + "fractionSize": 0, + "symbol": { + "grapheme": "$U", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "UYU": { + "name": "Peso Uruguayo", + "fractionSize": 0, + "symbol": { + "grapheme": "$U", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "$U", + "template": "$1", + "rtl": false + } + }, + "UZS": { + "name": "Uzbekistan Sum", + "fractionSize": 2, + "symbol": { + "grapheme": "so’m", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "so’m", + "template": "$1", + "rtl": false + } + }, + "VEF": { + "name": "Bolivar", + "fractionSize": 2, + "symbol": { + "grapheme": "Bs", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Bs", + "template": "$1", + "rtl": false + } + }, + "VES": { + "name": "Bolivar", + "fractionSize": 2, + "symbol": { + "grapheme": "Bs", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Bs", + "template": "$1", + "rtl": false + } + }, + "VND": { + "name": "Dong", + "fractionSize": 0, + "symbol": { + "grapheme": "₫", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₫", + "template": "1 $", + "rtl": false + } + }, + "VUV": { + "name": "Vatu", + "fractionSize": 0, + "symbol": { + "grapheme": "VT", + "template": "1$", + "rtl": false + }, + "uniqSymbol": null + }, + "WST": { + "name": "Tala", + "fractionSize": 2, + "symbol": { + "grapheme": "WS$", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "XAF": { + "name": "CFA Franc BEAC", + "fractionSize": 0, + "symbol": { + "grapheme": "FCFA", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "FCFA", + "template": "1 $", + "rtl": false + } + }, + "XCD": { + "name": "East Caribbean Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "EC$", + "template": "$1", + "rtl": false + } + }, + "XDR": { + "name": "SDR (Special Drawing Right)", + "fractionSize": 0, + "symbol": { + "grapheme": "SDR", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "XOF": { + "name": "CFA Franc BCEAO", + "fractionSize": 0, + "symbol": { + "grapheme": "CFA", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "CFA", + "template": "1 $", + "rtl": false + } + }, + "XPF": { + "name": "CFP Franc", + "fractionSize": 0, + "symbol": { + "grapheme": "₣", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "XSU": { + "name": "Sucre", + "fractionSize": 0, + "symbol": { + "grapheme": "XSU", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "XUA": { + "name": "ADB Unit of Account", + "fractionSize": 0, + "symbol": { + "grapheme": "XUA", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "YER": { + "name": "Yemeni Rial", + "fractionSize": 2, + "symbol": { + "grapheme": "﷼", + "template": "1 $", + "rtl": true + }, + "uniqSymbol": { + "grapheme": ".ر.ي", + "template": "1 $", + "rtl": true + } + }, + "ZAR": { + "name": "Rand", + "fractionSize": 2, + "symbol": { + "grapheme": "R", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "R", + "template": "$1", + "rtl": false + } + }, + "ZMW": { + "name": "Zambian Kwacha", + "fractionSize": 2, + "symbol": { + "grapheme": "K", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": null + }, + "ZWD": { + "name": "Zimbabwe Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "Z$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Z$", + "template": "$1", + "rtl": false + } + }, + "ZWL": { + "name": "Zimbabwe Dollar", + "fractionSize": 2, + "symbol": { + "grapheme": "Z$", + "template": "$1", + "rtl": false + }, + "uniqSymbol": null + }, + "BTC": { + "name": "BTC", + "fractionSize": 4, + "symbol": { + "grapheme": "₿", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "₿", + "template": "1 $", + "rtl": false + } + }, + "ETH": { + "name": "ETH", + "fractionSize": 4, + "symbol": { + "grapheme": "Ξ", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Ξ", + "template": "1 $", + "rtl": false + } + }, + "LTC": { + "name": "LTC", + "fractionSize": 4, + "symbol": { + "grapheme": "Ł", + "template": "1 $", + "rtl": false + }, + "uniqSymbol": { + "grapheme": "Ł", + "template": "1 $", + "rtl": false + } + } +} \ No newline at end of file diff --git a/src/assets/desktop-homepage-course-banner.webp b/src/assets/desktop-homepage-course-banner.webp new file mode 100644 index 0000000..c9ce1d8 Binary files /dev/null and b/src/assets/desktop-homepage-course-banner.webp differ diff --git a/src/assets/listing_spirit.svg b/src/assets/listing_spirit.svg new file mode 100644 index 0000000..d6861bc --- /dev/null +++ b/src/assets/listing_spirit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/listing_spirit_2.svg b/src/assets/listing_spirit_2.svg new file mode 100644 index 0000000..8370883 --- /dev/null +++ b/src/assets/listing_spirit_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/prize-1.png b/src/assets/prize-1.png new file mode 100644 index 0000000..27b0ecb Binary files /dev/null and b/src/assets/prize-1.png differ diff --git a/src/assets/prize-2.png b/src/assets/prize-2.png new file mode 100644 index 0000000..b7f129f Binary files /dev/null and b/src/assets/prize-2.png differ diff --git a/src/assets/prize-3.png b/src/assets/prize-3.png new file mode 100644 index 0000000..5b49a1c Binary files /dev/null and b/src/assets/prize-3.png differ diff --git a/src/assets/prize-4.png b/src/assets/prize-4.png new file mode 100644 index 0000000..fe5f9e2 Binary files /dev/null and b/src/assets/prize-4.png differ diff --git a/src/assets/prize-5.png b/src/assets/prize-5.png new file mode 100644 index 0000000..65fdde3 Binary files /dev/null and b/src/assets/prize-5.png differ diff --git a/src/assets/prize-6.png b/src/assets/prize-6.png new file mode 100644 index 0000000..7680e55 Binary files /dev/null and b/src/assets/prize-6.png differ diff --git a/src/assets/review-banner-header.svg b/src/assets/review-banner-header.svg new file mode 100644 index 0000000..ec68d0f --- /dev/null +++ b/src/assets/review-banner-header.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/some-silo-sprite.svg b/src/assets/some-silo-sprite.svg new file mode 100644 index 0000000..139e6e8 --- /dev/null +++ b/src/assets/some-silo-sprite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 16c8d9b..e926de2 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,33 +1,58 @@ - -import React, { useState, useRef, useEffect } from 'react'; +import { Button } from '@/src/components/ui/button'; +import { Input } from '@/src/components/ui/input'; import { Link, useNavigate, useRouter } from '@tanstack/react-router'; -import { motion, AnimatePresence } from 'framer-motion'; +import { AnimatePresence, motion } from 'framer-motion'; import { - Search, ChevronDown, Menu, User, Bell, Grid, - PenTool, Globe, GraduationCap, Headset, - Building2, ChevronRight, CheckCircle, - Star, Stethoscope, ShieldCheck, X, FileText, - CheckCircle2, Pencil, Calculator + Bell, + Building2, + Calculator, + CheckCircle, + CheckCircle2, + ChevronDown, + ChevronRight, + FileText, + Globe, + GraduationCap, + Grid, + Headset, + Menu, + PenTool, + Pencil, + Search, + ShieldCheck, + Star, + Stethoscope, + User, + X, } from 'lucide-react'; -import { CounselingModal } from './CounselingModal'; +import type React from 'react'; +import { useEffect, useRef, useState } from 'react'; import { AuthModal } from './AuthModal'; -import { CurrencyModal } from './CurrencyModal'; +import { CounselingModal } from './CounselingModal'; import { CountryModal } from './CountryModal'; +import { CurrencyModal } from './CurrencyModal'; import { GoalSelectionModal } from './GoalSelectionModal'; -import { Button } from '@/src/components/ui/button'; -import { Input } from '@/src/components/ui/input'; -import { CourseCategoryIcon } from './CourseCategoryIcon'; import { - COURSE_CATEGORIES, ALL_COURSE_LABELS, + COURSE_CATEGORIES, POPULAR_CITIES, POPULAR_STATES, getIconUrl, } from '../constants/courseCategories'; +import { CourseCategoryIcon } from './CourseCategoryIcon'; const EXPLORE_ITEMS = [ - { title: "Top Universities & Colleges", icon: Building2, links: ["Top MBA Colleges", "Top Engineering Colleges", "Top Medical Colleges", "Top Universities in India"] }, + { + title: 'Top Universities & Colleges', + icon: Building2, + links: [ + 'Top MBA Colleges', + 'Top Engineering Colleges', + 'Top Medical Colleges', + 'Top Universities in India', + ], + }, // ... ]; const NOTIFICATIONS = [ @@ -47,11 +72,21 @@ const MOCK_SEARCH_SUGGESTIONS = [ { id: '8', name: 'Amity University', location: 'Noida', type: 'college' }, { id: '9', name: 'JEE Main 2026', location: 'Exam', type: 'exam' }, { id: '10', name: 'NEET 2026', location: 'Exam', type: 'exam' }, - { id: '11', name: 'CAT 2026', location: 'Exam', type: 'exam' } + { id: '11', name: 'CAT 2026', location: 'Exam', type: 'exam' }, ]; // Removed 'All Courses' from quick links as it will be handled separately -const QUICK_LINKS = ['B.Tech', 'MBA', 'M.Tech', 'MBBS', 'B.Com', 'B.Sc', 'B.Sc (Nursing)', 'BA', 'BBA']; +const QUICK_LINKS = [ + 'B.Tech', + 'MBA', + 'M.Tech', + 'MBBS', + 'B.Com', + 'B.Sc', + 'B.Sc (Nursing)', + 'BA', + 'BBA', +]; export const Navbar: React.FC = () => { const navigate = useNavigate(); @@ -89,10 +124,14 @@ export const Navbar: React.FC = () => { if (modalRef.current && !modalRef.current.contains(event.target as Node)) { setIsGoalModalOpen(false); } - if (exploreRef.current && !exploreRef.current.contains(event.target as Node)) setIsExploreOpen(false); - if (notifRef.current && !notifRef.current.contains(event.target as Node)) setIsNotificationOpen(false); - if (userMenuRef.current && !userMenuRef.current.contains(event.target as Node)) setIsUserMenuOpen(false); - if (allCoursesRef.current && !allCoursesRef.current.contains(event.target as Node)) setIsAllCoursesOpen(false); + if (exploreRef.current && !exploreRef.current.contains(event.target as Node)) + setIsExploreOpen(false); + if (notifRef.current && !notifRef.current.contains(event.target as Node)) + setIsNotificationOpen(false); + if (userMenuRef.current && !userMenuRef.current.contains(event.target as Node)) + setIsUserMenuOpen(false); + if (allCoursesRef.current && !allCoursesRef.current.contains(event.target as Node)) + setIsAllCoursesOpen(false); }; // Listen for custom event to open goal modal from other components @@ -129,9 +168,10 @@ export const Navbar: React.FC = () => { setFilteredSuggestions([]); return; } - const filtered = MOCK_SEARCH_SUGGESTIONS.filter(c => - c.name.toLowerCase().includes(searchTerm.toLowerCase()) || - c.location.toLowerCase().includes(searchTerm.toLowerCase()) + const filtered = MOCK_SEARCH_SUGGESTIONS.filter( + (c) => + c.name.toLowerCase().includes(searchTerm.toLowerCase()) || + c.location.toLowerCase().includes(searchTerm.toLowerCase()) ); setFilteredSuggestions(filtered); }, [searchTerm]); @@ -140,48 +180,55 @@ export const Navbar: React.FC = () => { if (suggestion.type === 'exam') { navigate({ to: '/exams' }); } else { - navigate({ to: '/colleges/$id', params: { id: suggestion.id } as any }); + navigate({ to: '/college/$id', params: { id: suggestion.id } as any }); } setShowSuggestions(false); setSearchTerm(''); }; - const filteredAllCourses = ALL_COURSE_LABELS.filter(c => c.toLowerCase().includes(allCoursesSearch.toLowerCase())); + const filteredAllCourses = ALL_COURSE_LABELS.filter((c) => + c.toLowerCase().includes(allCoursesSearch.toLowerCase()) + ); return ( <> -
+
{/* --- TOP HEADER --- */} -
-
- +
+
{/* Logo & Select Goal */} -
- -
- +
+ +
+
-
- BRIGHT CAREER - SOLUTION +
+ + BRIGHT CAREER + + + SOLUTION +
{/* Select Goal Trigger - Show ONLY on Non-Study Abroad Pages */} {!isStudyAbroad && ( -
+
@@ -197,51 +244,62 @@ export const Navbar: React.FC = () => { {/* Select Country Trigger - Show ONLY on Study Abroad Pages */} {isStudyAbroad && ( )}
{/* Search Bar */} -
-
- + +
+
setSearchTerm(e.target.value)} onFocus={() => setShowSuggestions(true)} onBlur={() => setTimeout(() => setShowSuggestions(false), 200)} - placeholder="Search for Colleges, Exams, Courses and More..." - className="w-full pl-10 pr-4 py-3 bg-gray-50 border border-transparent rounded-md focus:bg-white focus:border-gray-200 focus:shadow-lg focus:ring-0 outline-none transition-all text-sm font-medium placeholder-gray-500 text-gray-900" + placeholder='Search for Colleges, Exams, Courses and More...' + className='w-full pl-10 pr-4 py-3 bg-gray-50 border border-transparent rounded-md focus:bg-white focus:border-gray-200 focus:shadow-lg focus:ring-0 outline-none transition-all text-sm font-medium placeholder-gray-500 text-gray-900' /> {/* Search Suggestions Dropdown */} {showSuggestions && searchTerm && filteredSuggestions.length > 0 && ( -
-
Suggestions
+
+
+ Suggestions +
{filteredSuggestions.map((item) => (
handleSuggestionClick(item)} > -
-
- {item.type === 'exam' ? : } +
+
+ {item.type === 'exam' ? ( + + ) : ( + + )}
-
{item.name}
-
{item.location}
+
+ {item.name} +
+
{item.location}
- +
))}
@@ -249,54 +307,62 @@ export const Navbar: React.FC = () => { {/* Right Actions */} -
- +
{/* Currency Trigger - Show ONLY on Study Abroad Pages */} {isStudyAbroad && ( )} {/* Get Counselling Button */} {/* Write Review */} - - -
- Write a Review - Get ₹300* + + +
+ Write a Review + + Get ₹300* +
{/* Explore Menu Trigger */} -
+
{/* EXPLORE MEGA MENU */} @@ -306,21 +372,23 @@ export const Navbar: React.FC = () => { initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 10 }} - className="absolute top-[50px] right-0 w-[600px] bg-white rounded-xl shadow-2xl border border-gray-100 overflow-hidden z-[90] p-6" + className='absolute top-[50px] right-0 w-[600px] bg-white rounded-xl shadow-2xl border border-gray-100 overflow-hidden z-[90] p-6' > -
+
{EXPLORE_ITEMS.map((section, idx) => ( -
-
- {section.title} +
+
+ {section.title}
-
- {section.links.map(link => ( +
+ {section.links.map((link) => ( {link} @@ -335,15 +403,15 @@ export const Navbar: React.FC = () => {
{/* Notifications */} -
+
{/* Notification Dropdown */} @@ -353,42 +421,62 @@ export const Navbar: React.FC = () => { initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 10 }} - className="absolute top-12 right-0 w-80 bg-white rounded-xl shadow-xl border border-gray-100 overflow-hidden z-[80]" + className='absolute top-12 right-0 w-80 bg-white rounded-xl shadow-xl border border-gray-100 overflow-hidden z-[80]' > -
-

Notifications

- +
+

Notifications

+
-
+
{NOTIFICATIONS.map((notif, i) => ( -
-
- {!notif.read &&
} +
+
+ {!notif.read && ( +
+ )}
-

{notif.title}

-

{notif.time}

+

+ {notif.title} +

+

{notif.time}

))}
- View All + + View All + )}
{/* User Menu */} -
+
@@ -398,79 +486,111 @@ export const Navbar: React.FC = () => { initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 10 }} - className="absolute top-14 right-0 w-[360px] bg-white rounded-xl shadow-2xl border border-gray-100 overflow-hidden z-[100]" + className='absolute top-14 right-0 w-[360px] bg-white rounded-xl shadow-2xl border border-gray-100 overflow-hidden z-[100]' > -
+
-
-
-
- +
+
+
+
-

Hello, Welcome To Bright Career Solution

-
- -

Search Colleges, Exams, Courses & More

+

+ Hello, Welcome To Bright Career Solution +

+
+ +

+ Search Colleges, Exams, Courses & More +

{/* Write Review Promo */} -
-
-
Write a Review &
Earn Upto 20 USD*
-
- - - - - +
+
+
+ Write a Review &
Earn Upto 20 USD* +
+
+ + + + +
{/* Illustration Placeholder */} -
- - - - - +
+ + + + +
{/* App Download */} -
-
-
Get Bright Career Solution App
-

For 10x Faster Results

-
- -
-
- QR +
+ QR
@@ -483,15 +603,14 @@ export const Navbar: React.FC = () => {
{/* --- SECONDARY NAVBAR (Black) --- */} -
-
-
- +
+
+
{/* All Courses Drawer Trigger */} -
+
-
- +
+ setAllCoursesSearch(e.target.value)} /> @@ -529,24 +655,28 @@ export const Navbar: React.FC = () => {
{/* List Section */} -
-
    +
    +
      {filteredAllCourses.length > 0 ? ( filteredAllCourses.map((course) => ( -
    • +
    • setIsAllCoursesOpen(false)} > - {course} - + + {course} + +
    • )) ) : ( -
    • No courses found
    • +
    • + No courses found +
    • )}
    @@ -558,93 +688,113 @@ export const Navbar: React.FC = () => { {QUICK_LINKS.map((link) => ( {link} ))}
-
- - Study Abroad +
+ + Study Abroad {/* Medical Dropdown */} -
-
- +
+
+ Medical - +
{/* Dropdown Content */} -
- -
- +
+ +
+
-
- Medical UG (MBBS) - Live Data +
+ Medical UG (MBBS) + + Live Data +
- -
- + +
+
-
- Medical PG - Live Data +
+ Medical PG + + Live Data +
- - Course Finder - New + + Course Finder + + New +
{/* Mobile Search */} -
-
- +
+ + setSearchTerm(e.target.value)} onFocus={() => setShowSuggestions(true)} onBlur={() => setTimeout(() => setShowSuggestions(false), 200)} - className="w-full pl-10 py-2 bg-gray-100 rounded-lg text-sm text-gray-900 outline-none" - placeholder="Search colleges..." + className='w-full pl-10 py-2 bg-gray-100 rounded-lg text-sm text-gray-900 outline-none' + placeholder='Search colleges...' /> {/* Mobile Suggestions Dropdown */} {showSuggestions && searchTerm && filteredSuggestions.length > 0 && ( -
-
Suggestions
+
+
+ Suggestions +
{filteredSuggestions.map((item) => (
handleSuggestionClick(item)} > -
-
- {item.type === 'exam' ? : } +
+
+ {item.type === 'exam' ? ( + + ) : ( + + )}
-
{item.name}
-
{item.location}
+
+ {item.name} +
+
{item.location}
- +
))}
@@ -662,7 +812,11 @@ export const Navbar: React.FC = () => { setIsAuthModalOpen(true); }} /> - setIsAuthModalOpen(false)} initialTab={authModalTab} /> + setIsAuthModalOpen(false)} + initialTab={authModalTab} + /> setIsCurrencyModalOpen(false)} diff --git a/src/components/college/CollegeDetailHeader.tsx b/src/components/college/CollegeDetailHeader.tsx new file mode 100644 index 0000000..979d94c --- /dev/null +++ b/src/components/college/CollegeDetailHeader.tsx @@ -0,0 +1,56 @@ +import { Badge } from '@/src/components/ui/badge'; +import { MapPin, ShieldCheck, Star } from 'lucide-react'; + +export const CollegeDetailHeader = () => { + return ( +
+ Cover +
+
+
+
+ Logo +
+
+
+ + Top Rated + + + Est. 1956 + +
+

+ All India Institute of Medical Sciences +

+
+ + New Delhi, India + + + AICTE Approved + + + 4.9 (1,200 Reviews) + +
+
+
+
+
+ ); +}; diff --git a/src/components/college/CollegeDetailTabs.tsx b/src/components/college/CollegeDetailTabs.tsx new file mode 100644 index 0000000..94d1c29 --- /dev/null +++ b/src/components/college/CollegeDetailTabs.tsx @@ -0,0 +1,31 @@ +import { Link, useParams } from '@tanstack/react-router'; + +export const CollegeDetailTabs = () => { + const { id } = useParams({ strict: false }) as { id: string }; + + const tabs = [ + { label: 'Overview', to: `/college/${id}` }, + { label: 'Courses & Fees', to: `/college/${id}/courses-fees` }, + { label: 'Placement', to: `/college/${id}/placement` }, + { label: 'Reviews', to: `/college/${id}/reviews` }, + ]; + + return ( +
+
+ {tabs.map((tab) => ( + + {tab.label} + + ))} +
+
+ ); +}; diff --git a/src/components/college/CollegeFilterSidebar.tsx b/src/components/college/CollegeFilterSidebar.tsx new file mode 100644 index 0000000..d894c0d --- /dev/null +++ b/src/components/college/CollegeFilterSidebar.tsx @@ -0,0 +1,124 @@ +import { Badge } from '@/src/components/ui/badge'; +import { Button } from '@/src/components/ui/button'; +import { Card } from '@/src/components/ui/card'; +import { Checkbox } from '@/src/components/ui/checkbox'; +import { Input } from '@/src/components/ui/input'; +import { Filter, Trash2 } from 'lucide-react'; +import type React from 'react'; +import { IndiaMap } from '../IndiaMap'; + +interface SearchParams { + city?: string | null; + state?: string | null; + course?: string | null; +} + +interface CollegeFilterSidebarProps { + searchParams: SearchParams; + activeState: string | null; + activeCourse: string | null; + clearFilter: (key: keyof SearchParams) => void; + handleStateClick: (state: string) => void; + handleStreamChange: (checked: boolean | string, type: string) => void; + navigate: (options: { search: any }) => void; +} + +export const CollegeFilterSidebar: React.FC = ({ + searchParams, + activeState, + activeCourse, + clearFilter, + handleStateClick, + handleStreamChange, + navigate, +}) => { + return ( + + ); +}; diff --git a/src/components/college/CollegeGridView.tsx b/src/components/college/CollegeGridView.tsx new file mode 100644 index 0000000..16006a3 --- /dev/null +++ b/src/components/college/CollegeGridView.tsx @@ -0,0 +1,173 @@ +import { Badge } from '@/src/components/ui/badge'; +import { Button } from '@/src/components/ui/button'; +import { Card, CardContent } from '@/src/components/ui/card'; +import { motion } from 'framer-motion'; +import { ArrowRight, ArrowRightLeft, CheckCircle, Filter, Heart, MapPin, Star } from 'lucide-react'; +import type React from 'react'; +import type { College } from '../../services/collegeService'; + +interface CollegeGridViewProps { + filteredColleges: College[]; + isLoading: boolean; + hasMore: boolean; + isInCompare: (id: string) => boolean; + handleCompareClick: (college: College) => void; + clearAllFilters: () => void; +} + +export const CollegeGridView: React.FC = ({ + filteredColleges, + isLoading, + hasMore, + isInCompare, + handleCompareClick, + clearAllFilters, +}) => { + return ( +
+
+ {filteredColleges.length > 0 ? ( + filteredColleges.map((college) => ( + + + {/* Image */} +
+ {college.name} +
+ +
+ {college.tags.map((tag) => ( + + {tag} + + ))} +
+
+ + {/* Content */} + +
+
+

+ {college.name} +

+ + {college.rating} + +
+ +
+ + {college.location} + + + {college.approvedBy} + +
+ +
+
+

+ Total Fees +

+

{college.fees}

+
+
+

+ Avg Package +

+

₹12.50 LPA

+
+
+
+ +
+ + +
+
+ + + )) + ) : ( +
+ +
+ +
+

No Colleges Found

+

+ We couldn't find any colleges matching your current filters. Try adjusting your + search criteria. +

+ +
+
+ )} +
+ + {/* Pagination Loading / End Indicator */} + {isLoading && ( +
+
+ Loading more colleges... +
+ )} + {!hasMore && filteredColleges.length > 0 && ( +
+ You've reached the end of the list. +
+ )} +
+ ); +}; diff --git a/src/components/college/CollegeHeaderFilter.tsx b/src/components/college/CollegeHeaderFilter.tsx new file mode 100644 index 0000000..27ad3f5 --- /dev/null +++ b/src/components/college/CollegeHeaderFilter.tsx @@ -0,0 +1,160 @@ +import { Button } from '@/src/components/ui/button'; +import { LayoutGrid, List, Table } from 'lucide-react'; +import type React from 'react'; + +type ViewMode = 'list' | 'grid' | 'table'; + +interface CollegeHeaderFilterProps { + view: ViewMode; + setView: (view: ViewMode) => void; +} + +export const CollegeHeaderFilter: React.FC = ({ view, setView }) => { + const streams = [ + { name: 'Management', count: 7760 }, + { name: 'Science', count: 6470 }, + { name: 'Engineering', count: 6217 }, + { name: 'Arts', count: 5804 }, + { name: 'Computer Applications', count: 5162 }, + { name: 'Commerce', count: 5103 }, + { name: 'Education', count: 3031 }, + { name: 'Medical', count: 2489 }, + ]; + + const courses = [ + { name: 'MBA/PGDM', count: 5293 }, + { name: 'B.Sc', count: 5001 }, + { name: 'B.Com', count: 4884 }, + { name: 'BA', count: 4641 }, + { name: 'BE/B.Tech', count: 4499 }, + { name: 'BBA/BMS', count: 4415 }, + { name: 'M.Sc', count: 3754 }, + { name: 'BCA', count: 3741 }, + { name: 'MA', count: 3116 }, + { name: 'ME/M.Tech', count: 2925 }, + ]; + + const states = [ + { name: 'Maharashtra', count: 2968 }, + { name: 'Tamil Nadu', count: 2464 }, + ]; + + const Pill = ({ text, count }: { text: string; count: number }) => ( + + ); + + return ( +
+ {/* Row 1: Streams */} +
+ {streams.map((s) => ( + + ))} +
+ + {/* Row 2: Courses */} +
+ {courses.map((c) => ( + + ))} +
+ + {/* Row 3: States & Sorting */} +
+
+ {states.map((s) => ( + + ))} + +
+ +
+ Sort By + + + + + +
+ + +
+ ) : ( + +
+ +
+

No Colleges Found

+

+ We couldn't find any colleges matching your current filters. Try adjusting your search + criteria. +

+ +
+ )} + + {/* Pagination Loading / End Indicator */} + {isLoading && ( +
+
+ Loading more colleges... +
+ )} + {!hasMore && filteredColleges.length > 0 && ( +
+ You've reached the end of the list. +
+ )} +
+ ); +}; diff --git a/src/components/college/tabs/CoursesFeesTab.tsx b/src/components/college/tabs/CoursesFeesTab.tsx new file mode 100644 index 0000000..40ffca7 --- /dev/null +++ b/src/components/college/tabs/CoursesFeesTab.tsx @@ -0,0 +1,141 @@ +import { Badge } from '@/src/components/ui/badge'; +import { Button } from '@/src/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/src/components/ui/card'; +import { ChevronRight, Download } from 'lucide-react'; + +export const CoursesFeesTab = () => { + const courses = [ + { + name: 'B.Sc (Nursing)', + fees: '₹3,165', + duration: '4 Years', + type: 'Degree', + mode: 'On Campus', + qualification: 'Graduation', + reviews: '4.7/5 (23)', + eligibility: '10+2 with 55% + AIIMS Entrance', + applicationDate: '12 Apr - 12 May 2024', + }, + { + name: 'MBBS', + fees: '₹1,628', + duration: '5.5 Years', + type: 'Degree', + mode: 'On Campus', + qualification: 'Graduation', + reviews: '4.8/5 (92)', + eligibility: '10+2 with 60% + NEET', + applicationDate: '9 Feb - 9 Mar 2024', + }, + { + name: 'M.D General Medicine', + fees: '₹2,106', + duration: '3 Years', + type: 'Degree', + mode: 'On Campus', + qualification: 'Post Graduation', + reviews: '4.9/5 (15)', + eligibility: 'MBBS + INI CET', + applicationDate: '15 Sep - 15 Oct 2024', + }, + ]; + + return ( +
+ + + + AIIMS, New Delhi Courses & Fees 2024 + +
+ {['All', 'Medical', 'Science', 'Paramedical', 'Dental'].map((stream, i) => ( + + {stream} + + ))} +
+
+ +
+ {courses.map((course, idx) => ( +
+
+
+

+ {course.name} +

+
+
+

+ First Year Fees +

+

{course.fees}

+
+
+

+ Duration +

+

{course.duration}

+
+
+

+ Eligibility +

+

{course.eligibility}

+
+
+ +
+
+ + + Application Date:{' '} + {course.applicationDate} + +
+
+
+ +
+ + +
+
+
+ ))} +
+
+
+ + + +
+

+ Want to see full details of all {courses.length} courses? +

+

+ Download the complete brochure for AIIMS, New Delhi. +

+
+ +
+
+
+ ); +}; diff --git a/src/components/college/tabs/OverviewTab.tsx b/src/components/college/tabs/OverviewTab.tsx new file mode 100644 index 0000000..8fc32c0 --- /dev/null +++ b/src/components/college/tabs/OverviewTab.tsx @@ -0,0 +1,422 @@ +import { Badge } from '@/src/components/ui/badge'; +import { Button } from '@/src/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/src/components/ui/card'; +import { Link, useParams } from '@tanstack/react-router'; +import { + Building2, + CheckCircle2, + ChevronDown, + ChevronRight, + ChevronUp, + Download, + GraduationCap, + MapPin, + Star, +} from 'lucide-react'; +import { useState } from 'react'; + +export const OverviewTab = () => { + const { id } = useParams({ from: '/college/$id' }); + const [isAboutExpanded, setIsAboutExpanded] = useState(false); + const [isAdmissionsExpanded, setIsAdmissionsExpanded] = useState(false); + const [expandedFaq, setExpandedFaq] = useState(0); + + return ( +
+ {/* About Section */} + + + About the Institute + + +

+ All India Institute of Medical Sciences (AIIMS) New Delhi is globally recognized as the + premier medical institute in India. Established in 1956, it serves as a nucleus for + nurturing excellence in all aspects of health care. The institute offers comprehensive + facilities for teaching, research, and patient care. + {isAboutExpanded && ( + + {' '} + AIIMS is an Institution of National Importance and is ranked #1 in India by NIRF. It + offers various undergraduate, postgraduate, and super-specialty medical courses. + + )} + +

+
+ + ✓ AICTE Approved + + + ✓ UGC Recognized + + + Est. 1956 + + + Autonomous University + +
+
+
+ + {/* Fees & Eligibility Section */} + + + + AIIMS, New Delhi Fees & Eligibility + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Course + + Fees + + Eligibility + + Action +
B.Sc (Nursing)₹3,165 (1st Yr Fees)10+2 with 55% + AIIMS Entrance + +
MBBS₹1,628 (1st Yr Fees)10+2 with 60% + NEET + +
M.D₹2,106 (1st Yr Fees)MBBS + INI CET + +
+
+
+ + + +
+
+ + {/* Placements Section */} + + + + AIIMS, New Delhi Placements 2024 + + + +
+
+

₹1.05 Cr

+

+ Highest Package +

+
+
+

₹24 LPA

+

+ Average Package +

+
+
+

100%

+

+ Placement Rate +

+
+
+

Top

+

+ Hospital Networks +

+
+
+
+ + + +
+
+
+ + {/* Cutoff Section */} + + + + AIIMS, New Delhi Cutoff 2024 + + +
+ + + + + + + + + + + + + + + + + + + + +
+ Course + + Category + + Closing Rank (2024) +
MBBSGeneral57
MBBSOBC255
+
+
+ + {/* Admissions Alert Section */} + + +
+
+ +
+
+

+ AIIMS, New Delhi Admissions 2024 +

+

+ Admission to AIIMS New Delhi for the academic year 2024 is ongoing. The institute + conducts computerized entrance examinations for undergraduate and postgraduate + courses. + {isAdmissionsExpanded && ( + + {' '} + INI CET 2024 will be held on May 19, 2024 for admission to MD/MS/MCh/DM courses. + For B.Sc Nursing, the exam is scheduled for June 8, 2024. + + )} + +

+
+
+
+
+ + {/* Campus & Facilities Section */} + + + + AIIMS New Delhi Campus & Facilities + + + +
+ {[ + { + label: 'Campus Area', + val: '115 Acres', + icon: , + }, + { + label: 'Hostels', + val: '14 Blocks', + icon: , + }, + { + label: 'Library', + val: '1.5L+ Books', + icon: , + }, + { + label: 'Hospital Beds', + val: '2,500+', + icon: , + }, + ].map((item, i) => ( +
+
{item.icon}
+

{item.val}

+

+ {item.label} +

+
+ ))} +
+

+ The AIIMS campus is spread over 115 acres in Ansari Nagar, New Delhi. It houses the + teaching hospital, medical and nursing colleges, residential quarters, and research + facilities. The Dr. B.B. Dikshit Library is one of the largest medical libraries in + India. +

+ +
+
+ + {/* Reviews snippet */} + + + Latest Reviews +
+ + 4.9 / 5 +
+
+ +
+ {[1, 2].map((i) => ( +
+
+
+
+ {i === 1 ? 'A' : 'R'} +
+
+

+ {i === 1 ? 'Aditi Sharma' : 'Rahul Verma'} +

+

MBBS Student • Batch of 2026

+
+
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + ))} +
+
+

+ {i === 1 + ? 'The academics here are unparalleled. The faculty includes top doctors of the country. The clinical exposure you get here is something you will not find in any other medical college.' + : 'Best medical infrastructure in India. Library is huge and open 24/7. Hostels are decent with good mess food. The peer group is extremely competitive but helpful.'} +

+
+ ))} +
+
+ + + +
+
+
+ + {/* FAQs Section */} + + + AIIMS New Delhi FAQs + + +
+ {[ + { + q: 'What is the highest package offered at AIIMS New Delhi?', + a: 'The highest package offered during AIIMS New Delhi placements is usually around ₹1.05 Crores per annum, typically offered by international hospital networks.', + }, + { + q: 'Is there a hostel facility available?', + a: 'Yes, AIIMS provides comprehensive hostel facilities for both male and female students, with 14 hostel blocks available on campus equipped with modern amenities.', + }, + { + q: 'What entrance exam is required for MBBS?', + a: 'For MBBS admission at AIIMS New Delhi, candidates must qualify for the NEET-UG examination with high percentiles, as the cutoff is extremely competitive.', + }, + ].map((faq, i) => ( +
+ + {expandedFaq === i && ( +
+ {faq.a} +
+ )} +
+ ))} +
+
+
+
+ ); +}; diff --git a/src/components/college/tabs/PlacementTab.tsx b/src/components/college/tabs/PlacementTab.tsx new file mode 100644 index 0000000..1e27880 --- /dev/null +++ b/src/components/college/tabs/PlacementTab.tsx @@ -0,0 +1,199 @@ +import { Badge } from '@/src/components/ui/badge'; +import { Card, CardContent, CardHeader, CardTitle } from '@/src/components/ui/card'; +import { Building, GraduationCap, TrendingUp, Users } from 'lucide-react'; +import { + Bar, + BarChart, + CartesianGrid, + Legend, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; + +const PLACEMENT_DATA = [ + { year: '2020', avg: 15.5, max: 38 }, + { year: '2021', avg: 18.2, max: 45 }, + { year: '2022', avg: 22.5, max: 80 }, + { year: '2023', avg: 24.8, max: 105 }, +]; + +export const PlacementTab = () => { + return ( +
+ + + + AIIMS, New Delhi Placements 2024 Highlights + + + +
+
+
+ +
+

₹1.05 Cr

+

+ Highest Package +

+
+ +
+
+ +
+

₹24 LPA

+

+ Average Package +

+
+ +
+
+ +
+

100%

+

+ Placement Rate +

+
+ +
+
+ +
+

150+

+

+ Top Recruiters +

+
+
+ +

Placement Trends (2020 - 2023)

+
+ + + + + `₹${value}L`} + /> + [`₹${value} LPA`, '']} + /> + + + + + +
+
+
+ + + + Top Recruiters 2024 + + +
+ {/* Placeholder for real logos */} + {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((i) => ( +
+ Logo {i} +
+ ))} +
+
+
+ + + + Sector-wise Placements + +
+ + + + + + + + + + + + + + + + + + + + + +
+ Sector + + Percentage of Students Placed +
Hospitals & Healthcare +
+
+
+
+ 65% +
+
Pharmaceutical & Research +
+
+
+
+ 20% +
+
Medical Tech & Others +
+
+
+
+ 15% +
+
+
+
+
+ ); +}; diff --git a/src/components/college/tabs/ReviewsTab.tsx b/src/components/college/tabs/ReviewsTab.tsx new file mode 100644 index 0000000..d5d47c6 --- /dev/null +++ b/src/components/college/tabs/ReviewsTab.tsx @@ -0,0 +1,216 @@ +import { Badge } from '@/src/components/ui/badge'; +import { Button } from '@/src/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/src/components/ui/card'; +import { ChevronDown, Filter, PenTool, Star, ThumbsDown, ThumbsUp } from 'lucide-react'; + +export const ReviewsTab = () => { + const reviews = [ + { + id: 1, + author: 'Aditi Sharma', + course: 'MBBS - Bachelor of Medicine & Surgery', + batch: 'Batch of 2026', + rating: 5.0, + date: 'Oct 12, 2023', + title: 'The pinnacle of medical education in India', + content: + 'The academics here are unparalleled. The faculty includes top doctors of the country. The clinical exposure you get here is something you will not find in any other medical college. Hostels are decent, and the campus life is vibrant despite the rigorous curriculum.', + likes: 45, + dislikes: 2, + }, + { + id: 2, + author: 'Rahul Verma', + course: 'M.D General Medicine', + batch: 'Batch of 2024', + rating: 4.8, + date: 'Sep 05, 2023', + title: 'Incredible clinical exposure but highly stressful', + content: + 'Best medical infrastructure in India. Library is huge and open 24/7. Hostels are decent with good mess food. The peer group is extremely competitive but helpful. The workload can be overwhelming, but it prepares you for anything.', + likes: 32, + dislikes: 1, + }, + { + id: 3, + author: 'Sneha Patel', + course: 'B.Sc (Nursing)', + batch: 'Batch of 2025', + rating: 4.5, + date: 'Aug 22, 2023', + title: 'Great faculty, strict schedule', + content: + 'The nursing program is very comprehensive. Practical classes are conducted with the utmost seriousness. The only downside is that the schedule is very strict and leaves little room for extracurricular activities.', + likes: 18, + dislikes: 4, + }, + ]; + + return ( +
+ + + + AIIMS, New Delhi Reviews + + + + +
+ {/* Rating Summary Left */} +
+
4.9
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + ))} +
+

Based on 142 Reviews

+
+ + {/* Rating Distribution Middle */} +
+ {[ + { stars: 5, pct: 85 }, + { stars: 4, pct: 10 }, + { stars: 3, pct: 3 }, + { stars: 2, pct: 1 }, + { stars: 1, pct: 1 }, + ].map((row) => ( +
+ + {row.stars} + +
+
+
+ {row.pct}% +
+ ))} +
+ + {/* Category Scores Right */} +
+

Category Ratings

+ {[ + { label: 'Academic', val: '8.9' }, + { label: 'Accommodation', val: '8.2' }, + { label: 'Faculty', val: '9.1' }, + { label: 'Infrastructure', val: '8.5' }, + { label: 'Placement', val: '8.8' }, + { label: 'Social Life', val: '8.0' }, + ].map((item, idx) => ( +
+ {item.label} + + {item.val} + +
+ ))} +
+
+ + + + {/* Filters and Search - placeholder layout */} +
+
+ + Filter By Course + + + Year of Passing + +
+
+ Sort By: + +
+
+ + {/* Review List */} +
+ {reviews.map((review) => ( + + +
+
+
+ {review.author.charAt(0)} +
+
+

{review.author}

+

+ {review.course} • {review.batch} +

+
+
+
+
+ + {review.rating.toFixed(1)} + + +
+ Posted on {review.date} +
+
+ +
+
"{review.title}"
+

{review.content}

+
+ +
+ Was this review helpful? + + +
+
+
+ ))} +
+ +
+ +
+
+ ); +}; diff --git a/src/context/CourseFilterContext.tsx b/src/context/CourseFilterContext.tsx index 1b727f9..d40ee6b 100644 --- a/src/context/CourseFilterContext.tsx +++ b/src/context/CourseFilterContext.tsx @@ -1,39 +1,39 @@ -import React, { createContext, useContext, useState, ReactNode } from 'react'; +import { type FC, type ReactNode, createContext, useContext, useState } from 'react'; export type CourseGoal = - | 'All' - | 'BE/B.Tech' - | 'MBA/PGDM' - | 'MBBS' - | 'ME/M.Tech' - | 'B.Sc' - | 'BA' - | 'B.Com' - | 'BCA' - | 'BBA/BMS' - | 'B.Sc (I)'; + | 'All' + | 'BE/B.Tech' + | 'MBA/PGDM' + | 'MBBS' + | 'ME/M.Tech' + | 'B.Sc' + | 'BA' + | 'B.Com' + | 'BCA' + | 'BBA/BMS' + | 'B.Sc (I)'; interface CourseFilterContextValue { - selectedFilter: CourseGoal; - setSelectedFilter: (filter: CourseGoal) => void; + selectedFilter: CourseGoal; + setSelectedFilter: (filter: CourseGoal) => void; } const CourseFilterContext = createContext(undefined); -export const CourseFilterProvider: React.FC<{ children: ReactNode }> = ({ children }) => { - const [selectedFilter, setSelectedFilter] = useState('All'); +export const CourseFilterProvider: FC<{ children: ReactNode }> = ({ children }) => { + const [selectedFilter, setSelectedFilter] = useState('All'); - return ( - - {children} - - ); + return ( + + {children} + + ); }; export const useCourseFilter = () => { - const context = useContext(CourseFilterContext); - if (!context) { - throw new Error('useCourseFilter must be used within CourseFilterProvider'); - } - return context; + const context = useContext(CourseFilterContext); + if (!context) { + throw new Error('useCourseFilter must be used within CourseFilterProvider'); + } + return context; }; diff --git a/src/index.css b/src/index.css index 34e171c..6318541 100644 --- a/src/index.css +++ b/src/index.css @@ -109,6 +109,82 @@ } } +@layer components { + /* Base Sprite Classes */ + .icon-sprite-1, .icon-sprite-2 { + display: inline-flex; + align-items: center; + justify-content: center; + position: relative; + /* Default bounding box for layout */ + width: 16px; + height: 16px; + } + + .icon-sprite-1::before, .icon-sprite-2::before { + content: ''; + display: block; + position: absolute; + background-repeat: no-repeat; + transform-origin: center; + background-position: var(--sprite-x, 0px) var(--sprite-y, 0px); + } + + /* listing_spirit.svg configuration (Grid spacing ~60px, height ~44px) */ + .icon-sprite-1::before { + background-image: url('/src/assets/listing_spirit.svg'); + min-width: 44px; + min-height: 44px; + transform: scale(var(--sprite-scale, 0.40)); + } + + /* listing_spirit_2.svg configuration (Grid spacing ~30px, height ~60px) */ + .icon-sprite-2::before { + background-image: url('/src/assets/listing_spirit_2.svg'); + min-width: 60px; + min-height: 60px; + transform: scale(var(--sprite-scale, 0.35)); + } + + /* --- Specific listing_spirit.svg Icon Instances --- */ + .icon-gallery { --sprite-x: -20px; --sprite-y: -4px; --sprite-scale: 0.4; filter: contrast(1.2); } + .icon-video { --sprite-x: -60px; --sprite-y: -4px; --sprite-scale: 0.45; } + + /* Button Strip Icons */ + .icon-reviews { --sprite-x: -240px; --sprite-y: -4px; } + .icon-down { --sprite-x: -360px; --sprite-y: -4px; --sprite-scale: 0.40; filter: grayscale(100%); } + .icon-up { --sprite-x: -48px; --sprite-y: -4px; --sprite-scale: 0.40; filter: grayscale(100%); } + .icon-courses { --sprite-x: -300px; --sprite-y: -4px; --sprite-scale: 0.45; } + .icon-placement { --sprite-x: -1200px; --sprite-y: -2px; --sprite-scale: 0.40; filter: grayscale(100%); } + + /* Action Button Icons */ + .icon-apply { --sprite-x: -600px; --sprite-y: -4px; --sprite-scale: 0.45; filter: brightness(0) invert(1); } + .icon-brochure { --sprite-x: -540px; --sprite-y: -4px; --sprite-scale: 0.45; filter: brightness(0) sepia(1) hue-rotate(360deg) saturate(5000%); } + .icon-compare-add { --sprite-x: -1260px; --sprite-y: -4px; --sprite-scale: 0.5; } + .icon-compare-added { filter: brightness(0) invert(1); } + + /* Info Strip Icons */ + .icon-rank-medal { --sprite-x: -180px; --sprite-y: -2px; --sprite-scale: 0.45; width: 20px; height: 20px; } + .icon-rating-shield { --sprite-x: -420px; --sprite-y: -4px; --sprite-scale: 0.45; width: 14px; height: 18px; } + .clg-reivew-ico { --sprite-x: -110px; --sprite-y: -4px; --sprite-scale: 0.40; filter: grayscale(100%); } + /* --- Specific listing_spirit_2.svg Icon Instances --- */ + .icon-facility { + width: 20px; /* Layout width for facilities */ + height: 20px; + --sprite-y: -8px; + --sprite-scale: 0.35; + } + + .icon-ribbon { + width: 14px; + height: 14px; + --sprite-x: 0px; + --sprite-y: -8px; + --sprite-scale: 0.35; + filter: brightness(0) saturate(100%) invert(43%) sepia(87%) saturate(1915%) hue-rotate(15deg) brightness(101%) contrast(101%); /* Orange tint match for the ribbon */ + } +} + @layer utilities { .progress-shimmer { position: relative; diff --git a/src/index.tsx b/src/index.tsx index 398b33f..fcfd401 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,14 +3,18 @@ import { createRoot } from 'react-dom/client'; import './index.css'; import App from './App'; +// Ensure the root element exists const rootElement = document.getElementById('root'); if (!rootElement) { - throw new Error("Could not find root element to mount to"); + throw new Error('Failed to find the root element'); } -const root = createRoot(rootElement); -root.render( - - - -); +// Create root and render the app +if (!rootElement.innerHTML) { + const root = createRoot(rootElement); + root.render( + + + + ); +} diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts new file mode 100644 index 0000000..2b6c1bc --- /dev/null +++ b/src/lib/supabase.ts @@ -0,0 +1,15 @@ +import { createClient } from '@supabase/supabase-js'; + +const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; +const supabaseAnonKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY; + +if (!supabaseUrl || !supabaseAnonKey) { + console.warn( + 'Missing Supabase credentials. Ensure VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY are set.' + ); +} + +export const supabase = createClient( + supabaseUrl || 'https://placeholder.supabase.co', + supabaseAnonKey || 'placeholder_key' +); diff --git a/src/pages/CollegeListing.tsx b/src/pages/CollegeListing.tsx index 6a180e3..12fe2da 100644 --- a/src/pages/CollegeListing.tsx +++ b/src/pages/CollegeListing.tsx @@ -1,28 +1,36 @@ +import { Badge } from '@/src/components/ui/badge'; +import { Button } from '@/src/components/ui/button'; +import { Card, CardContent } from '@/src/components/ui/card'; +import { Checkbox } from '@/src/components/ui/checkbox'; +import { Input } from '@/src/components/ui/input'; import { Link, useNavigate, useSearch } from '@tanstack/react-router'; import { motion } from 'framer-motion'; -import { ArrowRight, ArrowRightLeft, CheckCircle, Filter, Heart, MapPin, Star, Trash2, X } from 'lucide-react'; +import { + ArrowRight, + ArrowRightLeft, + CheckCircle, + Filter, + Heart, + LayoutGrid, + List, + MapPin, + Star, + Table, + Trash2, + X, +} from 'lucide-react'; import type React from 'react'; import { useEffect, useState } from 'react'; -import { Button } from '@/src/components/ui/button'; -import { Input } from '@/src/components/ui/input'; -import { Card, CardContent } from '@/src/components/ui/card'; -import { Badge } from '@/src/components/ui/badge'; -import { Checkbox } from '@/src/components/ui/checkbox'; -import { IndiaMap } from '../components/IndiaMap'; +import { CollegeFilterSidebar } from '../components/college/CollegeFilterSidebar'; +import { CollegeGridView } from '../components/college/CollegeGridView'; +import { CollegeHeaderFilter } from '../components/college/CollegeHeaderFilter'; +import { CollegeListView } from '../components/college/CollegeListView'; +import { CollegeTableView } from '../components/college/CollegeTableView'; import { useCompare } from '../context/CompareContext'; -const MOCK_COLLEGES = Array(8).fill(null).map((_, i) => ({ - id: `c${i}`, - name: i % 2 === 0 ? 'All India Institute of Medical Sciences (AIIMS)' : 'Indian Institute of Technology (IIT)', - location: i % 3 === 0 ? 'New Delhi, Delhi NCR' : (i % 3 === 1 ? 'Mumbai, Maharashtra' : 'Bangalore, Karnataka'), - state: i % 3 === 0 ? 'Delhi' : (i % 3 === 1 ? 'Maharashtra' : 'Karnataka'), - rating: (4 + Math.random()).toFixed(1), - reviews: Math.floor(Math.random() * 1000), - fees: i % 2 === 0 ? '₹1,628 - ₹5,000' : '₹2.5L - ₹4.5L', - img: `https://picsum.photos/400/300?random=${i + 20}`, - tags: i % 2 === 0 ? ['Public', 'Medical', 'Co-Ed'] : ['Public', 'Engineering', 'Autonomous'], - approvedBy: i % 2 === 0 ? 'NMC' : 'AICTE', -})); +import { type College, getColleges } from '../services/collegeService'; + +const INITIAL_COLLEGES: College[] = []; type SearchParams = { city?: string; @@ -33,8 +41,12 @@ type SearchParams = { export const CollegeListing: React.FC = () => { const navigate = useNavigate(); const searchParams = useSearch({ strict: false }) as SearchParams; - const [view, setView] = useState<'list' | 'grid'>('list'); - const [filteredColleges, setFilteredColleges] = useState(MOCK_COLLEGES); + const [view, setView] = useState<'list' | 'grid' | 'table'>('list'); + const [allColleges, setAllColleges] = useState(INITIAL_COLLEGES); + const [filteredColleges, setFilteredColleges] = useState(INITIAL_COLLEGES); + const [page, setPage] = useState(1); + const [hasMore, setHasMore] = useState(true); + const [isLoading, setIsLoading] = useState(false); const { addToCompare, removeFromCompare, isInCompare } = useCompare(); // Extract filters from URL @@ -42,25 +54,67 @@ export const CollegeListing: React.FC = () => { const activeState = searchParams.state || null; const activeCourse = searchParams.course; + const loadMore = async () => { + if (isLoading || !hasMore) return; + setIsLoading(true); + const nextPage = page + 1; + const data = await getColleges(nextPage, 10, { + state: activeState, + city: activeCity, + course: activeCourse, + }); + console.log(`Loaded pagination page ${nextPage} data:`, data); + setAllColleges((prev) => { + const existingIds = new Set(prev.map((c) => c.id)); + const newColleges = data.filter((c) => !existingIds.has(c.id)); + const updated = [...prev, ...newColleges]; + setFilteredColleges(updated); + return updated; + }); + setPage(nextPage); + if (data.length < 10) setHasMore(false); + setIsLoading(false); + }; + + // Fetch initial data whenever filters change useEffect(() => { - let filtered = MOCK_COLLEGES; + const fetchInitialColleges = async () => { + // Clear data instantly to show fresh loading state + setAllColleges([]); + setFilteredColleges([]); + setIsLoading(true); - if (activeState) { - // Filter by state match or location string match - filtered = filtered.filter(c => - c.state.includes(activeState) || - c.location.includes(activeState) || - (activeState === 'Delhi NCR' && c.state === 'Delhi') - ); - } - if (activeCity) { - filtered = filtered.filter(c => c.location.includes(activeCity)); - } + const data = await getColleges(1, 10, { + state: activeState, + city: activeCity, + course: activeCourse, + }); + console.log('Loaded initial page 1 data with filters:', data); + setAllColleges(data); + setFilteredColleges(data); + setPage(1); + setHasMore(data.length === 10); + setIsLoading(false); + }; + fetchInitialColleges(); + }, [activeState, activeCity, activeCourse]); - // In a real app, we'd filter by course type too, but mock data is limited. + // Infinite Scroll Listener + useEffect(() => { + const handleScroll = () => { + if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 500) { + if (!isLoading && hasMore) { + loadMore(); + } + } + }; + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, [isLoading, hasMore, page]); - setFilteredColleges(filtered); - }, [activeCity, activeState, activeCourse]); + // Cleaned up client-side filtering because we're relying on the server to handle queries + // filteredColleges state is now basically identical to allColleges, updated locally with loadMore + // and completely reset when filters change in the useEffect above. const clearFilter = (key: keyof SearchParams) => { const { [key]: _, ...newSearch } = searchParams; @@ -76,7 +130,16 @@ export const CollegeListing: React.FC = () => { } }; - const handleCompareClick = (college: typeof MOCK_COLLEGES[0]) => { + const handleStreamChange = (checked: boolean | string, type: string) => { + if (checked) { + navigate({ search: { ...searchParams, course: type } as any }); + } else if (activeCourse === type) { + const { course: _, ...newSearch } = searchParams; + navigate({ search: newSearch as any }); + } + }; + + const handleCompareClick = (college: College) => { if (isInCompare(college.id)) { removeFromCompare(college.id); } else { @@ -85,219 +148,142 @@ export const CollegeListing: React.FC = () => { name: college.name, img: college.img, location: college.location, - rating: college.rating + rating: college.rating, }); } }; return ( -
-
+
+
{/* Breadcrumb & Header */} -
-
Home > Colleges > {activeCourse || 'All Courses'}
-

+
+
+ Home > Colleges > {activeCourse || 'All Courses'} +
+

{activeCourse ? `Top ${activeCourse} Colleges` : 'Top Colleges in India'} {activeState && ` in ${activeState}`} {activeCity && ` in ${activeCity}`}

-

Found {filteredColleges.length} colleges based on your preferences

+

+ Found {filteredColleges.length} colleges based on your preferences +

{/* Active Filters Chips */} {(activeCity || activeState || activeCourse) && ( -
+
{activeCourse && ( - - {activeCourse} + + {activeCourse}{' '} + )} {activeState && ( - - {activeState} + + {activeState}{' '} + )} {activeCity && ( - - {activeCity} + + {activeCity}{' '} + )} - +
)}
-
- {/* Sidebar Filters */} - - - {/* Main Content */} -
- {/* Sort & View Toggle */} - -
- - - -
-
- Showing {filteredColleges.length} colleges -
-
- - {/* College Cards */} -
- {filteredColleges.length > 0 ? ( - filteredColleges.map((college) => ( - - - {/* Image */} -
- {college.name} -
- -
- {college.tags.map(tag => ( - {tag} - ))} -
-
- - {/* Content */} - -
-
-
-

- {college.name} -

-
- {college.location} - | - - {college.approvedBy} Approved - -
-
-
- - {college.rating} - - {college.reviews} reviews -
-
- -
-
-

Total Fees

-

{college.fees}

-
-
-

Avg Package

-

₹12.50 LPA

-
-
-
+
+ +
+ {/* Sort & Quick Filter Header */} + -
- - -
- - - - )) - ) : ( - -
- -
-

No Colleges Found

-

We couldn't find any colleges matching your current filters. Try adjusting your search criteria.

- -
- )} -
+ {/* View Component Rendering */} + {view === 'list' && ( + navigate({ search: {} as any })} + /> + )} + {view === 'grid' && ( + navigate({ search: {} as any })} + /> + )} + {view === 'table' && ( + navigate({ search: {} as any })} + /> + )}

); -}; \ No newline at end of file +}; diff --git a/src/pages/CourseFinder.tsx b/src/pages/CourseFinder.tsx index 1d7ca02..848f482 100644 --- a/src/pages/CourseFinder.tsx +++ b/src/pages/CourseFinder.tsx @@ -1,12 +1,22 @@ - -import { Link, useSearch } from '@tanstack/react-router'; -import { ArrowRight, BookOpen, ChevronDown, ChevronRight, ChevronUp, Clock, Filter, GraduationCap, MapPin, Search } from 'lucide-react'; -import type React from 'react'; -import { useCallback, useEffect, useRef, useState } from 'react'; import { Button } from '@/src/components/ui/button'; -import { Input } from '@/src/components/ui/input'; import { Card, CardContent } from '@/src/components/ui/card'; import { Checkbox } from '@/src/components/ui/checkbox'; +import { Input } from '@/src/components/ui/input'; +import { Link, useSearch } from '@tanstack/react-router'; +import { + ArrowRight, + BookOpen, + ChevronDown, + ChevronRight, + ChevronUp, + Clock, + Filter, + GraduationCap, + MapPin, + Search, +} from 'lucide-react'; +import type React from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; // --- Types --- interface Course { @@ -26,13 +36,75 @@ interface Course { // --- Mock Data Generator --- const COURSES_DB: Partial[] = [ - { title: "Bachelor of Commerce", shortCode: "[B.Com]", description: "BCom is a 3-year undergraduate course for students who have cleared 12th standard with a major in Commerce. The full form of BCom is Bachelor of Commerce. BCom Admissions are based on merit as well as entrance exams such as CUET, PU CET, NPAT, etc. BCom offers diverse Career options in the fields of", jobRoles: ["Chartered Accountant", "Accounting Analyst", "Equity Analyst", "Financial Analyst"] }, - { title: "Bachelor of Computer Applications", shortCode: "[BCA]", description: "BCA – Bachelor of Computer Applications – is a 3-year long degree that can be pursued after completion of 10+2. BCA is available in Regular, Distance, and online format. A minimum of 50% marks are required for admission to BCA. A BCA degree is pursued by students who wish to get Jobs in the IT & Tech Industry", jobRoles: ["Software Developer", "Technical Analyst", "System Engineer", "Web Developer"] }, - { title: "Bachelor of Business Administration", shortCode: "[BBA]", description: "The Bachelor of Business Administration (BBA) course is a 3-year undergraduate program ideal for students exploring careers in business management. Students can pursue a general BBA or choose specialized subjects such as BBA in Finance, BBA in Marketing, BBA in International Business, BBA in Human Res", jobRoles: ["Marketing Executive", "Business Analyst", "Finance/Banking", "Risk Control Analyst"] }, - { title: "Master of Business Administration", shortCode: "[MBA]", description: "MBA (Master of Business Administration) is a 2-year postgraduate program that teaches students how to manage businesses, lead teams, and make important decisions. During an MBA, students learn about areas like Finance, Marketing, Human Resources, Operations, and Leadership.", jobRoles: ["Human Resources Manager", "Operations Manager", "Marketing Manager", "Relationship Manager"] }, - { title: "Bachelor of Technology", shortCode: "[B.Tech] (Computer Science)", description: "BTech CSE is a 4 year UG course that studies practical and theoretical knowledge of computer hardware and software. This course lays emphasis on the basics of computer programming and networking while also comprising a plethora of topics. The admission process for the B.tech CSE is to clear entrance exams", jobRoles: ["Project Coordinator", "Information Technology", "Applications Engineer", "Solutions Engineer"] }, - { title: "Master of Computer Applications", shortCode: "[MCA]", description: "MCA (Master of Computer Applications) is a master's level course focusing on computer applications and software development. It will provide you with comprehensive knowledge and skills in topics like programming languages, data structures, DBMS, emerging technologies and more in a 3-year course", jobRoles: ["Software Engineer", "Software Developer", "Data Engineer", "Java Programmer"] }, - { title: "Bachelor of Education", shortCode: "[B.Ed]", description: "The Bachelor of Education (B.Ed.) degree is a 2-year professional program for individuals aspiring to be teachers in schools, colleges, and other academic institutions. B Ed course is crucial for those who want to pursue a career in teaching and is a common qualification for teaching positions.", jobRoles: ["Assistant Professor", "Higher Education", "Primary School Teacher", "Secondary School Teacher"] }, + { + title: 'Bachelor of Commerce', + shortCode: '[B.Com]', + description: + 'BCom is a 3-year undergraduate course for students who have cleared 12th standard with a major in Commerce. The full form of BCom is Bachelor of Commerce. BCom Admissions are based on merit as well as entrance exams such as CUET, PU CET, NPAT, etc. BCom offers diverse Career options in the fields of', + jobRoles: ['Chartered Accountant', 'Accounting Analyst', 'Equity Analyst', 'Financial Analyst'], + }, + { + title: 'Bachelor of Computer Applications', + shortCode: '[BCA]', + description: + 'BCA – Bachelor of Computer Applications – is a 3-year long degree that can be pursued after completion of 10+2. BCA is available in Regular, Distance, and online format. A minimum of 50% marks are required for admission to BCA. A BCA degree is pursued by students who wish to get Jobs in the IT & Tech Industry', + jobRoles: ['Software Developer', 'Technical Analyst', 'System Engineer', 'Web Developer'], + }, + { + title: 'Bachelor of Business Administration', + shortCode: '[BBA]', + description: + 'The Bachelor of Business Administration (BBA) course is a 3-year undergraduate program ideal for students exploring careers in business management. Students can pursue a general BBA or choose specialized subjects such as BBA in Finance, BBA in Marketing, BBA in International Business, BBA in Human Res', + jobRoles: [ + 'Marketing Executive', + 'Business Analyst', + 'Finance/Banking', + 'Risk Control Analyst', + ], + }, + { + title: 'Master of Business Administration', + shortCode: '[MBA]', + description: + 'MBA (Master of Business Administration) is a 2-year postgraduate program that teaches students how to manage businesses, lead teams, and make important decisions. During an MBA, students learn about areas like Finance, Marketing, Human Resources, Operations, and Leadership.', + jobRoles: [ + 'Human Resources Manager', + 'Operations Manager', + 'Marketing Manager', + 'Relationship Manager', + ], + }, + { + title: 'Bachelor of Technology', + shortCode: '[B.Tech] (Computer Science)', + description: + 'BTech CSE is a 4 year UG course that studies practical and theoretical knowledge of computer hardware and software. This course lays emphasis on the basics of computer programming and networking while also comprising a plethora of topics. The admission process for the B.tech CSE is to clear entrance exams', + jobRoles: [ + 'Project Coordinator', + 'Information Technology', + 'Applications Engineer', + 'Solutions Engineer', + ], + }, + { + title: 'Master of Computer Applications', + shortCode: '[MCA]', + description: + "MCA (Master of Computer Applications) is a master's level course focusing on computer applications and software development. It will provide you with comprehensive knowledge and skills in topics like programming languages, data structures, DBMS, emerging technologies and more in a 3-year course", + jobRoles: ['Software Engineer', 'Software Developer', 'Data Engineer', 'Java Programmer'], + }, + { + title: 'Bachelor of Education', + shortCode: '[B.Ed]', + description: + 'The Bachelor of Education (B.Ed.) degree is a 2-year professional program for individuals aspiring to be teachers in schools, colleges, and other academic institutions. B Ed course is crucial for those who want to pursue a career in teaching and is a common qualification for teaching positions.', + jobRoles: [ + 'Assistant Professor', + 'Higher Education', + 'Primary School Teacher', + 'Secondary School Teacher', + ], + }, ]; const generateMockCourses = (page: number, count = 5): Course[] => { @@ -40,48 +112,62 @@ const generateMockCourses = (page: number, count = 5): Course[] => { const template = COURSES_DB[(page * count + i) % COURSES_DB.length]; return { id: `${page}-${i}`, - title: template.title || "Course Title", - shortCode: template.shortCode || "Code", + title: template.title || 'Course Title', + shortCode: template.shortCode || 'Code', duration: `${2 + Math.floor(Math.random() * 3)} Years`, - degreeType: "Degree", - mode: "On Campus", - level: Math.random() > 0.5 ? "Graduation" : "Post Graduation", - eligibility: "10+2", - entranceExam: ["CUET", "JEE Main", "CAT", "NEET"][Math.floor(Math.random() * 4)], - description: template.description || "Course description...", - jobRoles: template.jobRoles || ["Role 1", "Role 2"], - collegeCount: 100 + Math.floor(Math.random() * 4000) + degreeType: 'Degree', + mode: 'On Campus', + level: Math.random() > 0.5 ? 'Graduation' : 'Post Graduation', + eligibility: '10+2', + entranceExam: ['CUET', 'JEE Main', 'CAT', 'NEET'][Math.floor(Math.random() * 4)], + description: template.description || 'Course description...', + jobRoles: template.jobRoles || ['Role 1', 'Role 2'], + collegeCount: 100 + Math.floor(Math.random() * 4000), }; }); }; // --- Components --- -const FilterSection: React.FC<{ title: string; count?: number; items: string[]; isOpen?: boolean }> = ({ title, count, items, isOpen = false }) => { +const FilterSection: React.FC<{ + title: string; + count?: number; + items: string[]; + isOpen?: boolean; +}> = ({ title, count, items, isOpen = false }) => { const [open, setOpen] = useState(isOpen); return ( -
+
{open && ( -
+
{/* Search inside filter if needed (omitted for brevity based on design) */} {items.map((item, idx) => ( -
@@ -111,11 +197,11 @@ export const CourseFinder: React.FC = () => { const fetchCourses = useCallback(async () => { setLoading(true); // Simulate API delay - await new Promise(resolve => setTimeout(resolve, 800)); + await new Promise((resolve) => setTimeout(resolve, 800)); const newCourses = generateMockCourses(page); - setCourses(prev => [...prev, ...newCourses]); - setPage(prev => prev + 1); + setCourses((prev) => [...prev, ...newCourses]); + setPage((prev) => prev + 1); setLoading(false); // Stop after 5 pages for demo @@ -129,7 +215,7 @@ export const CourseFinder: React.FC = () => { useEffect(() => { const observer = new IntersectionObserver( - entries => { + (entries) => { if (entries[0].isIntersecting && hasMore && !loading) { fetchCourses(); } @@ -149,76 +235,102 @@ export const CourseFinder: React.FC = () => { }, [hasMore, loading, fetchCourses]); return ( -
+
{/* --- Top Search Area --- */} -
-
-
-
- +
+
+
+
+
{/* Top Filters Row */} -
- - {['Course', 'State', 'City', 'Entrance/Exam Accepted', 'Program Type'].map(filter => ( - ))}
-
- +
{/* --- Left Sidebar Filters --- */} -