merge: sync remote github/main with local main
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# ─── DATABASE CONNECTION CONFIGURATION ───
|
||||
spring.datasource.url=jdbc:postgresql://localhost:5432/rit_freshers_hub?sslmode=disable
|
||||
spring.datasource.username=postgres
|
||||
spring.datasource.password=${DB_PASSWORD:Amudiesh22@.}
|
||||
spring.datasource.password=${DB_PASSWORD:Devesh@54}
|
||||
|
||||
# ─── JPA / HIBERNATE SETTINGS ───
|
||||
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
|
||||
|
||||
42
package-lock.json
generated
42
package-lock.json
generated
@@ -1776,9 +1776,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3602,9 +3599,6 @@
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3619,9 +3613,6 @@
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3636,9 +3627,6 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3653,9 +3641,6 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3670,9 +3655,6 @@
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3687,9 +3669,6 @@
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3704,9 +3683,6 @@
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3721,9 +3697,6 @@
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3738,9 +3711,6 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3755,9 +3725,6 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3772,9 +3739,6 @@
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3789,9 +3753,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3806,9 +3767,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
||||
@@ -65,14 +65,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.08095,
|
||||
"lng": 80.27076
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.184827,
|
||||
"from_lng": 80.31205,
|
||||
"to_lat": 13.08095,
|
||||
"to_lng": 80.27076,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.184827,
|
||||
@@ -1146,14 +1146,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.08095,
|
||||
"lng": 80.27076
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.128881,
|
||||
"from_lng": 80.290792,
|
||||
"to_lat": 13.08095,
|
||||
"to_lng": 80.27076,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.184827,
|
||||
@@ -2193,14 +2193,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.08095,
|
||||
"lng": 80.27076
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.08095,
|
||||
"from_lng": 80.27076,
|
||||
"to_lat": 13.08095,
|
||||
"to_lng": 80.27076,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.184827,
|
||||
@@ -3258,14 +3258,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0761258,
|
||||
"from_lng": 80.270781,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.100598,
|
||||
@@ -4211,14 +4211,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.090276,
|
||||
"from_lng": 80.265585,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.118326,
|
||||
@@ -5196,14 +5196,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0884944,
|
||||
"from_lng": 80.1909707,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.118326,
|
||||
@@ -6207,14 +6207,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.089154,
|
||||
"from_lng": 80.230054,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.118326,
|
||||
@@ -7220,14 +7220,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.085333,
|
||||
"from_lng": 80.187393,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.085333,
|
||||
@@ -7847,14 +7847,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0293843,
|
||||
"from_lng": 80.2342825,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R05A",
|
||||
@@ -7934,14 +7934,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0617032,
|
||||
"from_lng": 80.2346118,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R06",
|
||||
@@ -8023,14 +8023,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.062841,
|
||||
"from_lng": 80.197105,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.066018,
|
||||
@@ -13337,14 +13337,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R10",
|
||||
@@ -15473,14 +15473,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.2820098,
|
||||
"from_lng": 80.2537109,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R13",
|
||||
@@ -15560,14 +15560,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R13A",
|
||||
@@ -15623,14 +15623,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.1001091,
|
||||
"from_lng": 80.2145485,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R14",
|
||||
@@ -15698,14 +15698,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R14B",
|
||||
@@ -15743,14 +15743,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.1305159,
|
||||
"from_lng": 79.9243758,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R15",
|
||||
@@ -15818,14 +15818,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R15A",
|
||||
@@ -15929,14 +15929,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R15B",
|
||||
@@ -16010,14 +16010,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R16",
|
||||
@@ -16085,14 +16085,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R16B",
|
||||
@@ -16184,14 +16184,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R17",
|
||||
@@ -16245,14 +16245,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.040666,
|
||||
"from_lng": 80.17222,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.054006,
|
||||
@@ -16860,14 +16860,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.040666,
|
||||
"from_lng": 80.17222,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.054006,
|
||||
@@ -17479,14 +17479,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 12.984051,
|
||||
"from_lng": 80.2175088,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R18A",
|
||||
@@ -17542,14 +17542,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R18B",
|
||||
@@ -17635,14 +17635,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 12.7871437,
|
||||
"from_lng": 80.219987,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R19",
|
||||
@@ -17704,14 +17704,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R19A",
|
||||
@@ -17749,14 +17749,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R20",
|
||||
@@ -17818,14 +17818,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R20A",
|
||||
@@ -17881,14 +17881,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R21",
|
||||
@@ -17944,14 +17944,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R22",
|
||||
@@ -18043,14 +18043,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R22A",
|
||||
@@ -18136,14 +18136,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R23",
|
||||
@@ -18211,14 +18211,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R24",
|
||||
@@ -18346,14 +18346,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R25",
|
||||
@@ -18409,14 +18409,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.1331405,
|
||||
"from_lng": 80.1701786,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R25A",
|
||||
@@ -18460,14 +18460,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R26",
|
||||
@@ -18535,14 +18535,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.1938755,
|
||||
"from_lng": 80.2685646,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R27",
|
||||
@@ -20662,14 +20662,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.1158603,
|
||||
"from_lng": 80.2300407,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214,
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138,
|
||||
"polyline": [
|
||||
[
|
||||
13.115889,
|
||||
@@ -21543,14 +21543,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R29A",
|
||||
@@ -21600,14 +21600,14 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
},
|
||||
{
|
||||
"number": "R29B",
|
||||
@@ -21669,13 +21669,13 @@
|
||||
{
|
||||
"name": "RIT Campus",
|
||||
"time": "07:40 AM",
|
||||
"lat": 13.0118,
|
||||
"lng": 80.0214
|
||||
"lat": 13.03868,
|
||||
"lng": 80.045138
|
||||
}
|
||||
],
|
||||
"from_lat": 13.0118,
|
||||
"from_lng": 80.0214,
|
||||
"to_lat": 13.0118,
|
||||
"to_lng": 80.0214
|
||||
"to_lat": 13.03868,
|
||||
"to_lng": 80.045138
|
||||
}
|
||||
]
|
||||
@@ -6,6 +6,7 @@ import ProtectedRoute from '@/components/Auth/ProtectedRoute';
|
||||
import MainLayout from '@/layouts/MainLayout';
|
||||
import Home from '@/pages/Home/Home';
|
||||
import Notes from '@/pages/Notes/Notes';
|
||||
import Toolkit from '@/pages/Toolkit/Toolkit';
|
||||
import AIAssistant from '@/pages/AIAssistant/AIAssistant';
|
||||
import Campus from '@/pages/Campus/Campus';
|
||||
import Events from '@/pages/Events/Events';
|
||||
@@ -49,6 +50,7 @@ function App() {
|
||||
<Route element={<MainLayout />}>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/notes" element={<Notes />} />
|
||||
<Route path="/toolkit" element={<Toolkit />} />
|
||||
<Route path="/ai-assistant" element={<AIAssistant />} />
|
||||
<Route path="/campus" element={<Campus />} />
|
||||
<Route path="/bus-routes" element={<BusRoutes />} />
|
||||
|
||||
@@ -17,37 +17,84 @@ L.Icon.Default.mergeOptions({
|
||||
shadowUrl: markerShadow,
|
||||
});
|
||||
|
||||
// Glowing Live Bus Icon
|
||||
const liveBusIcon = L.divIcon({
|
||||
html: `<div class="relative flex items-center justify-center w-10 h-10 rounded-full bg-emerald-500 border-2 border-white shadow-xl text-white text-base font-bold cursor-pointer"><span class="absolute inset-0 rounded-full bg-emerald-500/50 animate-ping"></span>🚌</div>`,
|
||||
html: `<div class="relative flex items-center justify-center w-10 h-10 rounded-full bg-emerald-500 border-2 border-white shadow-2xl text-white text-base font-bold cursor-pointer"><span class="absolute inset-0 rounded-full bg-emerald-500/60 animate-ping"></span>🚌</div>`,
|
||||
className: '',
|
||||
iconSize: [40, 40],
|
||||
iconAnchor: [20, 20],
|
||||
});
|
||||
|
||||
// Stopped Bus Icon
|
||||
const stoppedBusIcon = L.divIcon({
|
||||
html: `<div class="relative flex items-center justify-center w-10 h-10 rounded-full bg-red-500 border-2 border-white shadow-xl text-white text-base font-bold cursor-pointer">🚌</div>`,
|
||||
html: `<div class="relative flex items-center justify-center w-10 h-10 rounded-full bg-red-500 border-2 border-white shadow-2xl text-white text-base font-bold cursor-pointer">🚌</div>`,
|
||||
className: '',
|
||||
iconSize: [40, 40],
|
||||
iconAnchor: [20, 20],
|
||||
});
|
||||
|
||||
// Helper component to pan map to active bus marker when selected
|
||||
function MapPanFocus({ center }: { center: [number, number] | null }) {
|
||||
// Helper: Create Clean Start Point Icon (Starting Location Name Only)
|
||||
function createStartIcon(locationName: string) {
|
||||
return L.divIcon({
|
||||
html: `
|
||||
<div class="relative flex items-center justify-center cursor-pointer group">
|
||||
<span class="absolute -inset-2 rounded-full bg-emerald-500/40 animate-ping"></span>
|
||||
<div class="relative flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-emerald-600 border-2 border-white text-white font-extrabold text-xs shadow-2xl transition-transform group-hover:scale-105">
|
||||
<span class="text-sm">📍</span>
|
||||
<span class="whitespace-nowrap tracking-wide">${locationName}</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
className: '',
|
||||
iconSize: [160, 40],
|
||||
iconAnchor: [80, 20],
|
||||
});
|
||||
}
|
||||
|
||||
// Helper: Create Clean Destination Point Icon (RIT Campus Only)
|
||||
function createDestinationIcon(locationName: string) {
|
||||
const displayName = locationName.includes('RIT') ? locationName : 'RIT Campus';
|
||||
return L.divIcon({
|
||||
html: `
|
||||
<div class="relative flex items-center justify-center cursor-pointer group">
|
||||
<span class="absolute -inset-2 rounded-full bg-orange-500/40 animate-ping"></span>
|
||||
<div class="relative flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-orange-600 border-2 border-white text-white font-extrabold text-xs shadow-2xl transition-transform group-hover:scale-105">
|
||||
<span class="text-sm">🏫</span>
|
||||
<span class="whitespace-nowrap tracking-wide">${displayName}</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
className: '',
|
||||
iconSize: [160, 40],
|
||||
iconAnchor: [80, 20],
|
||||
});
|
||||
}
|
||||
|
||||
// Helper component to auto-fit map view bounds when route changes
|
||||
function MapPanFocus({ bounds }: { bounds: L.LatLngBoundsExpression | null }) {
|
||||
const map = useMap();
|
||||
|
||||
useEffect(() => {
|
||||
if (center) {
|
||||
map.setView(center, 13, { animate: true });
|
||||
if (bounds) {
|
||||
map.fitBounds(bounds, {
|
||||
padding: [80, 80],
|
||||
maxZoom: 14,
|
||||
animate: true,
|
||||
duration: 0.8,
|
||||
});
|
||||
}
|
||||
}, [center, map]);
|
||||
}, [bounds, map]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
interface BusRouteMapProps {
|
||||
selectedRoute: BusRoute | null;
|
||||
allRoutes: BusRoute[];
|
||||
allRoutes?: BusRoute[];
|
||||
}
|
||||
|
||||
const DEFAULT_CENTER: [number, number] = [13.0118, 80.0214]; // RIT Campus default
|
||||
const RIT_CAMPUS_COORDS: [number, number] = [13.03868, 80.045138]; // True RIT Campus Kuthambakkam / Poonamallee
|
||||
const DEFAULT_CENTER: [number, number] = RIT_CAMPUS_COORDS;
|
||||
|
||||
export default function BusRouteMap({ selectedRoute }: BusRouteMapProps) {
|
||||
const [allLiveLocations, setAllLiveLocations] = useState<
|
||||
@@ -100,36 +147,52 @@ export default function BusRouteMap({ selectedRoute }: BusRouteMapProps) {
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
// Determine center focus point if a bus is live or selected
|
||||
const activeFocusCenter = useMemo<[number, number] | null>(() => {
|
||||
// Compute Start and Destination coordinates only
|
||||
const routeData = useMemo(() => {
|
||||
if (!selectedRoute) return null;
|
||||
|
||||
const normalizeRouteNum = (str: string) => (str || '').replace(/^[Rr]0*/, '').trim().toUpperCase();
|
||||
const matchLocKey = Object.keys(allLiveLocations).find(
|
||||
(k) => normalizeRouteNum(k) === normalizeRouteNum(selectedRoute.number)
|
||||
);
|
||||
|
||||
if (matchLocKey && allLiveLocations[matchLocKey]) {
|
||||
const loc = allLiveLocations[matchLocKey];
|
||||
return [loc.latitude, loc.longitude];
|
||||
}
|
||||
// Start coordinates
|
||||
let startCoords: [number, number] | null = null;
|
||||
let startName = selectedRoute.from || 'Start Point';
|
||||
|
||||
if (selectedRoute.from_lat && selectedRoute.from_lng) {
|
||||
return [selectedRoute.from_lat, selectedRoute.from_lng];
|
||||
startCoords = [selectedRoute.from_lat, selectedRoute.from_lng];
|
||||
} else if (selectedRoute.stops && selectedRoute.stops.length > 0) {
|
||||
const firstStop = selectedRoute.stops[0];
|
||||
if (firstStop.lat && firstStop.lng) {
|
||||
startCoords = [firstStop.lat, firstStop.lng];
|
||||
startName = firstStop.name || startName;
|
||||
}
|
||||
}
|
||||
|
||||
return DEFAULT_CENTER;
|
||||
}, [selectedRoute, allLiveLocations]);
|
||||
// Destination is ALWAYS the true RIT Campus location (Kuthambakkam)
|
||||
const destCoords: [number, number] = RIT_CAMPUS_COORDS;
|
||||
const destName = 'RIT Campus';
|
||||
|
||||
// Compute bounding box for map view auto-fit (start & destination only)
|
||||
const allPoints: [number, number][] = [];
|
||||
if (startCoords) allPoints.push(startCoords);
|
||||
if (destCoords) allPoints.push(destCoords);
|
||||
|
||||
const bounds: L.LatLngBoundsExpression | null =
|
||||
allPoints.length > 0 ? (allPoints as L.LatLngBoundsExpression) : null;
|
||||
|
||||
return {
|
||||
startCoords,
|
||||
startName,
|
||||
destCoords,
|
||||
destName,
|
||||
bounds,
|
||||
};
|
||||
}, [selectedRoute]);
|
||||
|
||||
return (
|
||||
<div className="relative h-full w-full bg-slate-950 overflow-hidden">
|
||||
<MapContainer
|
||||
center={DEFAULT_CENTER as L.LatLngExpression}
|
||||
zoom={11}
|
||||
minZoom={10}
|
||||
minZoom={9}
|
||||
maxZoom={18}
|
||||
maxBounds={[[12.65, 79.25], [13.35, 80.45]] as L.LatLngBoundsExpression}
|
||||
maxBoundsViscosity={1.0}
|
||||
className="h-full w-full z-10"
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
>
|
||||
@@ -138,7 +201,52 @@ export default function BusRouteMap({ selectedRoute }: BusRouteMapProps) {
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
/>
|
||||
|
||||
{/* Live GPS Bus Markers ONLY - No polyline routes */}
|
||||
{/* ── SELECTED ROUTE MARKERS (Starting Point & RIT Campus Destination ONLY) ── */}
|
||||
{selectedRoute && routeData && (
|
||||
<>
|
||||
{/* START Point Marker */}
|
||||
{routeData.startCoords && (
|
||||
<Marker
|
||||
position={routeData.startCoords}
|
||||
icon={createStartIcon(routeData.startName)}
|
||||
>
|
||||
<Popup>
|
||||
<div className="p-1 font-sans text-center">
|
||||
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-emerald-100 text-emerald-800 text-[10px] font-bold">
|
||||
📍 ORIGIN / PICKUP
|
||||
</span>
|
||||
<h4 className="font-bold text-slate-900 text-xs mt-1">{routeData.startName}</h4>
|
||||
<p className="text-[10px] text-slate-500 mt-0.5">
|
||||
Departure: <strong>{selectedRoute.departureTime || 'Early Morning'}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</Popup>
|
||||
</Marker>
|
||||
)}
|
||||
|
||||
{/* DESTINATION Point Marker (RIT Campus) */}
|
||||
{routeData.destCoords && (
|
||||
<Marker
|
||||
position={routeData.destCoords}
|
||||
icon={createDestinationIcon(routeData.destName)}
|
||||
>
|
||||
<Popup>
|
||||
<div className="p-1 font-sans text-center">
|
||||
<span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-orange-100 text-orange-800 text-[10px] font-bold">
|
||||
🏫 DESTINATION
|
||||
</span>
|
||||
<h4 className="font-bold text-slate-900 text-xs mt-1">{routeData.destName}</h4>
|
||||
<p className="text-[10px] text-slate-500 mt-0.5">
|
||||
Arrival: <strong>{selectedRoute.arrivalTime || '08:30 AM'}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</Popup>
|
||||
</Marker>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* ── LIVE GPS BUS TRACKING MARKERS ── */}
|
||||
{Object.entries(allLiveLocations).map(([rNum, loc]) => {
|
||||
const normalizeRouteNum = (str: string) => (str || '').replace(/^[Rr]0*/, '').trim().toUpperCase();
|
||||
if (selectedRoute && normalizeRouteNum(selectedRoute.number) !== normalizeRouteNum(rNum)) return null;
|
||||
@@ -174,7 +282,8 @@ export default function BusRouteMap({ selectedRoute }: BusRouteMapProps) {
|
||||
);
|
||||
})}
|
||||
|
||||
<MapPanFocus center={activeFocusCenter} />
|
||||
{/* Auto fit map bounds when selected route changes */}
|
||||
<MapPanFocus bounds={routeData?.bounds || null} />
|
||||
</MapContainer>
|
||||
|
||||
{/* Floating Info Card on Selected Route */}
|
||||
@@ -183,21 +292,21 @@ export default function BusRouteMap({ selectedRoute }: BusRouteMapProps) {
|
||||
<div className="flex items-center gap-2 mb-1.5">
|
||||
<span
|
||||
className="px-2.5 py-0.5 rounded-full text-xs font-bold text-white shadow-xs"
|
||||
style={{ backgroundColor: selectedRoute.color }}
|
||||
style={{ backgroundColor: selectedRoute.color || '#F97316' }}
|
||||
>
|
||||
{selectedRoute.number}
|
||||
</span>
|
||||
<span className="text-xs font-bold text-white">{selectedRoute.name}</span>
|
||||
</div>
|
||||
<div className="text-[11px] text-slate-300 space-y-1">
|
||||
<p>
|
||||
🏁 <strong>Start:</strong> {selectedRoute.from} ({selectedRoute.departureTime})
|
||||
<p className="flex items-center gap-1.5">
|
||||
<span className="text-emerald-400 font-bold">📍 Start:</span> {selectedRoute.from} ({selectedRoute.departureTime})
|
||||
</p>
|
||||
<p>
|
||||
🏫 <strong>Destination:</strong> RIT Campus ({selectedRoute.arrivalTime})
|
||||
<p className="flex items-center gap-1.5">
|
||||
<span className="text-orange-400 font-bold">🏫 Destination:</span> RIT Campus ({selectedRoute.arrivalTime})
|
||||
</p>
|
||||
<p>
|
||||
📍 <strong>Stops:</strong> {selectedRoute.stops.length} mapped stops
|
||||
<p className="text-slate-400 text-[10px] pt-0.5">
|
||||
📍 {selectedRoute.stops.length} mapped stops along route
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -58,32 +58,32 @@ export default function Navbar() {
|
||||
initial={{ y: -100, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.6, ease: 'easeOut' }}
|
||||
className="fixed top-4 left-1/2 -translate-x-1/2 z-50 w-[95%] max-w-6xl transition-all duration-300 shadow-[0_8px_32px_rgba(0,0,0,0.25)]"
|
||||
className="fixed top-4 left-1/2 -translate-x-1/2 z-50 w-[96%] max-w-7xl transition-all duration-300 shadow-[0_8px_32px_rgba(0,0,0,0.3)]"
|
||||
style={{
|
||||
background: 'linear-gradient(to right, rgba(15, 23, 42, 0.45) 0%, rgba(30, 41, 59, 0.35) 50%, rgba(15, 23, 42, 0.45) 100%)',
|
||||
background: 'linear-gradient(to right, rgba(15, 23, 42, 0.75) 0%, rgba(30, 41, 59, 0.65) 50%, rgba(15, 23, 42, 0.75) 100%)',
|
||||
backdropFilter: 'blur(16px)',
|
||||
WebkitBackdropFilter: 'blur(16px)',
|
||||
borderRadius: '20px',
|
||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.15)',
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-between px-5 py-2.5">
|
||||
<div className="flex items-center justify-between px-3.5 sm:px-5 py-2">
|
||||
{/* Logo - RIT Event Hub Style */}
|
||||
<a href="/" className="flex items-center gap-2 group">
|
||||
<a href="/" className="flex items-center gap-2 group shrink-0">
|
||||
{/* Logo Image */}
|
||||
<motion.img
|
||||
whileHover={{ scale: 1.05 }}
|
||||
src="/logo.png"
|
||||
alt="RIT Logo"
|
||||
className="w-10 h-10 object-contain rounded-full shrink-0"
|
||||
className="w-9 h-9 sm:w-10 sm:h-10 object-contain rounded-full shrink-0"
|
||||
/>
|
||||
|
||||
<div className="flex items-center">
|
||||
<span className="font-extrabold text-white text-2xl tracking-tighter" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
<span className="font-extrabold text-white text-xl sm:text-2xl tracking-tighter" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
rit
|
||||
</span>
|
||||
<div className="h-7 w-[1px] bg-white/20 mx-2" />
|
||||
<div className="flex flex-col text-[8.5px] font-bold text-slate-200 leading-tight tracking-wider" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
<div className="h-6 sm:h-7 w-[1px] bg-white/20 mx-1.5 sm:mx-2" />
|
||||
<div className="hidden sm:flex flex-col text-[8px] sm:text-[8.5px] font-bold text-slate-200 leading-tight tracking-wider" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
<span>RAJALAKSHMI</span>
|
||||
<span>INSTITUTE OF</span>
|
||||
<span>TECHNOLOGY</span>
|
||||
@@ -92,14 +92,14 @@ export default function Navbar() {
|
||||
</a>
|
||||
|
||||
{/* Desktop Nav */}
|
||||
<div className="hidden md:flex items-center gap-1">
|
||||
<div className="hidden lg:flex items-center gap-0.5 xl:gap-1">
|
||||
{NAV_LINKS.map((link) => {
|
||||
const isActive = checkIsActive(link.path);
|
||||
return (
|
||||
<Link
|
||||
key={link.path}
|
||||
to={link.path}
|
||||
className="relative px-1.5 lg:px-2.5 xl:px-3.5 py-1.5 rounded-lg text-[10px] lg:text-[11px] xl:text-xs font-semibold uppercase tracking-wider transition-all duration-200"
|
||||
className="relative px-2 xl:px-2.5 py-1.5 rounded-lg text-[10px] xl:text-[11px] font-bold uppercase tracking-wider transition-all duration-200"
|
||||
style={{
|
||||
fontFamily: 'Poppins, sans-serif',
|
||||
color: isActive ? '#FFFFFF' : '#CBD5E1',
|
||||
@@ -120,7 +120,7 @@ export default function Navbar() {
|
||||
</div>
|
||||
|
||||
{/* Right Side: Auth + Mobile Toggle */}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
{/* Auth Section */}
|
||||
{isAuthenticated && user ? (
|
||||
<div className="relative" ref={profileRef}>
|
||||
@@ -140,8 +140,8 @@ export default function Navbar() {
|
||||
{user.name.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
<div className="hidden lg:flex flex-col items-start">
|
||||
<span className="text-white text-[11px] font-semibold leading-tight max-w-[100px] truncate">
|
||||
<div className="hidden xl:flex flex-col items-start">
|
||||
<span className="text-white text-[11px] font-semibold leading-tight max-w-[90px] truncate">
|
||||
{user.name.split(' ')[0]}
|
||||
</span>
|
||||
{isVerifiedStudent && (
|
||||
@@ -150,7 +150,7 @@ export default function Navbar() {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<ChevronDown className="w-3 h-3 text-slate-400 hidden lg:block" />
|
||||
<ChevronDown className="w-3 h-3 text-slate-400 hidden xl:block" />
|
||||
</button>
|
||||
|
||||
{/* Profile Dropdown */}
|
||||
@@ -213,10 +213,10 @@ export default function Navbar() {
|
||||
</div>
|
||||
) : (
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.03 }}
|
||||
whileTap={{ scale: 0.97 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
onClick={loginWithGoogle}
|
||||
className="hidden md:flex items-center gap-2 px-4 py-2 rounded-xl text-white text-[11px] font-semibold border border-white/15 hover:border-orange-500/40 hover:bg-white/5 transition-all cursor-pointer"
|
||||
className="flex items-center gap-1.5 px-3.5 py-1.5 rounded-xl text-white text-xs font-bold bg-gradient-to-r from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600 shadow-md shadow-orange-500/25 border border-orange-400/40 transition-all cursor-pointer shrink-0"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<LogIn className="w-3.5 h-3.5" />
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Feature, Stat, BusRoute, Faculty, Event, Club, Question, ToolkitIt
|
||||
export const NAV_LINKS = [
|
||||
{ label: 'Home', path: '/' },
|
||||
{ label: 'Notes', path: '/notes' },
|
||||
{ label: 'Toolkit', path: '/notes?section=toolkit' },
|
||||
{ label: 'Toolkit', path: '/toolkit' },
|
||||
{ label: 'Chatbot', path: '/ai-assistant' },
|
||||
{ label: 'Campus Map', path: '/campus' },
|
||||
{ label: 'Bus Routes', path: '/bus-routes' },
|
||||
@@ -94,10 +94,28 @@ export const FEATURES: Feature[] = [
|
||||
icon: 'Wrench',
|
||||
title: 'Student Toolkit',
|
||||
description: 'Download timetables, academic calendar, syllabus, forms, and ERP guides.',
|
||||
path: '/notes?section=toolkit',
|
||||
path: '/toolkit',
|
||||
color: '#06B6D4',
|
||||
bgColor: '#ECFEFF',
|
||||
},
|
||||
{
|
||||
id: 'collab',
|
||||
icon: 'Code2',
|
||||
title: 'Dev Collab',
|
||||
description: 'Connect with peer developers, build campus projects, share repositories, and collaborate.',
|
||||
path: '/collab',
|
||||
color: '#6366F1',
|
||||
bgColor: '#EEF2FF',
|
||||
},
|
||||
{
|
||||
id: 'leetcode',
|
||||
icon: 'Trophy',
|
||||
title: 'LeetCode Leaderboard',
|
||||
description: 'Track peer coding rankings, solve daily problems, and compete on the campus leaderboard.',
|
||||
path: '/leetcode',
|
||||
color: '#F59E0B',
|
||||
bgColor: '#FEF3C7',
|
||||
},
|
||||
];
|
||||
|
||||
// ─── Bus Routes ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -23,8 +23,9 @@ const BLUEPRINT_LEGEND = [
|
||||
{ id: 'a-block', label: 'A Block', color: '#60A5FA', bg: 'bg-blue-50/80', text: 'text-blue-900', border: 'border-blue-200' },
|
||||
{ id: 'b-block', label: 'B Block', color: '#93C5FD', bg: 'bg-blue-50/60', text: 'text-blue-900', border: 'border-blue-200' },
|
||||
{ id: 'c-block', label: 'C Block', color: '#BFDBFE', bg: 'bg-blue-50/40', text: 'text-blue-900', border: 'border-blue-200' },
|
||||
{ id: 'h-block', label: 'H Block', color: '#C084FC', bg: 'bg-purple-50/80', text: 'text-purple-900', border: 'border-purple-200' },
|
||||
{ id: 'admin', label: 'Admin / Facility', color: '#FDBA74', bg: 'bg-orange-50/80', text: 'text-orange-950', border: 'border-orange-200' },
|
||||
{ id: 'hostel', label: 'Hostel / Mess', color: '#C084FC', bg: 'bg-purple-50/80', text: 'text-purple-950', border: 'border-purple-200' },
|
||||
{ id: 'hostel', label: 'Hostel / Mess', color: '#F472B6', bg: 'bg-pink-50/80', text: 'text-pink-950', border: 'border-pink-200' },
|
||||
{ id: 'lab', label: 'Lab / Academic', color: '#FDE047', bg: 'bg-yellow-50/80', text: 'text-yellow-950', border: 'border-yellow-200' },
|
||||
{ id: 'amenity', label: 'Amenity', color: '#BEF264', bg: 'bg-lime-50/80', text: 'text-lime-950', border: 'border-lime-200' },
|
||||
{ id: 'parking', label: 'Parking Area', color: '#94A3B8', bg: 'bg-slate-100/80', text: 'text-slate-900', border: 'border-slate-300' },
|
||||
@@ -39,15 +40,15 @@ const LOCATION_SPOTS: LocationSpot[] = [
|
||||
{ name: 'Girls Mess', x: 14.5, y: 31.0, category: 'Hostel / Mess', desc: 'Dedicated Dining Hall for Women', area: 'West Wing' },
|
||||
{ name: 'MEC Lab', x: 14.0, y: 39.5, category: 'Lab / Academic', desc: 'Mechanical Engineering Laboratory', area: 'West Wing' },
|
||||
{ name: 'EPL Lab', x: 13.0, y: 47.5, category: 'Lab / Academic', desc: 'Engineering Practices Laboratory', area: 'West Wing' },
|
||||
{ name: 'Nikola Tesla Block', x: 40.5, y: 36.5, category: 'B Block', desc: 'Main Electrical & Engineering Research Block', area: 'Central Block' },
|
||||
{ name: 'B Block (Nikola Tesla Block)', x: 40.5, y: 36.5, category: 'B Block', desc: 'Main Electrical & Engineering Research Block', area: 'Central Block' },
|
||||
{ name: 'Astronaut Statue', x: 51.0, y: 23.0, category: 'Amenity', desc: 'Iconic Landmark Monument', area: 'Central Park' },
|
||||
{ name: 'Campus Centre', x: 67.0, y: 23.0, category: 'Admin / Facility', desc: 'Student Activity & Administrative Center', area: 'North East' },
|
||||
{ name: 'Hut', x: 70.0, y: 37.0, category: 'Amenity', desc: 'Student Discussion & Rest Area', area: 'Central East' },
|
||||
{ name: 'Homi Jehangir Bhabha Block', x: 87.0, y: 24.0, category: 'A Block', desc: 'Science & Physics Research Block', area: 'East Wing' },
|
||||
{ name: 'Boys Mess', x: 87.0, y: 17.5, category: 'Hostel / Mess', desc: 'Ground Floor Dining Hall for Men (Homi Bhabha Block)', area: 'East Wing' },
|
||||
{ name: 'Staff Mess', x: 87.0, y: 30.5, category: 'Amenity', desc: 'First Floor Dining Hall for Faculty & Staff (Homi Bhabha Block)', area: 'East Wing' },
|
||||
{ name: 'H Block (Homi Jehangir Bhabha Block)', x: 87.0, y: 24.0, category: 'H Block', desc: 'Science & Physics Research Block', area: 'East Wing' },
|
||||
{ name: 'Boys Mess', x: 87.0, y: 17.5, category: 'Hostel / Mess', desc: 'Ground Floor Dining Hall for Men (H Block)', area: 'East Wing' },
|
||||
{ name: 'Staff Mess', x: 87.0, y: 30.5, category: 'Amenity', desc: 'First Floor Dining Hall for Faculty & Staff (H Block)', area: 'East Wing' },
|
||||
{ name: 'C Block', x: 87.0, y: 38.0, category: 'C Block', desc: 'Labs, Classrooms & Staff Rooms', area: 'East Wing' },
|
||||
{ name: 'Alan Turing Block', x: 77.0, y: 53.0, category: 'Lab / Academic', desc: 'Computer Science & AI Labs', area: 'East Wing' },
|
||||
{ name: 'A Block (Alan Turing Block)', x: 77.0, y: 53.0, category: 'A Block', desc: 'Computer Science & AI Labs', area: 'East Wing' },
|
||||
{ name: 'Arcade', x: 35.0, y: 57.0, category: 'Amenity', desc: 'Student Hub & Stores', area: 'Central South' },
|
||||
{ name: 'Green Building', x: 23.0, y: 71.0, category: 'Admin / Facility', desc: 'Eco-Friendly Academic Complex & Library', area: 'South West' },
|
||||
{ name: 'Security Booth', x: 49.0, y: 77.0, category: 'Amenity', desc: 'Main Gate Security Checkpoint', area: 'South Entrance' },
|
||||
@@ -59,9 +60,9 @@ const LOCATION_SPOTS: LocationSpot[] = [
|
||||
];
|
||||
|
||||
const CATEGORY_MAP_SPOTS: Record<string, string[]> = {
|
||||
dept: ['Homi Jehangir Bhabha Block', 'Nikola Tesla Block', 'C Block', 'Steve Jobs Block', 'Alan Turing Block', 'Green Building'],
|
||||
dept: ['A Block (Alan Turing Block)', 'B Block (Nikola Tesla Block)', 'C Block', 'H Block (Homi Jehangir Bhabha Block)', 'Steve Jobs Block', 'Green Building'],
|
||||
library: ['Green Building'],
|
||||
labs: ['MEC Lab', 'EPL Lab', 'Steve Jobs Block', 'Alan Turing Block', 'Nikola Tesla Block', 'C Block'],
|
||||
labs: ['MEC Lab', 'EPL Lab', 'A Block (Alan Turing Block)', 'B Block (Nikola Tesla Block)', 'C Block', 'H Block (Homi Jehangir Bhabha Block)', 'Steve Jobs Block'],
|
||||
hostel: ['Girls Hostel', 'Boys Mess'],
|
||||
canteen: ['Canteen', 'Girls Mess', 'Boys Mess', 'Staff Mess', 'Arcade'],
|
||||
auditorium: ['Steve Jobs Block', 'Campus Centre'],
|
||||
@@ -119,6 +120,7 @@ export default function Campus() {
|
||||
if (activeLegend === 'a-block' && spot.category === 'A Block') highlightedSpotNames.add(spot.name);
|
||||
if (activeLegend === 'b-block' && spot.category === 'B Block') highlightedSpotNames.add(spot.name);
|
||||
if (activeLegend === 'c-block' && spot.category === 'C Block') highlightedSpotNames.add(spot.name);
|
||||
if (activeLegend === 'h-block' && spot.category === 'H Block') highlightedSpotNames.add(spot.name);
|
||||
if (activeLegend === 'admin' && spot.category === 'Admin / Facility') highlightedSpotNames.add(spot.name);
|
||||
if (activeLegend === 'hostel' && spot.category === 'Hostel / Mess') highlightedSpotNames.add(spot.name);
|
||||
if (activeLegend === 'lab' && spot.category === 'Lab / Academic') highlightedSpotNames.add(spot.name);
|
||||
@@ -133,6 +135,7 @@ export default function Campus() {
|
||||
if (activeLegend === 'a-block') return fac.category === 'A Block';
|
||||
if (activeLegend === 'b-block') return fac.category === 'B Block';
|
||||
if (activeLegend === 'c-block') return fac.category === 'C Block';
|
||||
if (activeLegend === 'h-block') return fac.category === 'H Block';
|
||||
if (activeLegend === 'admin') return fac.category === 'Admin / Facility';
|
||||
if (activeLegend === 'hostel') return fac.category === 'Hostel / Mess';
|
||||
if (activeLegend === 'lab') return fac.category === 'Lab / Academic';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Search, Download, Filter, BookOpen, FileText, ScrollText, BookMarked, ChevronRight, ArrowLeft, ExternalLink, Code, Globe, GitBranch, Cloud, Palette, Shield, DollarSign, BarChart3, Users, Megaphone, TrendingUp, UserCheck, ClipboardList, ShoppingCart, Cpu, Activity, LayoutGrid, Layers, Zap, Settings, Gauge, Radio, Wifi, Bot, Sun, Wrench, Binary, BatteryCharging, CircuitBoard, ShieldCheck, BrainCircuit, FlaskConical, Lock, Terminal, Dna, Microscope, Sparkles, Smartphone, Monitor, Server, CheckCircle2, Database, Briefcase, AlertTriangle } from 'lucide-react';
|
||||
import { Search, Download, Filter, BookOpen, FileText, ScrollText, BookMarked, ChevronRight, ArrowLeft, ExternalLink, Code, Globe, GitBranch, Cloud, Palette, Shield, DollarSign, BarChart3, Users, Megaphone, TrendingUp, UserCheck, ClipboardList, ShoppingCart, Cpu, Activity, LayoutGrid, Layers, Zap, Settings, Gauge, Radio, Wifi, Bot, Sun, Wrench, Binary, BatteryCharging, CircuitBoard, ShieldCheck, BrainCircuit, FlaskConical, Lock, Terminal, Dna, Microscope, Sparkles, Smartphone, Monitor, Server, CheckCircle2, Database, Briefcase, AlertTriangle, RefreshCw } from 'lucide-react';
|
||||
import SectionTitle from '@/components/SectionTitle/SectionTitle';
|
||||
|
||||
const MOODLE_URL = 'http://182.74.17.142/moodle/login/index.php';
|
||||
import { getBackendUrl } from '@/lib/utils';
|
||||
import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer';
|
||||
import { TOOLKIT_ITEMS, DEPARTMENTS } from '@/constants';
|
||||
@@ -1432,27 +1434,7 @@ export default function Notes() {
|
||||
)}
|
||||
|
||||
<div className="container-custom py-10">
|
||||
{/* Under Development Banner */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="bg-amber-50 border border-amber-200 rounded-2xl p-4 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 text-amber-900 shadow-2xs mb-8"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-9 h-9 rounded-xl bg-amber-500/10 border border-amber-500/20 flex items-center justify-center shrink-0">
|
||||
<AlertTriangle className="w-5 h-5 text-amber-600" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs font-bold uppercase tracking-wider text-amber-700" style={{ fontFamily: 'Inter, sans-serif' }}>Under Development</div>
|
||||
<div className="text-xs font-medium text-amber-900" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Currently displaying sample mock notes & syllabus data. Official semester notes repository integration is in progress.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span className="px-3 py-1 rounded-full bg-amber-100 border border-amber-300 text-[11px] font-bold text-amber-800 shrink-0">
|
||||
Mock Data Active
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
|
||||
{selectedToolkit ? (
|
||||
(() => {
|
||||
@@ -1936,220 +1918,112 @@ export default function Notes() {
|
||||
})()
|
||||
) : (
|
||||
<div>
|
||||
{/* Search + Filters */}
|
||||
<div className="mb-12">
|
||||
{/* Moodle Academic Portal Hero Hub */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 16 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.4, delay: 0.1 }}
|
||||
className="bg-white rounded-2xl border border-[#E5E7EB] p-5 mb-8"
|
||||
style={{ boxShadow: '0 2px 15px -3px rgba(0,0,0,0.07)' }}
|
||||
transition={{ duration: 0.4 }}
|
||||
className="bg-white rounded-3xl border border-[#E5E7EB] p-8 md:p-10 shadow-sm relative overflow-hidden mb-8"
|
||||
style={{ boxShadow: '0 4px 25px -5px rgba(0,0,0,0.05)' }}
|
||||
>
|
||||
{/* Search */}
|
||||
<div className="relative mb-4">
|
||||
<Search className="absolute left-4 top-1/2 -translate-y-1/2 w-4.5 h-4.5 text-[#94A3B8]" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search notes, subjects..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full pl-11 pr-4 py-3 rounded-xl border border-[#E5E7EB] text-sm text-[#1E293B] placeholder-[#94A3B8] focus:outline-none focus:border-[#F97316] transition-colors"
|
||||
style={{ fontFamily: 'Inter, sans-serif' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Subtle Decorative Background Glow */}
|
||||
<div className="absolute -right-20 -top-20 w-80 h-80 bg-orange-500/5 rounded-full blur-3xl pointer-events-none" />
|
||||
<div className="absolute -left-20 -bottom-20 w-80 h-80 bg-amber-500/5 rounded-full blur-3xl pointer-events-none" />
|
||||
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{/* Type Filter */}
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Filter className="w-4 h-4 text-[#94A3B8]" />
|
||||
{['all', 'notes', 'pyq', 'syllabus'].map((type) => (
|
||||
<button
|
||||
key={type}
|
||||
onClick={() => setSelectedType(type)}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium capitalize transition-all"
|
||||
style={{
|
||||
fontFamily: 'Poppins, sans-serif',
|
||||
backgroundColor: selectedType === type ? '#F97316' : '#F8FAFC',
|
||||
color: selectedType === type ? 'white' : '#475569',
|
||||
border: `1px solid ${selectedType === type ? '#F97316' : '#E5E7EB'}`,
|
||||
}}
|
||||
>
|
||||
{type === 'all' ? 'All Types' : type.toUpperCase()}
|
||||
</button>
|
||||
))}
|
||||
<div className="relative z-10 max-w-3xl mx-auto text-center">
|
||||
{/* Header Badge */}
|
||||
<div className="inline-flex items-center gap-2 px-3.5 py-1.5 rounded-full bg-orange-50 border border-orange-200 text-xs font-bold text-[#F97316] mb-6">
|
||||
<BookOpen className="w-4 h-4 text-[#F97316]" />
|
||||
<span>Official RIT Learning Management System</span>
|
||||
</div>
|
||||
|
||||
{/* Semester Filter */}
|
||||
<div className="flex gap-2 flex-wrap items-center">
|
||||
{SEMESTERS.slice(0, 3).map((sem) => (
|
||||
<button
|
||||
key={sem}
|
||||
onClick={() => { setSelectedSem(sem); setSelectedSubject('All Subjects'); }}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium transition-all cursor-pointer"
|
||||
style={{
|
||||
fontFamily: 'Poppins, sans-serif',
|
||||
backgroundColor: selectedSem === sem ? '#1E293B' : '#F8FAFC',
|
||||
color: selectedSem === sem ? 'white' : '#475569',
|
||||
border: `1px solid ${selectedSem === sem ? '#1E293B' : '#E5E7EB'}`,
|
||||
}}
|
||||
>
|
||||
{sem}
|
||||
</button>
|
||||
))}
|
||||
{/* Main Heading */}
|
||||
<h2 className="text-3xl sm:text-4xl font-extrabold text-[#1E293B] mb-4 leading-tight" style={{ fontFamily: 'Playfair Display, serif' }}>
|
||||
Access Academic Notes & Study Materials on{' '}
|
||||
<span style={{ background: 'linear-gradient(135deg, #F97316, #FB923C)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', backgroundClip: 'text' }}>
|
||||
Moodle
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<p className="text-base text-[#64748B] mb-8 leading-relaxed max-w-2xl mx-auto" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
All official semester notes, previous year question papers (PYQs), syllabus data, and lab manuals are hosted directly on the official Rajalakshmi Institute of Technology Moodle server.
|
||||
</p>
|
||||
|
||||
{/* Primary Launch Action Buttons */}
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 mb-10">
|
||||
<a
|
||||
href={MOODLE_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="w-full sm:w-auto inline-flex items-center justify-center gap-3 px-8 py-4 rounded-2xl text-base font-bold text-white shadow-lg hover:shadow-xl hover:-translate-y-0.5 transition-all cursor-pointer"
|
||||
style={{
|
||||
fontFamily: 'Poppins, sans-serif',
|
||||
background: 'linear-gradient(135deg, #F97316, #FB923C)',
|
||||
}}
|
||||
>
|
||||
<ExternalLink className="w-5 h-5" />
|
||||
Launch Official RIT Moodle Portal
|
||||
</a>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(MOODLE_URL);
|
||||
alert('Moodle URL copied to clipboard!');
|
||||
}}
|
||||
className="w-full sm:w-auto inline-flex items-center justify-center gap-2 px-6 py-4 rounded-2xl border border-[#E5E7EB] hover:border-[#F97316] bg-[#F8FAFC] hover:bg-white text-sm font-semibold text-[#475569] hover:text-[#F97316] transition-all cursor-pointer"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<Globe className="w-4 h-4 text-[#64748B]" />
|
||||
Copy Moodle Direct URL
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Subject Dropdown */}
|
||||
{selectedSem !== 'All' && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-semibold text-[#64748B]" style={{ fontFamily: 'Poppins, sans-serif' }}>Subject:</span>
|
||||
<select
|
||||
value={selectedSubject}
|
||||
onChange={(e) => setSelectedSubject(e.target.value)}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium bg-[#F8FAFC] border border-[#E5E7EB] text-[#475569] focus:outline-none focus:border-[#F97316] transition-all cursor-pointer"
|
||||
style={{ fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
<option value="All Subjects">All Subjects</option>
|
||||
{(SUBJECTS_BY_SEM[parseInt(selectedSem)] || []).map((sub) => (
|
||||
<option key={sub} value={sub}>
|
||||
{sub}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{/* Feature Highlights Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-left border-t border-[#F1F5F9] pt-8">
|
||||
<div className="p-4 rounded-2xl bg-[#F8FAFC] border border-[#E5E7EB]/70 flex flex-col gap-2">
|
||||
<div className="w-8 h-8 rounded-xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-emerald-600">
|
||||
<ShieldCheck className="w-4 h-4" />
|
||||
</div>
|
||||
<div className="text-xs font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
100% Direct & Secure
|
||||
</div>
|
||||
<div className="text-[11px] text-[#64748B]" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Authenticates directly on official college server <code className="bg-slate-200/80 px-1 py-0.5 rounded text-[10px]">182.74.17.142</code>.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="p-4 rounded-2xl bg-[#F8FAFC] border border-[#E5E7EB]/70 flex flex-col gap-2">
|
||||
<div className="w-8 h-8 rounded-xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center text-blue-600">
|
||||
<FileText className="w-4 h-4" />
|
||||
</div>
|
||||
<div className="text-xs font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
Official Semester Notes
|
||||
</div>
|
||||
<div className="text-[11px] text-[#64748B]" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Complete 1st to 8th Semester course notes, PYQs, and assignments.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 rounded-2xl bg-[#F8FAFC] border border-[#E5E7EB]/70 flex flex-col gap-2">
|
||||
<div className="w-8 h-8 rounded-xl bg-purple-500/10 border border-purple-500/20 flex items-center justify-center text-purple-600">
|
||||
<Lock className="w-4 h-4" />
|
||||
</div>
|
||||
<div className="text-xs font-bold text-[#1E293B]" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
Student Login
|
||||
</div>
|
||||
<div className="text-[11px] text-[#64748B]" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
Log in using your RIT Register Number and official Moodle password.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Technical Security Note */}
|
||||
<div className="mt-6 text-[11px] text-[#94A3B8] leading-relaxed" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
ℹ️ <span className="font-semibold text-[#64748B]">Security Note:</span> To protect student session privacy and prevent clickjacking attacks, RIT's Moodle server enforces opening the portal directly in a secure browser tab rather than inside third-party frames (<code className="bg-slate-100 px-1 py-0.5 rounded text-[10px]">X-Frame-Options: SAMEORIGIN</code>).
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Results */}
|
||||
<StaggerContainer key={`${filtered.length}-${selectedSubject}`} className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mb-12">
|
||||
{filtered.map((note) => {
|
||||
const typeConfig = TYPE_COLORS[note.type] || { bg: '#F1F5F9', text: '#475569', icon: BookOpen };
|
||||
const TypeIcon = typeConfig.icon;
|
||||
return (
|
||||
<StaggerItem key={note.id}>
|
||||
<motion.div
|
||||
whileHover={{ y: -4 }}
|
||||
className="bg-white rounded-2xl border border-[#E5E7EB] p-5 flex flex-col justify-between gap-4 h-full"
|
||||
style={{
|
||||
borderLeft: `4px solid ${typeConfig.text}`,
|
||||
boxShadow: '0 2px 15px -3px rgba(0,0,0,0.07)'
|
||||
}}
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
{/* Visual PDF Preview Icon */}
|
||||
<div className="w-14 h-20 border border-slate-200 rounded-xl p-2 flex flex-col justify-between bg-[#F8FAFC] shrink-0 shadow-sm">
|
||||
<div className="bg-[#EF4444] text-[8px] font-extrabold text-white px-1 py-0.5 rounded w-fit uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
PDF
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="w-full h-1 bg-slate-200 rounded" />
|
||||
<div className="w-5/6 h-1 bg-slate-200 rounded" />
|
||||
<div className="w-2/3 h-1 bg-slate-200 rounded" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Text Details */}
|
||||
<div className="flex flex-col justify-between flex-1 min-w-0">
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<div className="w-6 h-6 rounded-lg flex items-center justify-center shrink-0" style={{ backgroundColor: typeConfig.bg }}>
|
||||
<TypeIcon className="w-3.5 h-3.5" style={{ color: typeConfig.text }} />
|
||||
</div>
|
||||
<span
|
||||
className="px-2 py-0.5 rounded-full text-[9px] font-bold uppercase tracking-wider"
|
||||
style={{ backgroundColor: typeConfig.bg, color: typeConfig.text, fontFamily: 'Poppins, sans-serif' }}
|
||||
>
|
||||
{note.type}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="text-sm font-bold text-[#1E293B] line-clamp-2 leading-tight mb-1" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{note.title}
|
||||
</h3>
|
||||
<p className="text-[11px] text-[#64748B] font-medium truncate" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
{note.subject} • Sem {note.semester}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Metadata Line */}
|
||||
<div className="flex items-center justify-between border-t border-[#F1F5F9] pt-3 text-[11px] text-[#64748B]" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="font-semibold text-slate-800">{note.downloads} downloads · {note.fileSize}</span>
|
||||
<span className="px-1 py-0.2 bg-[#F1F5F9] rounded text-[9px] font-bold text-slate-600">PDF</span>
|
||||
</div>
|
||||
<span>{note.uploadedAt ? `Updated ${note.uploadedAt}` : 'Recently'}</span>
|
||||
</div>
|
||||
|
||||
{/* Download Button */}
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.97 }}
|
||||
onClick={() => handleDownload(note.id, note.downloadUrl)}
|
||||
className="w-full flex items-center justify-center gap-2 py-2.5 rounded-xl text-sm font-semibold text-white cursor-pointer"
|
||||
style={{
|
||||
fontFamily: 'Poppins, sans-serif',
|
||||
background: 'linear-gradient(135deg, #F97316, #FB923C)',
|
||||
}}
|
||||
>
|
||||
<Download className="w-4 h-4" />
|
||||
Download
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
</StaggerItem>
|
||||
);
|
||||
})}
|
||||
</StaggerContainer>
|
||||
|
||||
{/* Toolkit Section */}
|
||||
<div ref={toolkitRef} />
|
||||
<SectionTitle tag="Useful Downloads" title="Student" highlight="Toolkit" align="left" />
|
||||
<StaggerContainer className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-20">
|
||||
{TOOLKIT_ITEMS.map((item) => {
|
||||
const iconConfig = TOOLKIT_ICONS[item.title] || { icon: Code, bg: '#FFF7ED', color: '#F97316' };
|
||||
const IconComponent = iconConfig.icon;
|
||||
return (
|
||||
<StaggerItem key={item.id} className="flex">
|
||||
<motion.div
|
||||
onClick={() => {
|
||||
if (item.title === 'CS tools') {
|
||||
setSelectedToolkit('cs');
|
||||
} else if (item.title === 'Business tools') {
|
||||
setSelectedToolkit('business');
|
||||
} else if (item.title === 'Electrical and Electronic tools') {
|
||||
setSelectedToolkit('electrical');
|
||||
} else if (item.title === 'Cybersecurity tools') {
|
||||
setSelectedToolkit('cybersecurity');
|
||||
} else if (item.title === 'AI tools') {
|
||||
setSelectedToolkit('ai');
|
||||
} else if (item.title === 'Biotech tools') {
|
||||
setSelectedToolkit('biotech');
|
||||
} else if (item.url && item.url !== '#') {
|
||||
window.open(item.url, '_blank');
|
||||
}
|
||||
}}
|
||||
whileHover={{ y: -4, boxShadow: '0 12px 30px -10px rgba(249,115,22,0.15)' }}
|
||||
className="flex items-start gap-5 p-7 bg-white hover:bg-[#FFF7ED] rounded-[22px] border border-[#E5E7EB] hover:border-[#FED7AA] cursor-pointer group w-full transition-all shadow-xs hover:shadow-md"
|
||||
>
|
||||
<div
|
||||
className="w-14 h-14 rounded-2xl flex items-center justify-center shrink-0 font-bold text-sm transition-transform group-hover:scale-105"
|
||||
style={{ backgroundColor: iconConfig.bg, color: iconConfig.color }}
|
||||
>
|
||||
<IconComponent className="w-7 h-7" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-base lg:text-lg font-bold text-[#1E293B] group-hover:text-[#F97316] transition-colors mb-1" style={{ fontFamily: 'Poppins, sans-serif' }}>
|
||||
{item.title}
|
||||
</div>
|
||||
<div className="text-sm text-[#64748B] leading-relaxed" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
{item.description}
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-[#94A3B8] group-hover:text-[#F97316] group-hover:translate-x-1.5 transition-all shrink-0 mt-1" />
|
||||
</motion.div>
|
||||
</StaggerItem>
|
||||
);
|
||||
})}
|
||||
</StaggerContainer>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
1020
src/pages/Toolkit/Toolkit.tsx
Normal file
1020
src/pages/Toolkit/Toolkit.tsx
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user