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 ```bash
cd /var/www/freshers-hub/backend cd /var/www/freshers-hub/backend
chmod +x mvnw 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; package com.rit.portal.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DriverLocationUpdate { public class DriverLocationUpdate {
private Double latitude; private Double latitude;
private Double longitude; private Double longitude;
private String pin; 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 { 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 = [ const quickLinks = [
{ label: 'Home', path: '/' }, { label: 'Home', path: '/' },
{ label: 'Notes & PYQs', path: '/notes' }, { label: 'Notes & PYQs', path: '/notes' },
{ label: 'Chatbot', path: '/ai-assistant' }, { label: 'RIT Chatbot', path: '/ai-assistant' },
{ label: 'Campus Map', path: '/campus' }, { label: '3D Campus Map', path: '/campus' },
{ label: 'Bus Routes', path: '/bus-routes' }, { label: 'Bus Routes', path: '/bus-routes' },
{ label: 'Faculty Directory', path: '/faculty' }, { label: 'Faculty Directory', path: '/faculty' },
{ label: 'Events', path: '/events' }, { label: 'Events', path: '/events' },
{ label: 'Community', path: '/community' }, { label: 'Community', path: '/community' },
{ label: 'Dev Collab', path: '/collab' }, { label: 'Dev Hub', 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: '#' },
]; ];
export default function Footer() { export default function Footer() {
@@ -49,7 +40,7 @@ export default function Footer() {
{/* Main Footer */} {/* Main Footer */}
<div className="container-custom py-14"> <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 */} {/* Brand */}
<div> <div>
<div className="flex items-center gap-2.5 mb-4"> <div className="flex items-center gap-2.5 mb-4">
@@ -65,68 +56,34 @@ export default function Footer() {
</div> </div>
</div> </div>
<p className="text-slate-400 text-sm leading-relaxed mb-5" style={{ fontFamily: 'Inter, sans-serif' }}> <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> </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> </div>
{/* Quick Links */} {/* Quick Links */}
<div> <div>
<h4 className="text-white font-semibold mb-4 text-sm uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}> <h4 className="text-white font-semibold mb-4 text-sm uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}>
Quick Links Quick Navigation
</h4> </h4>
<ul className="space-y-2.5"> <div className="grid grid-cols-2 gap-2">
{quickLinks.map((link) => ( {quickLinks.map((link) => (
<li key={link.path}>
<Link <Link
key={link.path}
to={link.path} to={link.path}
className="text-slate-400 hover:text-[#F97316] text-sm transition-colors flex items-center gap-1.5 group" 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' }} style={{ fontFamily: 'Inter, sans-serif' }}
> >
<span className="w-1 h-1 rounded-full bg-[#F97316] opacity-0 group-hover:opacity-100 transition-opacity" /> <span className="w-1 h-1 rounded-full bg-[#F97316] opacity-0 group-hover:opacity-100 transition-opacity" />
{link.label} {link.label}
</Link> </Link>
</li>
))} ))}
</ul>
</div> </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 */} {/* Contact */}
<div> <div>
<h4 className="text-white font-semibold mb-4 text-sm uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}> <h4 className="text-white font-semibold mb-4 text-sm uppercase tracking-wider" style={{ fontFamily: 'Poppins, sans-serif' }}>
Contact Campus Location & Contact
</h4> </h4>
<ul className="space-y-3"> <ul className="space-y-3">
<li className="flex items-start gap-3 text-slate-400 text-sm" style={{ fontFamily: 'Inter, sans-serif' }}> <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', id: '1',
role: 'assistant', 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(), timestamp: new Date().toISOString(),
}, },
]; ];

View File

@@ -32,34 +32,39 @@ const BLUEPRINT_LEGEND = [
]; ];
const LOCATION_SPOTS: LocationSpot[] = [ 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: 'Girls Hostel', x: 16.0, y: 8.5, 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: 'Playground', x: 40.0, y: 11.0, category: 'Amenity', desc: 'Main Sports & Athletic Field', area: 'Top Center' },
{ name: 'Canteen', x: 63.5, y: 13.5, category: 'Amenity', desc: 'Food Court & Refreshments', area: 'North Center' }, { name: 'Canteen', x: 67.0, y: 8.5, category: 'Amenity', desc: 'Food Court & Refreshments', area: 'Top Right' },
{ name: 'Statue', x: 61.0, y: 26.0, category: 'Amenity', desc: 'Landmark Monument', area: 'North Center' }, { name: 'Steve Jobs Block', x: 16.0, y: 21.0, category: 'Admin / Facility', desc: 'Auditorium, Computer Labs & Staff Rooms', area: 'West Wing' },
{ name: 'Boys Mess', x: 87.8, y: 10.5, category: 'Amenity', desc: 'Ground Floor Dining', area: 'Top Right' }, { name: 'Girls Mess', x: 14.5, y: 31.0, category: 'Hostel / Mess', desc: 'Dedicated Dining Hall for Women', area: 'West Wing' },
{ name: 'Staff Mess', x: 87.8, y: 22.0, category: 'Amenity', desc: 'First Floor Dining', area: 'Top Right' }, { name: 'MEC Lab', x: 14.0, y: 39.5, category: 'Lab / Academic', desc: 'Mechanical Engineering Laboratory', area: 'West Wing' },
{ name: 'C Block', x: 87.8, y: 41.0, category: 'C Block', desc: 'Labs, Classrooms, Auditorium & Staff Rooms', area: 'East Block' }, { name: 'EPL Lab', x: 13.0, y: 47.5, category: 'Lab / Academic', desc: 'Engineering Practices Laboratory', area: 'West Wing' },
{ name: 'Steve Jobs Block', x: 8.1, y: 38.5, category: 'Admin / Facility', desc: 'Auditorium, Labs & Staff Rooms', 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: 'Girls Mess', x: 8.1, y: 53.0, category: 'Amenity', desc: 'Dedicated Dining Hall for Women', area: 'West Wing' }, { name: 'Astronaut Statue', x: 51.0, y: 23.0, category: 'Amenity', desc: 'Iconic Landmark Monument', area: 'Central Park' },
{ name: 'EPL Lab', x: 8.1, y: 65.5, category: 'Lab / Academic', desc: 'Engineering Practices Laboratory', area: 'South West' }, { name: 'Campus Centre', x: 67.0, y: 23.0, category: 'Admin / Facility', desc: 'Student Activity & Administrative Center', area: 'North East' },
{ name: 'B Block', x: 32.5, y: 55.0, category: 'B Block', desc: 'Labs, Classrooms & Faculty Rooms', area: 'Central West' }, { name: 'Hut', x: 70.0, y: 37.0, category: 'Amenity', desc: 'Student Discussion & Rest Area', area: 'Central East' },
{ name: 'Hut', x: 62.7, y: 42.5, category: 'Amenity', desc: 'Student Discussion & Rest Area', area: 'Central Green' }, { name: 'Homi Jehangir Bhabha Block', x: 87.0, y: 24.0, category: 'A Block', desc: 'Science & Physics Research Block', area: 'East Wing' },
{ 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: '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: 'RSB Block', x: 24.0, y: 81.5, category: 'Amenity', desc: 'Library, Auditorium & Accounts Room', area: 'South West' }, { 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: 'Side Parking', x: 5.5, y: 85.5, category: 'Parking Area', desc: 'Visitor & Staff Parking Zone', area: 'South West' }, { name: 'C Block', x: 87.0, y: 38.0, category: 'C Block', desc: 'Labs, Classrooms & Staff Rooms', area: 'East Wing' },
{ name: 'Arcade', x: 41.5, y: 72.8, category: 'Amenity', desc: 'Student Hub & Stores', area: 'South Central' }, { name: 'Alan Turing Block', x: 77.0, y: 53.0, category: 'Lab / Academic', desc: 'Computer Science & AI Labs', area: 'East Wing' },
{ name: 'Security Booth', x: 45.9, y: 88.5, category: 'Amenity', desc: 'Main Gate Security Checkpoint', area: 'South Entrance' }, { name: 'Arcade', x: 35.0, y: 57.0, category: 'Amenity', desc: 'Student Hub & Stores', area: 'Central South' },
{ name: 'Parking Area', x: 73.0, y: 86.0, category: 'Parking Area', desc: 'Two-Wheeler & Four-Wheeler Parking', area: 'South East' }, { name: 'Green Building', x: 23.0, y: 71.0, category: 'Admin / Facility', desc: 'Eco-Friendly Academic Complex & Library', area: 'South West' },
{ name: 'Main Entrance', x: 51.8, y: 92.5, category: 'Amenity', desc: 'Primary Campus Security Gate', area: 'South Entrance' }, { 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[]> = { const CATEGORY_MAP_SPOTS: Record<string, string[]> = {
dept: ['A Block', 'B Block', 'C Block'], dept: ['Homi Jehangir Bhabha Block', 'Nikola Tesla Block', 'C Block', 'Steve Jobs Block', 'Alan Turing Block', 'Green Building'],
library: ['RSB Block'], library: ['Green Building'],
labs: ['Steve Jobs Block', 'A Block', 'B Block', 'C Block', 'EPL Lab'], labs: ['MEC Lab', 'EPL Lab', 'Steve Jobs Block', 'Alan Turing Block', 'Nikola Tesla Block', 'C Block'],
hostel: ['Girls Hostel'], hostel: ['Girls Hostel', 'Boys Mess'],
canteen: ['Canteen', 'Staff Mess', 'Girls Mess', 'Boys Mess'], canteen: ['Canteen', 'Girls Mess', 'Boys Mess', 'Staff Mess', 'Arcade'],
auditorium: ['Steve Jobs Block', 'C Block', 'RSB Block'], auditorium: ['Steve Jobs Block', 'Campus Centre'],
sports: ['Playground'], sports: ['Playground'],
}; };

View File

@@ -1,6 +1,6 @@
import { useState, useMemo } from 'react'; import { useState, useMemo } from 'react';
import { motion } from 'framer-motion'; 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 FacultyCard from '@/components/FacultyCard/FacultyCard';
import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer'; import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer';
import { FACULTY_DATA, DEPARTMENTS } from '@/constants'; import { FACULTY_DATA, DEPARTMENTS } from '@/constants';
@@ -64,6 +64,27 @@ export default function Faculty() {
</div> </div>
<div className="container-custom py-8 space-y-8"> <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 */} {/* Faculty Hero Section */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 items-stretch"> <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"> <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" className="container-custom relative z-20 flex flex-col items-center text-center px-4"
style={{ opacity: heroOpacity, y: heroY }} 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 */} {/* Heading */}
<motion.h1 <motion.h1
initial={{ opacity: 0, y: 15 }} initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 }} transition={{ duration: 0.6, delay: 0.1 }}
className="text-white text-3xl md:text-4xl font-light mb-1" className="text-3xl md:text-5xl font-medium tracking-wide mb-2"
style={{ fontFamily: 'Playfair Display, serif', textShadow: '0 2px 10px rgba(0,0,0,0.5)' }} style={{ color: '#FFFFFF', fontFamily: 'Playfair Display, serif', textShadow: '0 2px 14px rgba(0,0,0,0.95)' }}
> >
Welcome to Welcome to
</motion.h1> </motion.h1>
@@ -54,8 +42,8 @@ export default function Home() {
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.2 }} 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" className="text-5xl md:text-7xl font-black leading-tight mb-6"
style={{ fontFamily: 'Playfair Display, serif', filter: 'drop-shadow(0 4px 12px rgba(249, 115, 22, 0.45))' }} style={{ color: '#FFFFFF', fontFamily: 'Playfair Display, serif', textShadow: '0 4px 24px rgba(0,0,0,0.95)' }}
> >
RIT Freshers Hub RIT Freshers Hub
</motion.h2> </motion.h2>
@@ -64,7 +52,7 @@ export default function Home() {
initial={{ opacity: 0, y: 15 }} initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.3 }} 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' }} 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. 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 }} initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.4 }} 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"> <a href="#built-for-freshers">
<motion.button <motion.button
@@ -97,7 +85,7 @@ export default function Home() {
<motion.button <motion.button
whileHover={{ scale: 1.04, borderColor: '#F97316', backgroundColor: 'rgba(255,255,255,0.2)' }} whileHover={{ scale: 1.04, borderColor: '#F97316', backgroundColor: 'rgba(255,255,255,0.2)' }}
whileTap={{ scale: 0.96 }} 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' }} style={{ fontFamily: 'Poppins, sans-serif' }}
> >
<Bot className="w-4 h-4 text-[#F97316]" /> <Bot className="w-4 h-4 text-[#F97316]" />
@@ -105,25 +93,6 @@ export default function Home() {
</motion.button> </motion.button>
</Link> </Link>
</motion.div> </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> </motion.div>
</section> </section>
</LazyVideoHero> </LazyVideoHero>

View File

@@ -1,7 +1,7 @@
import { useState, useRef, useEffect } from 'react'; import { useState, useRef, useEffect } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { motion } from 'framer-motion'; 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 SectionTitle from '@/components/SectionTitle/SectionTitle';
import { getBackendUrl } from '@/lib/utils'; import { getBackendUrl } from '@/lib/utils';
import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer'; import { StaggerContainer, StaggerItem } from '@/components/AnimatedContainer/AnimatedContainer';
@@ -1432,6 +1432,28 @@ export default function Notes() {
)} )}
<div className="container-custom py-10"> <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 ? ( {selectedToolkit ? (
(() => { (() => {
const TOOLKIT_MAP: Record<string, { categories: typeof CS_TOOLS_CATEGORIES; label: string }> = { 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": if text == "/start":
welcome_text = ( welcome_text = (
f"👋 *Welcome to the RIT Chatbot 24/7!*\n\n" 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"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"🚀 *Developer Collaboration:* Type `/collab` to post your project idea!\n"
f"🗑️ *Remove Request:* Type `/remove` to cancel your active requests.\n\n" f"🗑️ *Remove Request:* Type `/remove` to cancel your active requests.\n\n"