Compare commits

..

18 Commits

Author SHA1 Message Date
Shanmuga Krishnan S M
1cbee2f4c8 remove(driver-app): remove rit-driver-app from git repository and add to .gitignore
Some checks are pending
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Waiting to run
2026-08-04 14:35:46 +05:30
Shanmuga Krishnan S M
d81b2682b4 fix(driver-app): remove silent stopSelf on location permission warning so background tracking thread always executes
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 14:31:05 +05:30
Shanmuga Krishnan S M
e5725615be fix(backend): replace Lombok in DriverLocationUpdate with explicit getters/setters to fix HTTP 400 JSON deserialization error
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 14:22:27 +05:30
Shanmuga Krishnan S M
3319868eca fix(driver-app): specify FOREGROUND_SERVICE_TYPE_LOCATION in startForeground call for Android 14/15 compatibility
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 14:18:11 +05:30
Shanmuga Krishnan S M
14b87b9d12 fix(driver-app): change RECEIVER_NOT_EXPORTED to RECEIVER_EXPORTED so MainActivity receives location updates from TrackingService
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 14:16:31 +05:30
Shanmuga Krishnan S M
4ef114fdcd fix(driver-app): guarantee Android 13+ broadcast delivery with explicit package targeting and indoor location fallback
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 14:13:58 +05:30
Shanmuga Krishnan S M
20a0dd842f fix(driver-app): clean up Android Studio XML layout render and button size warnings in activity_main.xml
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 14:09:06 +05:30
Shanmuga Krishnan S M
3397bb5ed1 fix(driver-app): optimize indoor building and stationary location tracking via freshest provider
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 14:02:05 +05:30
Shanmuga Krishnan S M
08974b9cd8 style(hero): set explicit inline color #FFFFFF for Welcome to RIT Freshers Hub text
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 13:57:06 +05:30
Shanmuga Krishnan S M
c1fcc83840 fix(ui): improve hero text contrast to crisp white with drop-shadows, remove false badges and non-working footer links
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 13:54:38 +05:30
Shanmuga Krishnan S M
e8886203ed feat(ui): add Under Development & Mock Data warning banners to Faculty Directory and Notes sections
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 13:40:59 +05:30
Shanmuga Krishnan S M
04c4ed907c feat(chatbot): add AI accuracy warning and disclaimer to initial greeting across Web, Telegram, and Discord
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 13:18:11 +05:30
Shanmuga Krishnan S M
d76e956b07 changes
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 13:07:56 +05:30
Shanmuga Krishnan S M
f198b43e4c changes
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 13:02:22 +05:30
Shanmuga Krishnan S M
c101cf05ed feat(map): add Boys Mess and Staff Mess markers pointing to Homi Jehangir Bhabha Block
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 11:57:32 +05:30
Shanmuga Krishnan S M
fca13b2e2c feat(map): update 3D campus map image and map all 22 pin locations accurately
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 11:51:26 +05:30
Shanmuga Krishnan S M
0ac0646614 ci(gitea): add Gitea Actions deployment workflow and Gitea CI/CD guide
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 11:18:23 +05:30
Shanmuga Krishnan S M
c7891cd992 ci: add GitHub Actions automated deployment workflow and CI/CD guide
Some checks failed
Deploy RIT Freshers Hub to VPS / Deploy to Live VPS (push) Has been cancelled
2026-08-04 11:16:12 +05:30
34 changed files with 365 additions and 1276 deletions

View File

@@ -0,0 +1,42 @@
name: Deploy RIT Freshers Hub to VPS
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy to Live VPS
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: SSH into VPS and Deploy
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.VPS_SSH_KEY }}
port: 22
script: |
echo "🚀 Starting Automated CI/CD Deployment from Gitea..."
cd /var/www/freshers-hub
echo "📥 Pulling latest code from Gitea..."
git pull origin main
echo "⚡ Building Frontend PWA..."
npm install --production=false
npm run build
echo "🤖 Building Go Chatbot..."
cd /var/www/freshers-hub/chatbot-service
go build -o chatbot-service main.go
echo "🔄 Restarting Systemd Services..."
systemctl restart springboot chatbot telegram-bot nginx
echo "🎉 Deployment Completed Successfully!"

42
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Deploy RIT Freshers Hub to VPS
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy to Live VPS
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: SSH into VPS and Deploy
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.VPS_SSH_KEY }}
port: 22
script: |
echo "🚀 Starting Automated CI/CD Deployment..."
cd /var/www/freshers-hub
echo "📥 Pulling latest code from GitHub..."
git pull origin main
echo "⚡ Building Frontend PWA..."
npm install --production=false
npm run build
echo "🤖 Building Go Chatbot..."
cd /var/www/freshers-hub/chatbot-service
go build -o chatbot-service main.go
echo "🔄 Restarting Systemd Services..."
systemctl restart springboot chatbot telegram-bot nginx
echo "🎉 Deployment Completed Successfully!"

View File

@@ -143,9 +143,7 @@ cd freshers-hub
---
## Step 6: Build & Run Component 2 (Spring Boot Java Backend - Port 8085)
1. **Build the Spring Boot `.jar` file:**
```bash
cd /var/www/freshers-hub/backend
chmod +x mvnw

84
CICD_GUIDE.md Normal file
View File

@@ -0,0 +1,84 @@
# 🔄 RIT Freshers Hub - Step-by-Step CI/CD Pipeline Guide
Automate your live server deployments with **GitHub Actions** so that whenever you run `git push origin main`, your website, backend, chatbot, and services update on your VPS automatically in 30 seconds!
---
## 🏗️ How the CI/CD Pipeline Works
```mermaid
graph LR
A[💻 Developer Pushes Code] -->|git push origin main| B[🐙 GitHub Repository]
B -->|Triggers Workflow| C[⚡ GitHub Actions Runner]
C -->|Secure SSH Connection| D[🌐 VPS Server 129.121.126.66]
D -->|1. git pull| E[📥 Update Code]
E -->|2. npm run build| F[⚡ Build PWA Frontend]
F -->|3. go build| G[🤖 Build Go Engine]
G -->|4. systemctl restart| H[🚀 Live Site Updated!]
```
---
## 🛠️ Step-by-Step Setup Guide
### Step 1: Add SSH Secrets to your GitHub Repository
1. Open your GitHub Repository in your web browser:
`https://github.com/Amudieshwar-AG/Freshers-Hub`
2. Click **Settings** (top toolbar) ⚙️.
3. In the left sidebar, expand **Secrets and variables** ➔ click **Actions**.
4. Click **New repository secret** (green button on top right) and add these **3 secrets**:
---
#### 🔑 Secret 1: `VPS_HOST`
* **Name:** `VPS_HOST`
* **Secret Value:** `129.121.126.66`
#### 🔑 Secret 2: `VPS_USERNAME`
* **Name:** `VPS_USERNAME`
* **Secret Value:** `root`
#### 🔑 Secret 3: `VPS_SSH_KEY`
* **Name:** `VPS_SSH_KEY`
* **Secret Value:** Paste your SSH Private Key contents.
* *Where to find your key on VPS:* Run `cat ~/.ssh/id_rsa` or `cat ~/.ssh/id_ed25519` on your server terminal.
* Copy the entire key including `-----BEGIN OPENSSH PRIVATE KEY-----` and `-----END OPENSSH PRIVATE KEY-----`.
---
### Step 2: Push the Workflow File to GitHub
The deployment workflow file is already created at:
[.github/workflows/deploy.yml](file:///f:/fresher/Freshers-Hub/.github/workflows/deploy.yml)
Push it to GitHub by running in your local terminal:
```bash
git add .github/workflows/deploy.yml CICD_GUIDE.md
git commit -m "ci: add GitHub Actions automated deployment workflow"
git push origin main
```
---
### Step 3: Test your CI/CD Pipeline! 🎉
1. Make any code edit or change on your project.
2. Push your changes:
```bash
git push origin main
```
3. Go to your **GitHub Repository** ➔ Click the **Actions** tab.
4. You will see a live workflow named **"Deploy RIT Freshers Hub to VPS"** running!
5. In ~30 seconds, it will complete with a green checkmark ``, and your live server at `https://rit-services.in` will be updated automatically!
---
## 🛑 Troubleshooting CI/CD Pipeline Issues
* **Error: `ssh: handshake failed` or `permission denied (publickey)`**
* **Fix:** Make sure the public key corresponding to `VPS_SSH_KEY` is added to `/root/.ssh/authorized_keys` on your VPS.
* On your VPS, run: `cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys`
* **Error: `Host key verification failed`**
* **Fix:** `appleboy/ssh-action` handles host key verification automatically, but ensure `VPS_HOST` is set strictly to `129.121.126.66` without extra spaces or `http://`.

62
GITEA_CICD_GUIDE.md Normal file
View File

@@ -0,0 +1,62 @@
# 🦊 RIT Freshers Hub - Gitea CI/CD Pipeline Guide
Automate your deployments from your self-hosted Gitea repository (`https://git.rit-services.in/ShanmugaKrishnanSM/RIT-nexus.git`) directly to your live VPS!
---
## 🛠️ Choose Your Preferred Gitea CI/CD Method:
* **Method 1: Gitea Actions (Recommended if Gitea Actions is enabled)** — Uses `.gitea/workflows/deploy.yml` with identical syntax to GitHub Actions.
* **Method 2: Gitea Webhook + Lightweight VPS Script (Fastest & Zero Setup)** — Gitea sends an HTTP trigger on push to automatically execute `git pull && npm run build` on your VPS.
---
## 🚀 Method 1: Setting Up Gitea Actions
### Step 1: Add Secrets in Gitea
1. Open your repository in Gitea:
`https://git.rit-services.in/ShanmugaKrishnanSM/RIT-nexus`
2. Click **Settings** (top right) ➔ **Actions****Secrets**.
3. Add these 3 secrets:
* **`VPS_HOST`**: `129.121.126.66`
* **`VPS_USERNAME`**: `root`
* **`VPS_SSH_KEY`**: Paste your SSH Private Key (`cat ~/.ssh/id_rsa` from VPS).
### Step 2: Push Workflow File
The Gitea workflow file is located at [.gitea/workflows/deploy.yml](file:///f:/fresher/Freshers-Hub/.gitea/workflows/deploy.yml).
Every `git push origin main` will automatically run the deployment steps on your VPS!
---
## ⚡ Method 2: Setting Up Gitea Webhook (Lightweight & Instant)
If Gitea Actions runner is not active on your Gitea instance, you can use a native **Gitea Webhook**:
### Step 1: Create a Deploy Script on VPS
On your VPS terminal (`ssh root@129.121.126.66`), create a deployment shell script:
```bash
cat << 'EOF' > /var/www/freshers-hub/deploy.sh
#!/bin/bash
echo "🚀 Deploying latest code from Gitea..."
cd /var/www/freshers-hub
git pull origin main
npm run build
cd chatbot-service && go build -o chatbot-service main.go
systemctl restart springboot chatbot telegram-bot nginx
echo "✅ Deployment finished!"
EOF
chmod +x /var/www/freshers-hub/deploy.sh
```
### Step 2: Add Webhook in Gitea
1. Go to your Gitea Repo ➔ **Settings****Webhooks**.
2. Click **Add Webhook** ➔ Select **Gitea**.
3. **Target URL:** `http://129.121.126.66:9000/hooks/deploy` (or your webhook port).
4. **HTTP Method:** `POST`
5. **Trigger On:** Push Events.
6. Click **Add Webhook**.
Whenever you push code to Gitea, it triggers `deploy.sh` on your VPS instantly!

Binary file not shown.

View File

@@ -1,14 +1,39 @@
package com.rit.portal.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DriverLocationUpdate {
private Double latitude;
private Double longitude;
private String pin;
public DriverLocationUpdate() {}
public DriverLocationUpdate(Double latitude, Double longitude, String pin) {
this.latitude = latitude;
this.longitude = longitude;
this.pin = pin;
}
public Double getLatitude() {
return latitude;
}
public void setLatitude(Double latitude) {
this.latitude = latitude;
}
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
this.longitude = longitude;
}
public String getPin() {
return pin;
}
public void setPin(String pin) {
this.pin = pin;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 282 KiB

View File

@@ -1,33 +0,0 @@
plugins {
id 'com.android.application'
}
android {
namespace 'com.rit.driver'
compileSdk 34
defaultConfig {
applicationId "com.rit.driver"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Location Permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- Foreground Service Permissions -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!-- Wakelock and Network Permissions -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".TrackingService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location" />
</application>
</manifest>

View File

@@ -1,9 +0,0 @@
package com.rit.driver;
public class Config {
public static final String BACKEND_URL = "https://rit-services.in";
public static final String DEFAULT_PIN = "RITDRIVER";
}

View File

@@ -1,202 +0,0 @@
package com.rit.driver;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 888;
private EditText etRouteNumber;
private EditText etDriverPin;
private Button btnStartSharing;
private Button btnStopSharing;
private TextView tvStatusHeader;
private TextView tvStatusLogs;
private LinearLayout statusCard;
private boolean isServiceRunning = false;
// Receive tracking updates from Foreground Service
private final BroadcastReceiver locationReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
if (intent.hasExtra(TrackingService.EXTRA_STATUS)) {
String status = intent.getStringExtra(TrackingService.EXTRA_STATUS);
tvStatusHeader.setText("STATUS: " + (isServiceRunning ? "ACTIVE" : "INACTIVE"));
logStatus(status);
}
if (intent.hasExtra(TrackingService.EXTRA_LATITUDE) && intent.hasExtra(TrackingService.EXTRA_LONGITUDE)) {
double lat = intent.getDoubleExtra(TrackingService.EXTRA_LATITUDE, 0.0);
double lng = intent.getDoubleExtra(TrackingService.EXTRA_LONGITUDE, 0.0);
float accuracy = intent.getFloatExtra(TrackingService.EXTRA_ACCURACY, 0.0f);
String gpsInfo = String.format("GPS Coords: %.6f, %.6f\nAccuracy: ±%.1fm", lat, lng, accuracy);
logStatus(gpsInfo);
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Bind Views
etRouteNumber = findViewById(R.id.etRouteNumber);
etDriverPin = findViewById(R.id.etDriverPin);
etDriverPin.setText(Config.DEFAULT_PIN);
btnStartSharing = findViewById(R.id.btnStartSharing);
btnStopSharing = findViewById(R.id.btnStopSharing);
tvStatusHeader = findViewById(R.id.tvStatusHeader);
tvStatusLogs = findViewById(R.id.tvStatusLogs);
statusCard = findViewById(R.id.statusCard);
btnStartSharing.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkAndRequestPermissions()) {
startTracking();
}
}
});
btnStopSharing.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopTracking();
}
});
}
@Override
protected void onResume() {
super.onResume();
// Register receiver for service communication
IntentFilter filter = new IntentFilter(TrackingService.ACTION_LOCATION_BROADCAST);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(locationReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
} else {
registerReceiver(locationReceiver, filter);
}
}
@Override
protected void onPause() {
// Unregister receiver
unregisterReceiver(locationReceiver);
super.onPause();
}
private void startTracking() {
String serverUrl = Config.BACKEND_URL;
String routeNumber = etRouteNumber.getText().toString().trim();
String driverPin = etDriverPin.getText().toString().trim();
if (routeNumber.isEmpty()) {
Toast.makeText(this, "Enter bus route number", Toast.LENGTH_SHORT).show();
return;
}
if (driverPin.isEmpty()) {
Toast.makeText(this, "Enter security driver PIN", Toast.LENGTH_SHORT).show();
return;
}
Intent serviceIntent = new Intent(this, TrackingService.class);
serviceIntent.putExtra("server_url", serverUrl);
serviceIntent.putExtra("route_number", routeNumber);
serviceIntent.putExtra("driver_pin", driverPin);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent);
} else {
startService(serviceIntent);
}
isServiceRunning = true;
btnStartSharing.setVisibility(View.GONE);
btnStopSharing.setVisibility(View.VISIBLE);
tvStatusHeader.setText("STATUS: ACTIVE");
logStatus("Foreground tracking service started.");
}
private void stopTracking() {
Intent serviceIntent = new Intent(this, TrackingService.class);
stopService(serviceIntent);
isServiceRunning = false;
btnStartSharing.setVisibility(View.VISIBLE);
btnStopSharing.setVisibility(View.GONE);
tvStatusHeader.setText("STATUS: INACTIVE");
logStatus("Tracking stopped by driver.");
}
private void logStatus(String msg) {
String currentText = tvStatusLogs.getText().toString();
tvStatusLogs.setText(msg + "\n\n" + currentText);
}
private boolean checkAndRequestPermissions() {
boolean hasFine = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
boolean hasCoarse = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
List<String> listPermissionsNeeded = new ArrayList<>();
if (!hasFine && !hasCoarse) {
listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
listPermissionsNeeded.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.POST_NOTIFICATIONS);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(
this,
listPermissionsNeeded.toArray(new String[0]),
PERMISSION_REQUEST_CODE
);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
boolean hasFine = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
boolean hasCoarse = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
if (hasFine || hasCoarse) {
startTracking();
} else {
Toast.makeText(this, "Location permission (Precise or Approximate) is required to track the bus.", Toast.LENGTH_LONG).show();
}
}
}
}

View File

@@ -1,78 +0,0 @@
package com.rit.driver;
import android.util.Log;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class NetworkHelper {
private static final String TAG = "NetworkHelper";
public interface Callback {
void onSuccess();
void onFailure(String error);
}
public static void postLocation(final String serverUrl, final String routeNumber, final double lat, final double lng, final String pin, final Callback callback) {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection conn = null;
try {
// Clean URL trailing slash and route mapping
String cleanUrl = serverUrl;
if (cleanUrl.endsWith("/")) {
cleanUrl = cleanUrl.substring(0, cleanUrl.length() - 1);
}
String targetUrl = cleanUrl + "/api/bus-locations/" + routeNumber;
URL url = new URL(targetUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
// Build JSON string payload using Locale.US to ensure dot decimals in JSON
String jsonInputString = String.format(
java.util.Locale.US,
"{\"latitude\": %.6f, \"longitude\": %.6f, \"pin\": \"%s\"}",
lat, lng, pin
);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
int code = conn.getResponseCode();
if (code == 200 || code == 201) {
Log.d(TAG, "Location uploaded successfully: " + code);
if (callback != null) {
callback.onSuccess();
}
} else {
String errMsg = "HTTP error code " + code;
Log.w(TAG, errMsg);
if (callback != null) {
callback.onFailure(errMsg);
}
}
} catch (Exception e) {
String errMsg = "Upload failed: " + e.getMessage();
Log.e(TAG, errMsg, e);
if (callback != null) {
callback.onFailure(errMsg);
}
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
}).start();
}
}

View File

@@ -1,230 +0,0 @@
package com.rit.driver;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
public class TrackingService extends Service {
private static final String TAG = "TrackingService";
private static final String CHANNEL_ID = "TrackingServiceChannel";
private static final int NOTIFICATION_ID = 444;
private LocationManager locationManager;
private PowerManager.WakeLock wakeLock;
private String serverUrl = "";
private String routeNumber = "";
private String driverPin = "";
// Broadcast action for MainActivity to update UI coordinates
public static final String ACTION_LOCATION_BROADCAST = "com.rit.driver.LOCATION_BROADCAST";
public static final String EXTRA_LATITUDE = "extra_latitude";
public static final String EXTRA_LONGITUDE = "extra_longitude";
public static final String EXTRA_ACCURACY = "extra_accuracy";
public static final String EXTRA_STATUS = "extra_status";
private final LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
double lat = location.getLatitude();
double lng = location.getLongitude();
float accuracy = location.getAccuracy();
Log.d(TAG, "Location updated: " + lat + ", " + lng + " (Accuracy: " + accuracy + "m)");
// Broadcast updates locally to MainActivity UI
Intent broadcastIntent = new Intent(ACTION_LOCATION_BROADCAST);
broadcastIntent.putExtra(EXTRA_LATITUDE, lat);
broadcastIntent.putExtra(EXTRA_LONGITUDE, lng);
broadcastIntent.putExtra(EXTRA_ACCURACY, accuracy);
broadcastIntent.putExtra(EXTRA_STATUS, "Broadcasting Location...");
sendBroadcast(broadcastIntent);
// Upload location to backend
NetworkHelper.postLocation(serverUrl, routeNumber, lat, lng, driverPin, new NetworkHelper.Callback() {
@Override
public void onSuccess() {
Log.d(TAG, "Uploaded location successfully");
Intent statusIntent = new Intent(ACTION_LOCATION_BROADCAST);
statusIntent.putExtra(EXTRA_STATUS, "Upload Success: Location synced.");
sendBroadcast(statusIntent);
}
@Override
public void onFailure(String error) {
Log.e(TAG, "Upload failed: " + error);
Intent statusIntent = new Intent(ACTION_LOCATION_BROADCAST);
statusIntent.putExtra(EXTRA_STATUS, "Upload Failed: " + error);
sendBroadcast(statusIntent);
}
});
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {
Intent statusIntent = new Intent(ACTION_LOCATION_BROADCAST);
statusIntent.putExtra(EXTRA_STATUS, "GPS Provider Disabled. Please turn on Location/GPS.");
sendBroadcast(statusIntent);
}
};
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: Service starting");
createNotificationChannel();
}
private android.os.Handler handler = new android.os.Handler(android.os.Looper.getMainLooper());
private Runnable periodicUploader = new Runnable() {
@Override
public void run() {
try {
Location loc = null;
if (locationManager != null) {
try {
Location gpsLoc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Location netLoc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
loc = (gpsLoc != null) ? gpsLoc : netLoc;
} catch (SecurityException ignored) {}
}
if (loc != null) {
locationListener.onLocationChanged(loc);
} else {
Intent statusIntent = new Intent(ACTION_LOCATION_BROADCAST);
statusIntent.putExtra(EXTRA_STATUS, "Waiting for initial GPS location fix...");
sendBroadcast(statusIntent);
}
} catch (Exception e) {
Log.e(TAG, "Error in periodic uploader: " + e.getMessage());
} finally {
handler.postDelayed(this, 5000);
}
}
};
@SuppressLint("InvalidWakeLockTag")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: Service active");
if (intent != null) {
serverUrl = intent.getStringExtra("server_url");
routeNumber = intent.getStringExtra("route_number");
driverPin = intent.getStringExtra("driver_pin");
}
// 1. Show Foreground Notification
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent,
PendingIntent.FLAG_IMMUTABLE
);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("RIT Driver Tracker")
.setContentText("Active Journey: Route " + routeNumber + " is currently tracking...")
.setSmallIcon(android.R.drawable.ic_menu_compass)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build();
startForeground(NOTIFICATION_ID, notification);
// 2. Acquire Power CPU WakeLock
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm != null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TrackingService::WakeLock");
wakeLock.acquire();
Log.d(TAG, "WakeLock acquired successfully");
}
// 3. Register Location Listeners (both GPS and Network for indoors/outdoors)
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try {
if (locationManager != null) {
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 0.0f, locationListener);
}
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3000, 0.0f, locationListener);
}
}
} catch (SecurityException e) {
Log.e(TAG, "SecurityException: Location permissions not granted", e);
stopSelf();
}
// 4. Start periodic 5-second uploader
handler.removeCallbacks(periodicUploader);
handler.post(periodicUploader);
return START_REDELIVER_INTENT;
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: Stopping service cleanups");
// Stop periodic uploader timer
if (handler != null && periodicUploader != null) {
handler.removeCallbacks(periodicUploader);
}
// 1. Remove GPS Listener
if (locationManager != null) {
locationManager.removeUpdates(locationListener);
}
// 2. Release CPU WakeLock
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
Log.d(TAG, "WakeLock released cleanly");
}
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"RIT Driver Tracker Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) {
manager.createNotificationChannel(serviceChannel);
}
}
}
}

View File

@@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#1E293B"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#F97316"
android:pathData="M54,20 C35.22,20 20,35.22 20,54 C20,72.78 35.22,88 54,88 C72.78,88 88,72.78 88,54 C88,35.22 72.78,20 54,20 Z M54,76 C41.85,76 32,66.15 32,54 C32,41.85 41.85,32 54,32 C66.15,32 76,41.85 76,54 C76,66.15 66.15,76 54,76 Z M54,40 L60,54 L54,68 L48,54 Z" />
</vector>

View File

@@ -1,148 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="#1E293B">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<!-- Title -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RIT Driver Tracker"
android:textColor="#FFFFFF"
android:textSize="28sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginTop="24dp"
android:layout_marginBottom="8dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Live Background Geolocation Broadcaster"
android:textColor="#94A3B8"
android:textSize="12sp"
android:gravity="center"
android:layout_marginBottom="32dp" />
<!-- Route Number Input -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="BUS ROUTE NUMBER"
android:textColor="#94A3B8"
android:textSize="11sp"
android:textStyle="bold"
android:layout_marginBottom="6dp" />
<EditText
android:id="@+id/etRouteNumber"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="@android:drawable/editbox_background"
android:hint="R01"
android:text="R01"
android:inputType="textCapCharacters"
android:padding="12dp"
android:textSize="14sp"
android:layout_marginBottom="20dp" />
<!-- Driver PIN Input -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="DRIVER SECURITY PIN"
android:textColor="#94A3B8"
android:textSize="11sp"
android:textStyle="bold"
android:layout_marginBottom="6dp" />
<EditText
android:id="@+id/etDriverPin"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="@android:drawable/editbox_background"
android:hint="Enter Security PIN"
android:text="RITDRIVER"
android:inputType="textPassword"
android:padding="12dp"
android:textSize="14sp"
android:layout_marginBottom="32dp" />
<!-- Start Sharing Button -->
<Button
android:id="@+id/btnStartSharing"
android:layout_width="match_parent"
android:layout_height="56dp"
android:backgroundTint="#F97316"
android:text="START LOCATION SHARING"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="15sp"
android:layout_marginBottom="16dp" />
<!-- Stop Sharing Button -->
<Button
android:id="@+id/btnStopSharing"
android:layout_width="match_parent"
android:layout_height="56dp"
android:backgroundTint="#EF4444"
android:text="STOP LOCATION SHARING"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="15sp"
android:visibility="gone"
android:layout_marginBottom="24dp" />
<!-- Status Card -->
<LinearLayout
android:id="@+id/statusCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#0F172A"
android:padding="16dp"
android:visibility="visible">
<TextView
android:id="@+id/tvStatusHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="STATUS: INACTIVE"
android:textColor="#94A3B8"
android:textStyle="bold"
android:textSize="12sp"
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/tvStatusLogs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Toggle location sharing to begin tracking.\nKeep phone screen turned on or off — the app will broadcast fine coordinates in the background."
android:textColor="#64748B"
android:textSize="12sp"
android:lineSpacingExtra="3dp" />
</LinearLayout>
<!-- Keep screen notice -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Notice: Once active, you can lock the screen or close the app interface. The native system foreground notification service keeps tracking alive."
android:textColor="#64748B"
android:textSize="10sp"
android:gravity="center"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp" />
</LinearLayout>
</ScrollView>

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">RIT Driver Tracker</string>
</resources>

View File

@@ -1,4 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.7.2' apply false
}

View File

@@ -1,4 +0,0 @@
# Project-wide Gradle settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
android.enableJetifier=true

Binary file not shown.

View File

@@ -1,7 +0,0 @@
#Fri Jul 24 14:49:37 IST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

248
rit-driver-app/gradlew vendored
View File

@@ -1,248 +0,0 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@@ -1,93 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -1,8 +0,0 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Fri Jul 24 14:24:21 IST 2026
sdk.dir=C\:\\Users\\dorut\\AppData\\Local\\Android\\Sdk

View File

@@ -1,17 +0,0 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "RIT Driver Tracker"
include ':app'

BIN
src/assets/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

BIN
src/assets/map.png.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

View File

@@ -1,25 +1,16 @@
import { Link } from 'react-router-dom';
import { GraduationCap, MapPin, Phone, Mail, Camera, Send, Globe, Play, ArrowRight } from 'lucide-react';
import { GraduationCap, MapPin, Phone, Mail, ArrowRight } from 'lucide-react';
const quickLinks = [
{ label: 'Home', path: '/' },
{ label: 'Notes & PYQs', path: '/notes' },
{ label: 'Chatbot', path: '/ai-assistant' },
{ label: 'Campus Map', path: '/campus' },
{ label: 'RIT Chatbot', path: '/ai-assistant' },
{ label: '3D Campus Map', path: '/campus' },
{ label: 'Bus Routes', path: '/bus-routes' },
{ label: 'Faculty Directory', path: '/faculty' },
{ label: 'Events', path: '/events' },
{ label: 'Community', path: '/community' },
{ label: 'Dev Collab', path: '/collab' },
];
const resources = [
{ label: 'Student Handbook', path: '#' },
{ label: 'Academic Calendar', path: '#' },
{ label: 'ERP Portal', path: '#' },
{ label: 'Library Portal', path: '#' },
{ label: 'Exam Results', path: '#' },
{ label: 'Fee Payment', path: '#' },
{ label: 'Dev Hub', path: '/collab' },
];
export default function Footer() {
@@ -49,7 +40,7 @@ export default function Footer() {
{/* Main Footer */}
<div className="container-custom py-14">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-10">
<div className="grid grid-cols-1 md:grid-cols-3 gap-10">
{/* Brand */}
<div>
<div className="flex items-center gap-2.5 mb-4">
@@ -65,68 +56,34 @@ export default function Footer() {
</div>
</div>
<p className="text-slate-400 text-sm leading-relaxed mb-5" style={{ fontFamily: 'Inter, sans-serif' }}>
Your all-in-one guide to campus life at RIT. Notes, chatbot, events, faculty, and more made for freshers.
Your all-in-one guide to campus life at RIT. Notes, chatbot, bus routes, 3D campus map, and developer hub built for students.
</p>
<div className="flex items-center gap-3">
{[Camera, Send, Globe, Play].map((Icon, i) => (
<a
key={i}
href="#"
className="w-9 h-9 rounded-lg bg-slate-700 flex items-center justify-center text-slate-400 hover:bg-[#F97316] hover:text-white transition-all duration-200"
aria-label="Social link"
>
<Icon className="w-4 h-4" />
</a>
))}
</div>
</div>
{/* Quick Links */}
<div>
<h4 className="text-white font-semibold mb-4 text-sm uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}>
Quick Links
Quick Navigation
</h4>
<ul className="space-y-2.5">
<div className="grid grid-cols-2 gap-2">
{quickLinks.map((link) => (
<li key={link.path}>
<Link
to={link.path}
className="text-slate-400 hover:text-[#F97316] text-sm transition-colors flex items-center gap-1.5 group"
style={{ fontFamily: 'Inter, sans-serif' }}
>
<span className="w-1 h-1 rounded-full bg-[#F97316] opacity-0 group-hover:opacity-100 transition-opacity" />
{link.label}
</Link>
</li>
<Link
key={link.path}
to={link.path}
className="text-slate-400 hover:text-[#F97316] text-sm transition-colors flex items-center gap-1.5 group py-1"
style={{ fontFamily: 'Inter, sans-serif' }}
>
<span className="w-1 h-1 rounded-full bg-[#F97316] opacity-0 group-hover:opacity-100 transition-opacity" />
{link.label}
</Link>
))}
</ul>
</div>
{/* Resources */}
<div>
<h4 className="text-white font-semibold mb-4 text-sm uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}>
Resources
</h4>
<ul className="space-y-2.5">
{resources.map((res) => (
<li key={res.label}>
<a
href={res.path}
className="text-slate-400 hover:text-[#F97316] text-sm transition-colors flex items-center gap-1.5 group"
style={{ fontFamily: 'Inter, sans-serif' }}
>
<span className="w-1 h-1 rounded-full bg-[#F97316] opacity-0 group-hover:opacity-100 transition-opacity" />
{res.label}
</a>
</li>
))}
</ul>
</div>
</div>
{/* Contact */}
<div>
<h4 className="text-white font-semibold mb-4 text-sm uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}>
Contact
Campus Location & Contact
</h4>
<ul className="space-y-3">
<li className="flex items-start gap-3 text-slate-400 text-sm" style={{ fontFamily: 'Inter, sans-serif' }}>

View File

@@ -9,7 +9,7 @@ const INITIAL_MESSAGES: ChatMessage[] = [
{
id: '1',
role: 'assistant',
content: "👋 Hi there! I'm your **RIT Assistant**. I have comprehensive knowledge about Rajalakshmi Institute of Technology — from admissions to campus facilities, bus routes, and academic details.\n\nHow can I help you today?",
content: "👋 Hi there! I'm your **RIT Chatbot**.\n\n⚠ *Please note: Answers generated by AI may occasionally be inaccurate or wrong. Please cross-reference critical academic, exam, or administrative details with official campus sources.*\n\nHow can I help you today?",
timestamp: new Date().toISOString(),
},
];

View File

@@ -32,34 +32,39 @@ const BLUEPRINT_LEGEND = [
];
const LOCATION_SPOTS: LocationSpot[] = [
{ name: 'Girls Hostel', x: 8.2, y: 12.0, category: 'Hostel / Mess', desc: 'Residential Quarter for Women', area: 'Top Left' },
{ name: 'Playground', x: 32.5, y: 19.5, category: 'Amenity', desc: 'Main Sports & Athletic Field', area: 'Top Left' },
{ name: 'Canteen', x: 63.5, y: 13.5, category: 'Amenity', desc: 'Food Court & Refreshments', area: 'North Center' },
{ name: 'Statue', x: 61.0, y: 26.0, category: 'Amenity', desc: 'Landmark Monument', area: 'North Center' },
{ name: 'Boys Mess', x: 87.8, y: 10.5, category: 'Amenity', desc: 'Ground Floor Dining', area: 'Top Right' },
{ name: 'Staff Mess', x: 87.8, y: 22.0, category: 'Amenity', desc: 'First Floor Dining', area: 'Top Right' },
{ name: 'C Block', x: 87.8, y: 41.0, category: 'C Block', desc: 'Labs, Classrooms, Auditorium & Staff Rooms', area: 'East Block' },
{ name: 'Steve Jobs Block', x: 8.1, y: 38.5, category: 'Admin / Facility', desc: 'Auditorium, Labs & Staff Rooms', area: 'West Wing' },
{ name: 'Girls Mess', x: 8.1, y: 53.0, category: 'Amenity', desc: 'Dedicated Dining Hall for Women', area: 'West Wing' },
{ name: 'EPL Lab', x: 8.1, y: 65.5, category: 'Lab / Academic', desc: 'Engineering Practices Laboratory', area: 'South West' },
{ name: 'B Block', x: 32.5, y: 55.0, category: 'B Block', desc: 'Labs, Classrooms & Faculty Rooms', area: 'Central West' },
{ name: 'Hut', x: 62.7, y: 42.5, category: 'Amenity', desc: 'Student Discussion & Rest Area', area: 'Central Green' },
{ name: 'A Block', x: 70.3, y: 67.0, category: 'A Block', desc: 'Labs, Classrooms, Faculty Rooms, Principal Room & Exam Cell', area: 'Central East' },
{ name: 'RSB Block', x: 24.0, y: 81.5, category: 'Amenity', desc: 'Library, Auditorium & Accounts Room', area: 'South West' },
{ name: 'Side Parking', x: 5.5, y: 85.5, category: 'Parking Area', desc: 'Visitor & Staff Parking Zone', area: 'South West' },
{ name: 'Arcade', x: 41.5, y: 72.8, category: 'Amenity', desc: 'Student Hub & Stores', area: 'South Central' },
{ name: 'Security Booth', x: 45.9, y: 88.5, category: 'Amenity', desc: 'Main Gate Security Checkpoint', area: 'South Entrance' },
{ name: 'Parking Area', x: 73.0, y: 86.0, category: 'Parking Area', desc: 'Two-Wheeler & Four-Wheeler Parking', area: 'South East' },
{ name: 'Main Entrance', x: 51.8, y: 92.5, category: 'Amenity', desc: 'Primary Campus Security Gate', area: 'South Entrance' },
{ name: 'Girls Hostel', x: 16.0, y: 8.5, category: 'Hostel / Mess', desc: 'Residential Quarter for Women', area: 'Top Left' },
{ name: 'Playground', x: 40.0, y: 11.0, category: 'Amenity', desc: 'Main Sports & Athletic Field', area: 'Top Center' },
{ name: 'Canteen', x: 67.0, y: 8.5, category: 'Amenity', desc: 'Food Court & Refreshments', area: 'Top Right' },
{ name: 'Steve Jobs Block', x: 16.0, y: 21.0, category: 'Admin / Facility', desc: 'Auditorium, Computer Labs & Staff Rooms', area: 'West Wing' },
{ 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: '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: '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: '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' },
{ name: 'ATM', x: 49.0, y: 86.0, category: 'Amenity', desc: '24/7 Campus Banking ATM', area: 'South Entrance' },
{ name: 'Bike Parking', x: 75.0, y: 67.0, category: 'Parking Area', desc: 'Two-Wheeler Vehicle Parking', area: 'South East' },
{ name: 'Generator Room', x: 76.0, y: 81.0, category: 'Admin / Facility', desc: 'Campus Power & Utility Station', area: 'South East' },
{ name: 'Side Gate', x: 23.0, y: 93.0, category: 'Amenity', desc: 'Secondary Campus Gate', area: 'South West' },
{ name: 'Main Gate', x: 59.0, y: 93.0, category: 'Amenity', desc: 'Primary Campus Entrance', area: 'South Entrance' },
];
const CATEGORY_MAP_SPOTS: Record<string, string[]> = {
dept: ['A Block', 'B Block', 'C Block'],
library: ['RSB Block'],
labs: ['Steve Jobs Block', 'A Block', 'B Block', 'C Block', 'EPL Lab'],
hostel: ['Girls Hostel'],
canteen: ['Canteen', 'Staff Mess', 'Girls Mess', 'Boys Mess'],
auditorium: ['Steve Jobs Block', 'C Block', 'RSB Block'],
dept: ['Homi Jehangir Bhabha Block', 'Nikola Tesla Block', 'C Block', 'Steve Jobs Block', 'Alan Turing Block', 'Green Building'],
library: ['Green Building'],
labs: ['MEC Lab', 'EPL Lab', 'Steve Jobs Block', 'Alan Turing Block', 'Nikola Tesla Block', 'C Block'],
hostel: ['Girls Hostel', 'Boys Mess'],
canteen: ['Canteen', 'Girls Mess', 'Boys Mess', 'Staff Mess', 'Arcade'],
auditorium: ['Steve Jobs Block', 'Campus Centre'],
sports: ['Playground'],
};

View File

@@ -1,6 +1,6 @@
import { useState, useMemo } from 'react';
import { motion } from 'framer-motion';
import { Search, Users, Filter, ArrowUpDown, BookOpen, ChevronRight } from 'lucide-react';
import { Search, Users, Filter, ArrowUpDown, BookOpen, ChevronRight, AlertTriangle } from 'lucide-react';
import FacultyCard from '@/components/FacultyCard/FacultyCard';
import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer';
import { FACULTY_DATA, DEPARTMENTS } from '@/constants';
@@ -64,6 +64,27 @@ export default function Faculty() {
</div>
<div className="container-custom py-8 space-y-8">
{/* 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"
>
<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 faculty profiles. Official RIT faculty directory 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>
{/* Faculty Hero Section */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 items-stretch">
<div className="lg:col-span-5 bg-white rounded-3xl p-8 border border-[#E8ECF4] shadow-sm flex flex-col justify-center relative overflow-hidden">

View File

@@ -27,25 +27,13 @@ export default function Home() {
className="container-custom relative z-20 flex flex-col items-center text-center px-4"
style={{ opacity: heroOpacity, y: heroY }}
>
{/* Badge */}
<motion.div
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="mb-4 inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-[#FFF7ED] border border-[#FED7AA] text-[#F97316] text-xs font-semibold shadow-2xs"
style={{ fontFamily: 'Poppins, sans-serif' }}
>
<Sparkles className="w-3.5 h-3.5" />
<span>OFFICIAL STUDENT PORTAL</span>
</motion.div>
{/* Heading */}
<motion.h1
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 }}
className="text-white text-3xl md:text-4xl font-light mb-1"
style={{ fontFamily: 'Playfair Display, serif', textShadow: '0 2px 10px rgba(0,0,0,0.5)' }}
className="text-3xl md:text-5xl font-medium tracking-wide mb-2"
style={{ color: '#FFFFFF', fontFamily: 'Playfair Display, serif', textShadow: '0 2px 14px rgba(0,0,0,0.95)' }}
>
Welcome to
</motion.h1>
@@ -54,8 +42,8 @@ export default function Home() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.2 }}
className="text-5xl md:text-7xl font-black leading-tight mb-6 bg-gradient-to-r from-[#F97316] via-[#FB923C] to-[#F97316] bg-clip-text text-transparent"
style={{ fontFamily: 'Playfair Display, serif', filter: 'drop-shadow(0 4px 12px rgba(249, 115, 22, 0.45))' }}
className="text-5xl md:text-7xl font-black leading-tight mb-6"
style={{ color: '#FFFFFF', fontFamily: 'Playfair Display, serif', textShadow: '0 4px 24px rgba(0,0,0,0.95)' }}
>
RIT Freshers Hub
</motion.h2>
@@ -64,7 +52,7 @@ export default function Home() {
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.3 }}
className="max-w-2xl text-slate-200 text-base md:text-lg leading-relaxed mb-8"
className="max-w-2xl text-slate-100 text-base md:text-lg font-medium leading-relaxed mb-8 drop-shadow-md"
style={{ fontFamily: 'Inter, sans-serif' }}
>
Your centralized gateway to campus life at Rajalakshmi Institute of Technology academic notes, AI assistant, bus routes, faculty directory, and campus navigation.
@@ -75,7 +63,7 @@ export default function Home() {
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.4 }}
className="flex flex-wrap justify-center gap-4 mb-10"
className="flex flex-wrap justify-center gap-4"
>
<a href="#built-for-freshers">
<motion.button
@@ -97,7 +85,7 @@ export default function Home() {
<motion.button
whileHover={{ scale: 1.04, borderColor: '#F97316', backgroundColor: 'rgba(255,255,255,0.2)' }}
whileTap={{ scale: 0.96 }}
className="flex items-center gap-2 px-8 py-3.5 rounded-xl font-semibold text-sm border-2 border-white/30 text-white bg-white/10 backdrop-blur-md transition-all cursor-pointer shadow-2xs"
className="flex items-center gap-2 px-8 py-3.5 rounded-xl font-semibold text-sm border-2 border-white/40 text-white bg-black/30 backdrop-blur-md transition-all cursor-pointer shadow-2xs"
style={{ fontFamily: 'Poppins, sans-serif' }}
>
<Bot className="w-4 h-4 text-[#F97316]" />
@@ -105,25 +93,6 @@ export default function Home() {
</motion.button>
</Link>
</motion.div>
{/* Trust Badges */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.8, delay: 0.5 }}
className="flex flex-wrap justify-center gap-6 text-slate-300 border-t border-white/20 pt-6 max-w-lg w-full"
>
{[
{ icon: CheckCircle, text: 'Official Portal' },
{ icon: Zap, text: 'Instant AI Support' },
{ icon: Shield, text: 'Student Verified' },
].map((badge, i) => (
<div key={i} className="flex items-center gap-1.5 text-xs font-medium" style={{ fontFamily: 'Inter, sans-serif' }}>
<badge.icon className="w-4 h-4 text-[#F97316]" />
<span>{badge.text}</span>
</div>
))}
</motion.div>
</motion.div>
</section>
</LazyVideoHero>

View File

@@ -1,7 +1,7 @@
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 } 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 } from 'lucide-react';
import SectionTitle from '@/components/SectionTitle/SectionTitle';
import { getBackendUrl } from '@/lib/utils';
import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer';
@@ -1432,6 +1432,28 @@ 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 ? (
(() => {
const TOOLKIT_MAP: Record<string, { categories: typeof CS_TOOLS_CATEGORIES; label: string }> = {

View File

@@ -579,6 +579,7 @@ def telegram_polling_thread():
if text == "/start":
welcome_text = (
f"👋 *Welcome to the RIT Chatbot 24/7!*\n\n"
f"⚠️ *Please note: Answers generated by AI may occasionally be inaccurate or wrong. Always verify critical academic or administrative details with official campus sources.*\n\n"
f"I can help you answer any questions about RIT Chennai — courses, hostels, transport, sports, and more.\n\n"
f"🚀 *Developer Collaboration:* Type `/collab` to post your project idea!\n"
f"🗑️ *Remove Request:* Type `/remove` to cancel your active requests.\n\n"