├── linux ├── .gitignore ├── main.cc ├── flutter │ ├── generated_plugin_registrant.h │ ├── generated_plugins.cmake │ ├── generated_plugin_registrant.cc │ └── CMakeLists.txt ├── my_application.h └── my_application.cc ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── _ │ │ │ ├── 114.png │ │ │ ├── 120.png │ │ │ ├── 180.png │ │ │ ├── 29.png │ │ │ ├── 40.png │ │ │ ├── 57.png │ │ │ ├── 58.png │ │ │ ├── 60.png │ │ │ ├── 80.png │ │ │ ├── 87.png │ │ │ └── 1024.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── RunnerTests │ └── RunnerTests.swift └── .gitignore ├── .eslintrc.json ├── macos ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Runner │ ├── Configs │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── Warnings.xcconfig │ │ └── AppInfo.xcconfig │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_64.png │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_512.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Release.entitlements │ ├── DebugProfile.entitlements │ ├── MainFlutterWindow.swift │ └── Info.plist ├── .gitignore ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme └── RunnerTests │ └── RunnerTests.swift ├── public └── CSMS.png ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── manifest.json └── index.html ├── src ├── app │ ├── favicon.ico │ ├── page.jsx │ ├── api │ │ ├── payments │ │ │ └── route.js │ │ ├── auth │ │ │ └── [...nextauth] │ │ │ │ └── route.js │ │ ├── users │ │ │ └── balance │ │ │ │ ├── getTransactions │ │ │ │ └── route.js │ │ │ │ ├── getBalance │ │ │ │ └── route.js │ │ │ │ └── updateBalance │ │ │ │ └── route.js │ │ └── verify │ │ │ └── route.js │ ├── layout.jsx │ └── globals.css ├── lib │ ├── utils.js │ └── mongodb.js ├── components │ ├── AuthProvider.js │ ├── ui │ │ ├── skeleton.jsx │ │ ├── label.jsx │ │ ├── input.jsx │ │ ├── progress.jsx │ │ ├── separator.jsx │ │ ├── toaster.jsx │ │ ├── checkbox.jsx │ │ ├── badge.jsx │ │ ├── avatar.jsx │ │ ├── tooltip.jsx │ │ ├── radio-group.jsx │ │ ├── scroll-area.jsx │ │ ├── card.jsx │ │ ├── topbar.jsx │ │ ├── button.jsx │ │ ├── drawer.jsx │ │ ├── dialog.jsx │ │ └── toast.jsx │ └── HomeContent.jsx └── hooks │ ├── use-media-query.js │ └── use-toast.js ├── assets ├── images │ ├── CSMS.png │ ├── mongodb.png │ ├── appwrite.png │ ├── google_logo.png │ ├── CSMS_coloured.png │ └── CSMS_blackandwhite.png └── screenshots │ ├── admin.png │ ├── wallet.png │ └── dashboard.png ├── jsconfig.json ├── next.config.mjs ├── .vscode └── settings.json ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── csms │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── windows ├── runner │ ├── resources │ │ └── app_icon.ico │ ├── resource.h │ ├── utils.h │ ├── runner.exe.manifest │ ├── flutter_window.h │ ├── main.cpp │ ├── CMakeLists.txt │ ├── utils.cpp │ ├── flutter_window.cpp │ ├── Runner.rc │ └── win32_window.h ├── .gitignore ├── flutter │ ├── generated_plugin_registrant.h │ ├── generated_plugins.cmake │ ├── generated_plugin_registrant.cc │ └── CMakeLists.txt └── CMakeLists.txt ├── postcss.config.mjs ├── devtools_options.yaml ├── lib ├── helper │ ├── validate_email.dart │ ├── get_register_id.dart │ ├── database │ │ ├── db_service.dart │ │ ├── threed_print_db.dart │ │ ├── lab_permission_db.dart │ │ ├── lost_id_db.dart │ │ ├── vehicle_pass_db.dart │ │ ├── leave_form_db.dart │ │ └── vending_db.dart │ ├── choose_navbar.dart │ ├── config.dart │ ├── navigate_users.dart │ └── data │ │ ├── labs.dart │ │ └── vending_items.dart ├── presentation │ ├── screens │ │ └── common │ │ │ ├── landing.dart │ │ │ └── error.dart │ ├── widgets │ │ ├── bottom_navbar_printer.dart │ │ ├── bottom_navbar_admin.dart │ │ ├── bottom_navbar.dart │ │ └── bottom_navbar_vending.dart │ └── providers │ │ ├── theme_provider.dart │ │ └── vending_provider.dart ├── main.dart └── models │ ├── print_request.dart │ ├── gate_pass.dart │ └── pink_slip.dart ├── components.json ├── .gitignore ├── test └── widget_test.dart ├── analysis_options.yaml ├── package.json ├── README.md ├── .metadata └── tailwind.config.js /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /public/CSMS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/public/CSMS.png -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/web/favicon.png -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/src/app/favicon.ico -------------------------------------------------------------------------------- /assets/images/CSMS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/images/CSMS.png -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/web/icons/Icon-512.png -------------------------------------------------------------------------------- /assets/images/mongodb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/images/mongodb.png -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /assets/images/appwrite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/images/appwrite.png -------------------------------------------------------------------------------- /assets/screenshots/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/screenshots/admin.png -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /assets/images/google_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/images/google_logo.png -------------------------------------------------------------------------------- /assets/screenshots/wallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/screenshots/wallet.png -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /assets/images/CSMS_coloured.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/images/CSMS_coloured.png -------------------------------------------------------------------------------- /assets/screenshots/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/screenshots/dashboard.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.ignoreCMakeListsMissing": true, 3 | "java.configuration.updateBuildConfiguration": "interactive" 4 | } 5 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/images/CSMS_blackandwhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/assets/images/CSMS_blackandwhite.png -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/lib/utils.js: -------------------------------------------------------------------------------- 1 | import { clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/114.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/120.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/180.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/57.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/58.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/60.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/80.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/87.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/_/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/_/1024.png -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/csms/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package me.xditya.csms 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xditya/CampusServicesManagementSystem/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /devtools_options.yaml: -------------------------------------------------------------------------------- 1 | description: This file stores settings for Dart & Flutter DevTools. 2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states 3 | extensions: 4 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/AuthProvider.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { SessionProvider } from "next-auth/react"; 4 | 5 | export const AuthProvider = ({ children }) => { 6 | return {children}; 7 | }; 8 | -------------------------------------------------------------------------------- /lib/helper/validate_email.dart: -------------------------------------------------------------------------------- 1 | bool validateEmail(String email) { 2 | // #TODO: add checks for admin accounts 3 | if (email.endsWith('@mbcet.ac.in') || email.endsWith("@xditya.me")) { 4 | return true; 5 | } else { 6 | return false; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/components/ui/skeleton.jsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }) { 7 | return ( 8 | (
) 11 | ); 12 | } 13 | 14 | export { Skeleton } 15 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/helper/get_register_id.dart: -------------------------------------------------------------------------------- 1 | String getRegisterIdFromEmail(String email) { 2 | List emailParts = email.split('@'); 3 | if (emailParts.length > 1) { 4 | List idParts = emailParts[0].split('.'); 5 | if (idParts.length > 1) { 6 | return idParts[1].toUpperCase(); 7 | } 8 | } 9 | return 'Not Applicable'; 10 | } 11 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/page.jsx: -------------------------------------------------------------------------------- 1 | import HomeContent from "@/components/HomeContent"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 |
7 |

8 | Campus Services Management System 9 |

10 | 11 |
12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": false, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lib/helper/database/db_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/helper/config.dart'; 2 | import 'package:mongo_dart/mongo_dart.dart'; 3 | 4 | class DBService { 5 | static final DBService _instance = DBService._internal(); 6 | late final Db db; 7 | 8 | factory DBService() => _instance; 9 | 10 | DBService._internal(); 11 | 12 | Future connect() async { 13 | final url = MONGODB_URL; 14 | db = await Db.create(url); 15 | await db.open(); 16 | } 17 | 18 | bool get isConnected => db.state == State.open; 19 | } 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/hooks/use-media-query.js: -------------------------------------------------------------------------------- 1 | // hooks/use-media-query.ts 2 | import { useState, useEffect } from "react"; 3 | 4 | export function useMediaQuery(query) { 5 | const [matches, setMatches] = useState(false); 6 | 7 | useEffect(() => { 8 | const media = window.matchMedia(query); 9 | if (media.matches !== matches) { 10 | setMatches(media.matches); 11 | } 12 | const listener = () => setMatches(media.matches); 13 | media.addListener(listener); 14 | return () => media.removeListener(listener); 15 | }, [matches, query]); 16 | 17 | return matches; 18 | } 19 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.google.gms:google-services:4.4.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | 19 | rootProject.buildDir = "../build" 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(":app") 25 | } 26 | 27 | tasks.register("clean", Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /src/app/api/payments/route.js: -------------------------------------------------------------------------------- 1 | import Razorpay from "razorpay"; 2 | import { NextResponse } from "next/server"; 3 | 4 | const razorpay = new Razorpay({ 5 | key_id: process.env.RAZORPAY_KEY_ID, 6 | key_secret: process.env.RAZORPAY_KEY_SECRET, 7 | }); 8 | 9 | export async function POST(request) { 10 | const { amount, currency } = await request.json(); 11 | 12 | var options = { 13 | amount: amount, 14 | currency: currency, 15 | receipt: "rcp1", 16 | }; 17 | const order = await razorpay.orders.create(options); 18 | console.log(order); 19 | return NextResponse.json({ orderId: order.id }, { status: 200 }); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/ui/label.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva } from "class-variance-authority"; 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef(({ className, ...props }, ref) => ( 14 | 15 | )) 16 | Label.displayName = LabelPrimitive.Root.displayName 17 | 18 | export { Label } 19 | -------------------------------------------------------------------------------- /src/app/layout.jsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | import { AuthProvider } from "../components/AuthProvider"; 3 | import { Analytics } from "@vercel/analytics/react"; 4 | import { Toaster } from "../components/ui/toaster"; 5 | 6 | export const metadata = { 7 | title: "Campus Services Management System", 8 | description: "Manage your campus services efficiently", 9 | }; 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | 15 | {children} 16 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = csms 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = me.xditya.csms 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2024 me.xditya. All rights reserved. 15 | -------------------------------------------------------------------------------- /src/app/api/auth/[...nextauth]/route.js: -------------------------------------------------------------------------------- 1 | import NextAuth from "next-auth"; 2 | import GoogleProvider from "next-auth/providers/google"; 3 | 4 | const handler = NextAuth({ 5 | providers: [ 6 | GoogleProvider({ 7 | clientId: process.env.GOOGLE_CLIENT_ID, 8 | clientSecret: process.env.GOOGLE_CLIENT_SECRET, 9 | }), 10 | ], 11 | callbacks: { 12 | async signIn({ account, profile }) { 13 | if (account.provider === "google") { 14 | const emailDomain = profile.email.split("@")[1]; 15 | return emailDomain === "mbcet.ac.in"; 16 | } 17 | return true; 18 | }, 19 | }, 20 | }); 21 | 22 | export { handler as GET, handler as POST }; 23 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /src/components/ui/input.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Input = React.forwardRef(({ className, type, ...props }, ref) => { 6 | return ( 7 | () 15 | ); 16 | }) 17 | Input.displayName = "Input" 18 | 19 | export { Input } 20 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /lib/helper/choose_navbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:appwrite/models.dart'; 2 | import 'package:csms/presentation/widgets/bottom_navbar.dart'; 3 | import 'package:csms/presentation/widgets/bottom_navbar_admin.dart'; 4 | import 'package:csms/presentation/widgets/bottom_navbar_printer.dart'; 5 | import 'package:csms/presentation/widgets/bottom_navbar_vending.dart'; 6 | import 'package:flutter/material.dart'; 7 | 8 | Widget chooseNavBar(User session) { 9 | if (session.labels.contains("admin")) { 10 | return const BottomNavBarAdmin(); 11 | } else if (session.labels.contains("vending")) { 12 | return const BottomNavBarVending(); 13 | } else if (session.labels.contains("printer")) { 14 | return const BottomNavBarPrinter(); 15 | } 16 | return const BottomNavBar(); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/ui/progress.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as ProgressPrimitive from "@radix-ui/react-progress" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Progress = React.forwardRef(({ className, value, ...props }, ref) => ( 9 | 16 | 19 | 20 | )) 21 | Progress.displayName = ProgressPrimitive.Root.displayName 22 | 23 | export { Progress } 24 | -------------------------------------------------------------------------------- /src/components/ui/separator.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as SeparatorPrimitive from "@radix-ui/react-separator"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | 8 | const Separator = React.forwardRef( 9 | ( 10 | { className, orientation = "horizontal", decorative = true, ...props }, 11 | ref 12 | ) => ( 13 | 24 | ) 25 | ); 26 | Separator.displayName = SeparatorPrimitive.Root.displayName; 27 | 28 | export { Separator }; 29 | -------------------------------------------------------------------------------- /src/lib/mongodb.js: -------------------------------------------------------------------------------- 1 | import { MongoClient } from "mongodb"; 2 | 3 | const uri = process.env.MONGO_URI; 4 | 5 | let client; 6 | let clientPromise; 7 | 8 | if (!process.env.MONGO_URI) { 9 | throw new Error("Please add your Mongo URI to .env.local"); 10 | } 11 | 12 | if (process.env.NODE_ENV === "development") { 13 | // In development mode, use a global variable so that the value 14 | // is preserved across module reloads caused by HMR (Hot Module Replacement). 15 | if (!global._mongoClientPromise) { 16 | client = new MongoClient(uri); 17 | global._mongoClientPromise = client.connect(); 18 | } 19 | clientPromise = global._mongoClientPromise; 20 | } else { 21 | // In production mode, it's best to not use a global variable. 22 | client = new MongoClient(uri); 23 | clientPromise = client.connect(); 24 | } 25 | 26 | export default clientPromise; 27 | -------------------------------------------------------------------------------- /lib/helper/config.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: non_constant_identifier_names 2 | 3 | import 'package:appwrite/appwrite.dart'; 4 | import 'package:flutter_dotenv/flutter_dotenv.dart'; 5 | 6 | final APPWRITE_PROJECT_ID = dotenv.get('APPWRITE_PROJECT_ID'); 7 | final APPWRITE_API_ENDPOINT = dotenv.get('APPWRITE_API_ENDPOINT'); 8 | // final APPWRITE_DATABASE_ID = dotenv.get('APPWRITE_DATABASE_ID'); 9 | // final APPWRITE_USERDB_COLLECTION_ID = 10 | // dotenv.get('APPWRITE_USERDB_COLLECTION_ID'); 11 | final MONGODB_URL = dotenv.get('MONGODB_URL'); 12 | final RAZORPAY_API_KEY = dotenv.get('RAZORPAY_API_KEY'); 13 | 14 | Client client = 15 | Client().setProject(APPWRITE_PROJECT_ID).setEndpoint(APPWRITE_API_ENDPOINT); 16 | 17 | final account = Account(client); 18 | 19 | Databases databases = Databases(client); 20 | 21 | final NOTIF_WEBSOCKET = dotenv.get('NOTIF_WEBSOCKET'); 22 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | file_saver 7 | url_launcher_linux 8 | window_to_front 9 | ) 10 | 11 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 12 | ) 13 | 14 | set(PLUGIN_BUNDLED_LIBRARIES) 15 | 16 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 17 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 18 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 21 | endforeach(plugin) 22 | 23 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 26 | endforeach(ffi_plugin) 27 | -------------------------------------------------------------------------------- /src/components/ui/toaster.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useToast } from "@/hooks/use-toast"; 4 | import { 5 | Toast, 6 | ToastClose, 7 | ToastDescription, 8 | ToastProvider, 9 | ToastTitle, 10 | ToastViewport, 11 | } from "@/components/ui/toast"; 12 | 13 | export function Toaster() { 14 | const { toasts } = useToast(); 15 | 16 | return ( 17 | 18 | {toasts.map(function ({ id, title, description, action, ...props }) { 19 | return ( 20 | 21 |
22 | {title && {title}} 23 | {description && ( 24 | {description} 25 | )} 26 |
27 | {action} 28 | 29 |
30 | ); 31 | })} 32 | 33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | connectivity_plus 7 | file_saver 8 | firebase_core 9 | url_launcher_windows 10 | window_to_front 11 | ) 12 | 13 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 14 | ) 15 | 16 | set(PLUGIN_BUNDLED_LIBRARIES) 17 | 18 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 19 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 20 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 23 | endforeach(plugin) 24 | 25 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 26 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 27 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 28 | endforeach(ffi_plugin) 29 | -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | 45 | .env 46 | lib/firebase_options.dart 47 | firebase.json 48 | android/app/google_services.json -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.0" apply false 22 | // START: FlutterFire Configuration 23 | id "com.google.gms.google-services" version "4.3.15" apply false 24 | // END: FlutterFire Configuration 25 | id "org.jetbrains.kotlin.android" version "2.0.21" apply false 26 | } 27 | 28 | include ":app" 29 | -------------------------------------------------------------------------------- /lib/presentation/screens/common/landing.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/helper/config.dart'; 2 | import 'package:csms/helper/navigate_users.dart'; 3 | import 'package:csms/presentation/screens/common/login.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class LandingScreen extends StatelessWidget { 7 | const LandingScreen({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return FutureBuilder( 12 | future: account.get().then((snapshot) => snapshot), 13 | builder: (context, snapshot) { 14 | if (snapshot.connectionState == ConnectionState.waiting) { 15 | return const Scaffold( 16 | body: Center( 17 | child: CircularProgressIndicator(), 18 | ), 19 | ); 20 | } 21 | 22 | if (snapshot.hasError || (snapshot.data != null)) { 23 | return const LoginScreen(); 24 | } 25 | naviagateUsers(context, snapshot.data!); 26 | return Container(); 27 | }, 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/api/users/balance/getTransactions/route.js: -------------------------------------------------------------------------------- 1 | import clientPromise from "@/lib/mongodb"; 2 | import { NextResponse } from "next/server"; 3 | 4 | export async function POST(request) { 5 | try { 6 | const { email } = await request.json(); 7 | 8 | const client = await clientPromise; 9 | const db = client.db("CampusServicesManagementSystem"); 10 | const users = db.collection("users"); 11 | 12 | const user = await users.findOne({ email }); 13 | if (!user) { 14 | return NextResponse.json({ 15 | success: false, 16 | message: "User not found", 17 | data: null, 18 | }); 19 | } 20 | 21 | return NextResponse.json({ 22 | success: true, 23 | message: "Transactions retrieved successfully", 24 | data: { 25 | transactions: user.transactions || [], 26 | }, 27 | }); 28 | } catch (error) { 29 | return NextResponse.json({ 30 | success: false, 31 | message: "Failed to retrieve transactions", 32 | data: null, 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "csms", 3 | "short_name": "csms", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | void fl_register_plugins(FlPluginRegistry* registry) { 14 | g_autoptr(FlPluginRegistrar) file_saver_registrar = 15 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin"); 16 | file_saver_plugin_register_with_registrar(file_saver_registrar); 17 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 18 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 19 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 20 | g_autoptr(FlPluginRegistrar) window_to_front_registrar = 21 | fl_plugin_registry_get_registrar_for_plugin(registry, "WindowToFrontPlugin"); 22 | window_to_front_plugin_register_with_registrar(window_to_front_registrar); 23 | } 24 | -------------------------------------------------------------------------------- /src/components/ui/checkbox.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; 5 | import { Check } from "lucide-react"; 6 | 7 | import { cn } from "@/lib/utils"; 8 | 9 | const Checkbox = React.forwardRef(({ className, ...props }, ref) => ( 10 | 18 | 21 | 22 | 23 | 24 | )); 25 | Checkbox.displayName = CheckboxPrimitive.Root.displayName; 26 | 27 | export { Checkbox }; 28 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /src/app/api/verify/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import crypto from "crypto"; 3 | 4 | const generatedSignature = (razorpayOrderId, razorpayPaymentId) => { 5 | const keySecret = process.env.RAZORPAY_KEY_SECRET; 6 | if (!keySecret) { 7 | throw new Error( 8 | "Razorpay key secret is not defined in environment variables." 9 | ); 10 | } 11 | const sig = crypto 12 | .createHmac("sha256", keySecret) 13 | .update(razorpayOrderId + "|" + razorpayPaymentId) 14 | .digest("hex"); 15 | return sig; 16 | }; 17 | 18 | export async function POST(request) { 19 | const { orderCreationId, razorpayPaymentId, razorpaySignature } = 20 | await request.json(); 21 | 22 | const signature = generatedSignature(orderCreationId, razorpayPaymentId); 23 | if (signature !== razorpaySignature) { 24 | return NextResponse.json( 25 | { message: "payment verification failed", isOk: false }, 26 | { status: 400 } 27 | ); 28 | } 29 | return NextResponse.json( 30 | { message: "payment verified successfully", isOk: true }, 31 | { status: 200 } 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void RegisterPlugins(flutter::PluginRegistry* registry) { 16 | ConnectivityPlusWindowsPluginRegisterWithRegistrar( 17 | registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); 18 | FileSaverPluginRegisterWithRegistrar( 19 | registry->GetRegistrarForPlugin("FileSaverPlugin")); 20 | FirebaseCorePluginCApiRegisterWithRegistrar( 21 | registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); 22 | UrlLauncherWindowsRegisterWithRegistrar( 23 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 24 | WindowToFrontPluginRegisterWithRegistrar( 25 | registry->GetRegistrarForPlugin("WindowToFrontPlugin")); 26 | } 27 | -------------------------------------------------------------------------------- /src/components/ui/badge.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva } from "class-variance-authority"; 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const badgeVariants = cva( 7 | "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80", 13 | secondary: 14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 15 | destructive: 16 | "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80", 17 | outline: "text-foreground", 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: "default", 22 | }, 23 | } 24 | ) 25 | 26 | function Badge({ 27 | className, 28 | variant, 29 | ...props 30 | }) { 31 | return (
); 32 | } 33 | 34 | export { Badge, badgeVariants } 35 | -------------------------------------------------------------------------------- /lib/helper/navigate_users.dart: -------------------------------------------------------------------------------- 1 | // navigate users according to their labels 2 | 3 | import 'package:appwrite/models.dart'; 4 | import 'package:csms/presentation/router/router.dart'; 5 | import 'package:fluro/fluro.dart'; 6 | import 'package:flutter/material.dart'; 7 | 8 | void naviagateUsers(BuildContext context, User session) { 9 | if (session.labels.contains('admin')) { 10 | AppRouter.router.navigateTo( 11 | context, 12 | '/admin', 13 | transition: TransitionType.fadeIn, 14 | replace: true, 15 | ); 16 | } else if (session.labels.contains('vending')) { 17 | AppRouter.router.navigateTo( 18 | context, 19 | '/vending-dashboard', 20 | transition: TransitionType.fadeIn, 21 | replace: true, 22 | ); 23 | } else if (session.labels.contains('printer')) { 24 | AppRouter.router.navigateTo( 25 | context, 26 | '/printer-orders', 27 | transition: TransitionType.fadeIn, 28 | replace: true, 29 | ); 30 | } else { 31 | AppRouter.router.navigateTo( 32 | context, 33 | '/dashboard', 34 | transition: TransitionType.fadeIn, 35 | replace: true, 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:csms/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/components/ui/avatar.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AvatarPrimitive from "@radix-ui/react-avatar" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Avatar = React.forwardRef(({ className, ...props }, ref) => ( 9 | 13 | )) 14 | Avatar.displayName = AvatarPrimitive.Root.displayName 15 | 16 | const AvatarImage = React.forwardRef(({ className, ...props }, ref) => ( 17 | 21 | )) 22 | AvatarImage.displayName = AvatarPrimitive.Image.displayName 23 | 24 | const AvatarFallback = React.forwardRef(({ className, ...props }, ref) => ( 25 | 32 | )) 33 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName 34 | 35 | export { Avatar, AvatarImage, AvatarFallback } 36 | -------------------------------------------------------------------------------- /src/components/ui/tooltip.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as TooltipPrimitive from "@radix-ui/react-tooltip"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | 8 | const TooltipProvider = TooltipPrimitive.Provider; 9 | 10 | const Tooltip = TooltipPrimitive.Root; 11 | 12 | const TooltipTrigger = TooltipPrimitive.Trigger; 13 | 14 | const TooltipContent = React.forwardRef( 15 | ({ className, sideOffset = 4, ...props }, ref) => ( 16 | 25 | ) 26 | ); 27 | TooltipContent.displayName = TooltipPrimitive.Content.displayName; 28 | 29 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; 30 | -------------------------------------------------------------------------------- /lib/helper/data/labs.dart: -------------------------------------------------------------------------------- 1 | class Labs { 2 | final Map> departmentLabs = { 3 | 'CS': [ 4 | 'Programming Lab', 5 | 'Networks Lab', 6 | 'Hardware Lab', 7 | 'Project Lab', 8 | 'Research Lab' 9 | ], 10 | 'EC': [ 11 | 'Electronics Lab', 12 | 'Communication Lab', 13 | 'Microprocessor Lab', 14 | 'Digital Signal Processing Lab', 15 | 'VLSI Lab' 16 | ], 17 | 'EEE': [ 18 | 'Electrical Machines Lab', 19 | 'Power Electronics Lab', 20 | 'Control Systems Lab', 21 | 'High Voltage Lab', 22 | 'Power Systems Lab' 23 | ], 24 | 'ME': [ 25 | 'Manufacturing Lab', 26 | 'Thermodynamics Lab', 27 | 'Fluid Mechanics Lab', 28 | 'CAD/CAM Lab', 29 | 'Robotics Lab' 30 | ], 31 | 'CE': [ 32 | 'Structural Engineering Lab', 33 | 'Environmental Engineering Lab', 34 | 'Geotechnical Lab', 35 | 'Survey Lab', 36 | 'Material Testing Lab' 37 | ], 38 | 'EL': [ 39 | 'Biomedical Lab', 40 | 'Instrumentation Lab', 41 | 'Signal Processing Lab', 42 | 'Embedded Systems Lab', 43 | 'Medical Electronics Lab' 44 | ], 45 | 'ADMIN': [ 46 | 'Admin Lab', 47 | ] 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/components/ui/radio-group.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { CheckIcon } from "@radix-ui/react-icons" 5 | import * as RadioGroupPrimitive from "@radix-ui/react-radio-group" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const RadioGroup = React.forwardRef(({ className, ...props }, ref) => { 10 | return (); 11 | }) 12 | RadioGroup.displayName = RadioGroupPrimitive.Root.displayName 13 | 14 | const RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => { 15 | return ( 16 | ( 23 | 24 | 25 | 26 | ) 27 | ); 28 | }) 29 | RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName 30 | 31 | export { RadioGroup, RadioGroupItem } 32 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | csms 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /lib/presentation/widgets/bottom_navbar_printer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavBarPrinter extends StatelessWidget { 4 | const BottomNavBarPrinter({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | final currentRoute = ModalRoute.of(context)?.settings.name ?? ''; 9 | 10 | return NavigationBar( 11 | selectedIndex: _getSelectedIndex(currentRoute), 12 | onDestinationSelected: (index) { 13 | if (index != _getSelectedIndex(currentRoute)) { 14 | switch (index) { 15 | case 0: 16 | Navigator.pushReplacementNamed(context, '/printer-orders'); 17 | break; 18 | case 1: 19 | Navigator.pushReplacementNamed(context, '/profile'); 20 | break; 21 | } 22 | } 23 | }, 24 | destinations: const [ 25 | NavigationDestination( 26 | icon: Icon(Icons.print), 27 | label: 'Print Orders', 28 | ), 29 | NavigationDestination( 30 | icon: Icon(Icons.person), 31 | label: 'Profile', 32 | ), 33 | ], 34 | ); 35 | } 36 | 37 | int _getSelectedIndex(String currentRoute) { 38 | switch (currentRoute) { 39 | case '/printer-orders': 40 | return 0; 41 | case '/profile': 42 | return 1; 43 | default: 44 | return 0; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/helper/data/vending_items.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class VendingItem { 4 | final String id; 5 | final String name; 6 | final double price; 7 | final IconData icon; 8 | 9 | const VendingItem({ 10 | required this.id, 11 | required this.name, 12 | required this.price, 13 | required this.icon, 14 | }); 15 | } 16 | 17 | const List vendingItems = [ 18 | VendingItem( 19 | id: "1", 20 | name: "Parotta", 21 | price: 15.0, 22 | icon: Icons.flatware, 23 | ), 24 | VendingItem( 25 | id: "2", 26 | name: "Biriyani", 27 | price: 10.0, 28 | icon: Icons.rice_bowl, 29 | ), 30 | VendingItem( 31 | id: "3", 32 | name: "Chapatti", 33 | price: 25.0, 34 | icon: Icons.local_dining, 35 | ), 36 | VendingItem( 37 | id: "4", 38 | name: "Chicken Curry", 39 | price: 20.0, 40 | icon: Icons.restaurant, 41 | ), 42 | VendingItem( 43 | id: "5", 44 | name: "Beef Curry", 45 | price: 30.0, 46 | icon: Icons.lunch_dining, 47 | ), 48 | VendingItem( 49 | id: "6", 50 | name: "Fish Curry", 51 | price: 30.0, 52 | icon: Icons.set_meal, 53 | ), 54 | VendingItem( 55 | id: "7", 56 | name: "Veg Curry", 57 | price: 15.0, 58 | icon: Icons.eco, 59 | ), 60 | VendingItem( 61 | id: "8", 62 | name: "Meals", 63 | price: 50.0, 64 | icon: Icons.dinner_dining, 65 | ), 66 | ]; 67 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"csms", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /src/components/ui/scroll-area.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const ScrollArea = React.forwardRef(({ className, children, ...props }, ref) => ( 9 | 13 | 14 | {children} 15 | 16 | 17 | 18 | 19 | )) 20 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName 21 | 22 | const ScrollBar = React.forwardRef(({ className, orientation = "vertical", ...props }, ref) => ( 23 | 35 | 36 | 37 | )) 38 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName 39 | 40 | export { ScrollArea, ScrollBar } 41 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]} -------------------------------------------------------------------------------- /src/components/ui/card.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Card = React.forwardRef(({ className, ...props }, ref) => ( 6 |
10 | )) 11 | Card.displayName = "Card" 12 | 13 | const CardHeader = React.forwardRef(({ className, ...props }, ref) => ( 14 |
18 | )) 19 | CardHeader.displayName = "CardHeader" 20 | 21 | const CardTitle = React.forwardRef(({ className, ...props }, ref) => ( 22 |

26 | )) 27 | CardTitle.displayName = "CardTitle" 28 | 29 | const CardDescription = React.forwardRef(({ className, ...props }, ref) => ( 30 |

34 | )) 35 | CardDescription.displayName = "CardDescription" 36 | 37 | const CardContent = React.forwardRef(({ className, ...props }, ref) => ( 38 |

39 | )) 40 | CardContent.displayName = "CardContent" 41 | 42 | const CardFooter = React.forwardRef(({ className, ...props }, ref) => ( 43 |
47 | )) 48 | CardFooter.displayName = "CardFooter" 49 | 50 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "csms", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@auth/core": "^0.37.2", 13 | "@radix-ui/react-avatar": "^1.1.0", 14 | "@radix-ui/react-checkbox": "^1.1.2", 15 | "@radix-ui/react-dialog": "^1.1.1", 16 | "@radix-ui/react-dropdown-menu": "^2.1.1", 17 | "@radix-ui/react-hover-card": "^1.1.1", 18 | "@radix-ui/react-icons": "^1.3.0", 19 | "@radix-ui/react-label": "^2.1.0", 20 | "@radix-ui/react-progress": "^1.1.0", 21 | "@radix-ui/react-radio-group": "^1.2.0", 22 | "@radix-ui/react-scroll-area": "^1.1.0", 23 | "@radix-ui/react-separator": "^1.1.0", 24 | "@radix-ui/react-slot": "^1.1.0", 25 | "@radix-ui/react-tabs": "^1.1.0", 26 | "@radix-ui/react-toast": "^1.2.1", 27 | "@radix-ui/react-tooltip": "^1.1.3", 28 | "@vercel/analytics": "^1.3.1", 29 | "class-variance-authority": "^0.7.0", 30 | "clsx": "^2.1.1", 31 | "csms": "file:", 32 | "date-fns": "^4.1.0", 33 | "lucide-react": "^0.436.0", 34 | "mongodb": "^6.10.0", 35 | "next": "^14.2.15", 36 | "next-auth": "^4.24.10", 37 | "razorpay": "^2.9.4", 38 | "react": "^18", 39 | "react-dom": "^18", 40 | "tailwind-merge": "^2.5.2", 41 | "tailwindcss-animate": "^1.0.7", 42 | "vaul": "^0.9.2" 43 | }, 44 | "devDependencies": { 45 | "@types/node": "22.7.8", 46 | "@types/react": "18.3.11", 47 | "eslint": "^8", 48 | "eslint-config-next": "14.2.7", 49 | "postcss": "^8", 50 | "tailwindcss": "^3.4.1" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/components/ui/topbar.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; 4 | import Link from "next/link"; 5 | import { usePathname, useRouter } from "next/navigation"; 6 | import Image from "next/image"; 7 | 8 | function getInitials(name) { 9 | const words = name.split(" ").filter((word) => word.length > 0); 10 | if (words.length === 0) return ""; 11 | if (words.length === 1) return words[0][0].toUpperCase(); 12 | return (words[0][0] + words[words.length - 1][0]).toUpperCase(); 13 | } 14 | 15 | export const TopBar = ({ session, title }) => { 16 | const pathname = usePathname(); 17 | const router = useRouter(); 18 | 19 | const handleProfileClick = (e) => { 20 | e.preventDefault(); 21 | if (pathname === "/profile") { 22 | router.push("/dashboard"); 23 | } else { 24 | router.push("/profile"); 25 | } 26 | }; 27 | 28 | return ( 29 |
30 | 31 | CSMS 32 | 33 |
{title}
34 | 42 |
43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎓 Campus Services Management System (CSMS) 2 | 3 | A comprehensive mobile application to streamline and digitize various college services. 4 | 5 | ## 🌟 Key Features 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
💳 Digital Wallet
Secure payments & transactions
🖨️ Print Services
Document printing with QR tracking
🚗 Vehicle Pass
Digital pass management
🎫 ID Cards
Lost card replacement system
🏢 Lab Access
Permission & booking system
🤖 Smart Vending
QR-based purchases
19 | 20 | ## 📱 Screenshots 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | ## 🚀 Quick Start 30 | 31 | 1. Set up [websockets](https://github.com/xditya/csms-notifs/) & [appwrite](https://appwrite.io/) 32 | 2. Clone & install: 33 | ```bash 34 | git clone https://github.com/xditya/CampusServicesManagementSystem 35 | flutter pub get 36 | ``` 37 | 3. Configure `.env` and run: 38 | ```bash 39 | flutter run 40 | ``` 41 | 42 | ## 🔗 Related Projects 43 | - [Websockets](https://github.com/xditya/csms-notifs) 44 | - [Vending API](https://github.com/xditya/csms-api) 45 | - [Hardware (ESP32, ESP32CAM)](https://github.com/xditya/csms-hardware) 46 | 47 | --- 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 |
CSMSAppwriteMongoDB
57 |
58 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 17 | base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 18 | - platform: android 19 | create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 20 | base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 21 | - platform: ios 22 | create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 23 | base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 24 | - platform: linux 25 | create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 26 | base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 27 | - platform: macos 28 | create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 29 | base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 30 | - platform: web 31 | create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 32 | base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 33 | - platform: windows 34 | create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 35 | base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /src/app/api/users/balance/getBalance/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import { MongoClient } from "mongodb"; 3 | 4 | const uri = process.env.MONGO_URI; 5 | 6 | // Check if MONGO_URI is defined 7 | if (!uri) { 8 | console.error("MONGO_URI is not defined in the environment variables"); 9 | } 10 | 11 | export async function POST(request) { 12 | let client; 13 | try { 14 | if (!uri) { 15 | return NextResponse.json( 16 | { error: "Database connection string is not configured" }, 17 | { status: 500 } 18 | ); 19 | } 20 | 21 | // Validate the MongoDB connection string 22 | if (!uri.startsWith("mongodb://") && !uri.startsWith("mongodb+srv://")) { 23 | return NextResponse.json( 24 | { error: "Invalid MongoDB connection string" }, 25 | { status: 500 } 26 | ); 27 | } 28 | 29 | // Parse the request body 30 | const { email } = await request.json(); 31 | 32 | if (!email) { 33 | return NextResponse.json({ error: "Email is required" }, { status: 400 }); 34 | } 35 | 36 | client = new MongoClient(uri); 37 | await client.connect(); 38 | const database = client.db("CampusServicesManagementSystem"); 39 | const users = database.collection("users"); 40 | 41 | // Find the user by email 42 | const user = await users.findOne({ email }); 43 | 44 | if (!user) { 45 | return NextResponse.json({ balance: 0 }, { status: 200 }); 46 | } 47 | 48 | const balance = user.balance || 0; 49 | 50 | return NextResponse.json({ balance }, { status: 200 }); 51 | } catch (error) { 52 | console.error("Error getting balance:", error); 53 | return NextResponse.json( 54 | { error: "Failed to get balance", details: error.message }, 55 | { status: 500 } 56 | ); 57 | } finally { 58 | if (client) { 59 | await client.close(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/components/ui/button.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Slot } from "@radix-ui/react-slot"; 3 | import { cva } from "class-variance-authority"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90", 14 | destructive: 15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", 16 | outline: 17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", 18 | secondary: 19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", 20 | ghost: "hover:bg-accent hover:text-accent-foreground", 21 | link: "text-primary underline-offset-4 hover:underline", 22 | }, 23 | size: { 24 | default: "h-9 px-4 py-2", 25 | sm: "h-8 rounded-md px-3 text-xs", 26 | lg: "h-10 rounded-md px-8", 27 | icon: "h-9 w-9", 28 | }, 29 | }, 30 | defaultVariants: { 31 | variant: "default", 32 | size: "default", 33 | }, 34 | } 35 | ); 36 | 37 | const Button = React.forwardRef( 38 | ({ className, variant, size, asChild = false, ...props }, ref) => { 39 | const Comp = asChild ? Slot : "button"; 40 | return ( 41 | 46 | ); 47 | } 48 | ); 49 | Button.displayName = "Button"; 50 | 51 | export { Button, buttonVariants }; 52 | -------------------------------------------------------------------------------- /lib/presentation/screens/common/error.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ErrorScreen extends StatelessWidget { 4 | const ErrorScreen({super.key}); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Scaffold( 9 | body: Center( 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | children: [ 13 | const Icon( 14 | Icons.error_outline, 15 | size: 100, 16 | color: Colors.red, 17 | ), 18 | const SizedBox(height: 20), 19 | Text( 20 | '404', 21 | style: Theme.of(context).textTheme.displayLarge?.copyWith( 22 | fontWeight: FontWeight.bold, 23 | color: Theme.of(context).primaryColor, 24 | ), 25 | ), 26 | const SizedBox(height: 10), 27 | Text( 28 | 'Page Not Found', 29 | style: Theme.of(context).textTheme.headlineSmall, 30 | ), 31 | const SizedBox(height: 20), 32 | const Text( 33 | 'The page you are looking for does not exist.', 34 | style: TextStyle(fontSize: 16), 35 | ), 36 | const SizedBox(height: 40), 37 | ElevatedButton.icon( 38 | onPressed: () { 39 | Navigator.pop(context); 40 | }, 41 | icon: const Icon(Icons.navigate_before), 42 | label: const Text('Go back'), 43 | style: ElevatedButton.styleFrom( 44 | padding: const EdgeInsets.symmetric( 45 | horizontal: 30, 46 | vertical: 15, 47 | ), 48 | textStyle: const TextStyle(fontSize: 16), 49 | ), 50 | ), 51 | ], 52 | ), 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import connectivity_plus 9 | import device_info_plus 10 | import file_saver 11 | import firebase_core 12 | import firebase_messaging 13 | import flutter_local_notifications 14 | import flutter_web_auth 15 | import flutter_web_auth_2 16 | import google_sign_in_ios 17 | import package_info_plus 18 | import path_provider_foundation 19 | import pdf_render 20 | import url_launcher_macos 21 | import window_to_front 22 | 23 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 24 | ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) 25 | DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) 26 | FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin")) 27 | FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) 28 | FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) 29 | FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) 30 | FlutterWebAuthPlugin.register(with: registry.registrar(forPlugin: "FlutterWebAuthPlugin")) 31 | FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin")) 32 | FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) 33 | FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) 34 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 35 | SwiftPdfRenderPlugin.register(with: registry.registrar(forPlugin: "SwiftPdfRenderPlugin")) 36 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 37 | WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) 38 | } 39 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/presentation/router/router.dart'; 2 | import 'package:csms/presentation/screens/common/error.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_dotenv/flutter_dotenv.dart'; 5 | import 'package:csms/presentation/providers/theme_provider.dart'; 6 | import 'package:csms/helper/database/db_service.dart'; 7 | import 'services/notification_service.dart'; 8 | import 'services/websocket_service.dart'; 9 | import 'package:connectivity_plus/connectivity_plus.dart'; 10 | 11 | Future main() async { 12 | WidgetsFlutterBinding.ensureInitialized(); 13 | 14 | // Initialize connectivity plugin 15 | await Connectivity().checkConnectivity(); 16 | 17 | await dotenv.load(fileName: ".env"); 18 | await DBService().connect(); 19 | await NotificationService().init(); 20 | await WebSocketService().connect(); 21 | runApp(const MyApp()); 22 | } 23 | 24 | class MyApp extends StatefulWidget { 25 | const MyApp({super.key}); 26 | 27 | @override 28 | State createState() => _MyAppState(); 29 | } 30 | 31 | class _MyAppState extends State { 32 | ThemeMode _themeMode = ThemeMode.system; 33 | 34 | @override 35 | void initState() { 36 | super.initState(); 37 | AppRouter.defineRoutes(); 38 | } 39 | 40 | void _updateThemeMode(ThemeMode mode) { 41 | setState(() { 42 | _themeMode = mode; 43 | }); 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | return ThemeProvider( 49 | themeMode: _themeMode, 50 | updateTheme: _updateThemeMode, 51 | child: MaterialApp( 52 | title: 'Campus Services Management System', 53 | theme: AppTheme.lightTheme, 54 | darkTheme: AppTheme.darkTheme, 55 | themeMode: _themeMode, 56 | debugShowCheckedModeBanner: false, 57 | onGenerateRoute: AppRouter.router.generator, 58 | onUnknownRoute: (settings) => 59 | MaterialPageRoute(builder: (context) => const ErrorScreen()), 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | unsigned int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length == 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: ["class"], 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 13 | 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))' 14 | }, 15 | borderRadius: { 16 | lg: 'var(--radius)', 17 | md: 'calc(var(--radius) - 2px)', 18 | sm: 'calc(var(--radius) - 4px)' 19 | }, 20 | colors: { 21 | background: 'hsl(var(--background))', 22 | foreground: 'hsl(var(--foreground))', 23 | card: { 24 | DEFAULT: 'hsl(var(--card))', 25 | foreground: 'hsl(var(--card-foreground))' 26 | }, 27 | popover: { 28 | DEFAULT: 'hsl(var(--popover))', 29 | foreground: 'hsl(var(--popover-foreground))' 30 | }, 31 | primary: { 32 | DEFAULT: 'hsl(var(--primary))', 33 | foreground: 'hsl(var(--primary-foreground))' 34 | }, 35 | secondary: { 36 | DEFAULT: 'hsl(var(--secondary))', 37 | foreground: 'hsl(var(--secondary-foreground))' 38 | }, 39 | muted: { 40 | DEFAULT: 'hsl(var(--muted))', 41 | foreground: 'hsl(var(--muted-foreground))' 42 | }, 43 | accent: { 44 | DEFAULT: 'hsl(var(--accent))', 45 | foreground: 'hsl(var(--accent-foreground))' 46 | }, 47 | destructive: { 48 | DEFAULT: 'hsl(var(--destructive))', 49 | foreground: 'hsl(var(--destructive-foreground))' 50 | }, 51 | border: 'hsl(var(--border))', 52 | input: 'hsl(var(--input))', 53 | ring: 'hsl(var(--ring))', 54 | chart: { 55 | '1': 'hsl(var(--chart-1))', 56 | '2': 'hsl(var(--chart-2))', 57 | '3': 'hsl(var(--chart-3))', 58 | '4': 'hsl(var(--chart-4))', 59 | '5': 'hsl(var(--chart-5))' 60 | } 61 | } 62 | } 63 | }, 64 | plugins: [require("tailwindcss-animate")], 65 | }; 66 | -------------------------------------------------------------------------------- /lib/presentation/widgets/bottom_navbar_admin.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavBarAdmin extends StatefulWidget { 4 | const BottomNavBarAdmin({super.key}); 5 | 6 | @override 7 | BottomNavBarAdminState createState() => BottomNavBarAdminState(); 8 | } 9 | 10 | class BottomNavBarAdminState extends State { 11 | int currentPageIndex = 0; 12 | 13 | @override 14 | void initState() { 15 | super.initState(); 16 | } 17 | 18 | @override 19 | void didChangeDependencies() { 20 | super.didChangeDependencies(); 21 | _setCurrentPageIndex(); 22 | } 23 | 24 | void _setCurrentPageIndex() { 25 | final routeName = ModalRoute.of(context)?.settings.name; 26 | switch (routeName) { 27 | case '/admin': 28 | currentPageIndex = 0; 29 | break; 30 | case '/profile': 31 | currentPageIndex = 1; 32 | break; 33 | default: 34 | currentPageIndex = 0; 35 | } 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | const items = [ 41 | NavigationDestination( 42 | icon: Icon(Icons.home_outlined), 43 | selectedIcon: Icon(Icons.home), 44 | label: 'Admin Dashboard', 45 | ), 46 | NavigationDestination( 47 | icon: Icon(Icons.person_outline), 48 | selectedIcon: Icon(Icons.person), 49 | label: 'Profile', 50 | ), 51 | ]; 52 | return NavigationBar( 53 | destinations: items, 54 | selectedIndex: currentPageIndex, 55 | onDestinationSelected: (index) { 56 | _navigateToPage(context, index); 57 | }); 58 | } 59 | 60 | void _navigateToPage(BuildContext context, int index) { 61 | switch (index) { 62 | case 0: 63 | Navigator.pushNamedAndRemoveUntil(context, '/admin', (route) => false); 64 | break; 65 | case 1: 66 | Navigator.pushReplacementNamed(context, '/profile'); 67 | break; 68 | default: 69 | Navigator.pushNamedAndRemoveUntil(context, '/admin', (route) => false); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/app/api/users/balance/updateBalance/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import clientPromise from "@/lib/mongodb"; 3 | 4 | export async function POST(request) { 5 | let oldBalance = 0; 6 | try { 7 | const { email, amount } = await request.json(); 8 | const client = await clientPromise; 9 | const database = client.db("CampusServicesManagementSystem"); 10 | const users = database.collection("users"); 11 | 12 | // Find the user by email 13 | const user = await users.findOne({ email }); 14 | let newUser = false; 15 | 16 | if (!user) { 17 | newUser = true; 18 | } else { 19 | oldBalance = user.balance || 0; 20 | } 21 | 22 | const newBalance = oldBalance + amount; 23 | let result; 24 | // Update the user's balance 25 | if (newUser) { 26 | result = await users.insertOne({ 27 | email, 28 | balance: newBalance, 29 | transactions: [ 30 | { 31 | transactionType: amount > 0 ? "deposit" : "withdrawal", 32 | transactionAmount: Math.abs(amount), 33 | timestamp: new Date(), 34 | }, 35 | ], 36 | }); 37 | } else { 38 | result = await users.updateOne( 39 | { email }, 40 | { 41 | $set: { balance: newBalance }, 42 | $push: { 43 | transactions: { 44 | transactionType: amount > 0 ? "deposit" : "withdrawal", 45 | transactionAmount: Math.abs(amount), 46 | timestamp: new Date(), 47 | }, 48 | }, 49 | } 50 | ); 51 | } 52 | 53 | if (result.modifiedCount === 1 || result.insertedId) { 54 | return NextResponse.json( 55 | { message: "Wallet balance updated", newBalance }, 56 | { status: 200 } 57 | ); 58 | } else { 59 | throw new Error("Failed to update balance"); 60 | } 61 | } catch (error) { 62 | console.error("Error updating balance:", error); 63 | return NextResponse.json( 64 | { error: "Failed to update balance" }, 65 | { status: 500 } 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/models/print_request.dart: -------------------------------------------------------------------------------- 1 | import 'package:bson/bson.dart'; 2 | 3 | class PrintRequest { 4 | final String processName; 5 | final String fileName; 6 | final List fileBytes; 7 | final int numberOfPages; 8 | final int numberOfCopies; 9 | final bool isColorPrint; 10 | final bool isDoubleSided; 11 | final double totalCost; 12 | final DateTime createdAt; 13 | final String status; 14 | 15 | PrintRequest({ 16 | required this.processName, 17 | required this.fileName, 18 | required this.fileBytes, 19 | required this.numberOfPages, 20 | required this.numberOfCopies, 21 | required this.isColorPrint, 22 | required this.isDoubleSided, 23 | required this.totalCost, 24 | required this.createdAt, 25 | this.status = 'pending', 26 | }); 27 | 28 | factory PrintRequest.fromJson(Map json) { 29 | // Handle the case where the request is nested in a document 30 | final requestData = 31 | json.containsKey('requests') ? (json['requests'] as List).first : json; 32 | 33 | return PrintRequest( 34 | processName: requestData['processName'] as String, 35 | fileName: requestData['fileName'] as String, 36 | fileBytes: (requestData['fileBytes'] as BsonBinary).byteList, 37 | numberOfPages: requestData['numberOfPages'] as int, 38 | numberOfCopies: requestData['numberOfCopies'] as int, 39 | isColorPrint: requestData['isColorPrint'] as bool, 40 | isDoubleSided: requestData['isDoubleSided'] as bool, 41 | totalCost: requestData['totalCost'] as double, 42 | createdAt: DateTime.parse(requestData['createdAt'] as String), 43 | status: requestData['status'] as String, 44 | ); 45 | } 46 | 47 | Map toJson() => { 48 | 'processName': processName, 49 | 'fileName': fileName, 50 | 'fileBytes': BsonBinary.from(fileBytes), 51 | 'numberOfPages': numberOfPages, 52 | 'numberOfCopies': numberOfCopies, 53 | 'isColorPrint': isColorPrint, 54 | 'isDoubleSided': isDoubleSided, 55 | 'totalCost': totalCost, 56 | 'createdAt': createdAt.toIso8601String(), 57 | 'status': status, 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | def localProperties = new Properties() 9 | def localPropertiesFile = rootProject.file("local.properties") 10 | if (localPropertiesFile.exists()) { 11 | localPropertiesFile.withReader("UTF-8") { reader -> 12 | localProperties.load(reader) 13 | } 14 | } 15 | 16 | def flutterVersionCode = localProperties.getProperty("flutter.versionCode") 17 | if (flutterVersionCode == null) { 18 | flutterVersionCode = "1" 19 | } 20 | 21 | def flutterVersionName = localProperties.getProperty("flutter.versionName") 22 | if (flutterVersionName == null) { 23 | flutterVersionName = "1.0" 24 | } 25 | 26 | android { 27 | namespace = "me.xditya.csms" 28 | compileSdk = flutter.compileSdkVersion 29 | ndkVersion = flutter.ndkVersion 30 | 31 | compileOptions { 32 | sourceCompatibility = JavaVersion.VERSION_1_8 33 | targetCompatibility = JavaVersion.VERSION_1_8 34 | } 35 | 36 | defaultConfig { 37 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 38 | applicationId = "me.xditya.csms" 39 | // You can update the following values to match your application needs. 40 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 41 | minSdk = flutter.minSdkVersion 42 | targetSdk = flutter.targetSdkVersion 43 | versionCode = flutterVersionCode.toInteger() 44 | versionName = flutterVersionName 45 | multiDexEnabled true 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig = signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source = "../.." 59 | } 60 | 61 | dependencies { 62 | implementation 'com.google.android.gms:play-services-auth:19.2.0' 63 | } 64 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | CSMS 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | csms 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | CFBundleURLTypes 49 | 50 | 51 | CFBundleTypeRole 52 | Editor 53 | CFBundleURLName 54 | io.appwrite 55 | CFBundleURLSchemes 56 | 57 | appwrite-callback-[PROJECT_ID] 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | @layer utilities { 20 | .text-balance { 21 | text-wrap: balance; 22 | } 23 | } 24 | 25 | @layer base { 26 | :root { 27 | --background: 0 0% 100%; 28 | --foreground: 0 0% 3.9%; 29 | --card: 0 0% 100%; 30 | --card-foreground: 0 0% 3.9%; 31 | --popover: 0 0% 100%; 32 | --popover-foreground: 0 0% 3.9%; 33 | --primary: 0 0% 9%; 34 | --primary-foreground: 0 0% 98%; 35 | --secondary: 0 0% 96.1%; 36 | --secondary-foreground: 0 0% 9%; 37 | --muted: 0 0% 96.1%; 38 | --muted-foreground: 0 0% 45.1%; 39 | --accent: 0 0% 96.1%; 40 | --accent-foreground: 0 0% 9%; 41 | --destructive: 0 84.2% 60.2%; 42 | --destructive-foreground: 0 0% 98%; 43 | --border: 0 0% 89.8%; 44 | --input: 0 0% 89.8%; 45 | --ring: 0 0% 3.9%; 46 | --chart-1: 12 76% 61%; 47 | --chart-2: 173 58% 39%; 48 | --chart-3: 197 37% 24%; 49 | --chart-4: 43 74% 66%; 50 | --chart-5: 27 87% 67%; 51 | --radius: 0.5rem; 52 | } 53 | .dark { 54 | --background: 0 0% 3.9%; 55 | --foreground: 0 0% 98%; 56 | --card: 0 0% 3.9%; 57 | --card-foreground: 0 0% 98%; 58 | --popover: 0 0% 3.9%; 59 | --popover-foreground: 0 0% 98%; 60 | --primary: 0 0% 98%; 61 | --primary-foreground: 0 0% 9%; 62 | --secondary: 0 0% 14.9%; 63 | --secondary-foreground: 0 0% 98%; 64 | --muted: 0 0% 14.9%; 65 | --muted-foreground: 0 0% 63.9%; 66 | --accent: 0 0% 14.9%; 67 | --accent-foreground: 0 0% 98%; 68 | --destructive: 0 62.8% 30.6%; 69 | --destructive-foreground: 0 0% 98%; 70 | --border: 0 0% 14.9%; 71 | --input: 0 0% 14.9%; 72 | --ring: 0 0% 83.1%; 73 | --chart-1: 220 70% 50%; 74 | --chart-2: 160 60% 45%; 75 | --chart-3: 30 80% 55%; 76 | --chart-4: 280 65% 60%; 77 | --chart-5: 340 75% 55%; 78 | } 79 | } 80 | 81 | @layer base { 82 | * { 83 | @apply border-border; 84 | } 85 | body { 86 | @apply bg-background text-foreground; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /lib/presentation/widgets/bottom_navbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavBar extends StatefulWidget { 4 | const BottomNavBar({super.key}); 5 | 6 | @override 7 | BottomNavBarState createState() => BottomNavBarState(); 8 | } 9 | 10 | class BottomNavBarState extends State { 11 | int currentPageIndex = 0; 12 | 13 | @override 14 | void initState() { 15 | super.initState(); 16 | } 17 | 18 | @override 19 | void didChangeDependencies() { 20 | super.didChangeDependencies(); 21 | _setCurrentPageIndex(); 22 | } 23 | 24 | void _setCurrentPageIndex() { 25 | final routeName = ModalRoute.of(context)?.settings.name; 26 | switch (routeName) { 27 | case '/': 28 | currentPageIndex = 0; 29 | break; 30 | case '/wallet': 31 | currentPageIndex = 1; 32 | break; 33 | case '/profile': 34 | currentPageIndex = 2; 35 | break; 36 | default: 37 | currentPageIndex = 0; 38 | } 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | const items = [ 44 | NavigationDestination( 45 | icon: Icon(Icons.home_outlined), 46 | selectedIcon: Icon(Icons.home), 47 | label: 'Dashboard', 48 | ), 49 | NavigationDestination( 50 | icon: Icon(Icons.account_balance_wallet_outlined), 51 | selectedIcon: Icon(Icons.account_balance_wallet), 52 | label: 'Wallet', 53 | ), 54 | NavigationDestination( 55 | icon: Icon(Icons.person_outline), 56 | selectedIcon: Icon(Icons.person), 57 | label: 'Profile', 58 | ), 59 | ]; 60 | return NavigationBar( 61 | destinations: items, 62 | selectedIndex: currentPageIndex, 63 | onDestinationSelected: (index) { 64 | _navigateToPage(context, index); 65 | }); 66 | } 67 | 68 | void _navigateToPage(BuildContext context, int index) { 69 | switch (index) { 70 | case 0: 71 | Navigator.pushNamedAndRemoveUntil( 72 | context, '/dashboard', (route) => false); 73 | break; 74 | case 1: 75 | Navigator.pushReplacementNamed(context, '/wallet'); 76 | break; 77 | case 2: 78 | Navigator.pushReplacementNamed(context, '/profile'); 79 | break; 80 | default: 81 | Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/helper/database/threed_print_db.dart: -------------------------------------------------------------------------------- 1 | import 'package:mongo_dart/mongo_dart.dart'; 2 | 3 | class ThreeDPrintDB { 4 | final Db db; 5 | 6 | ThreeDPrintDB(this.db); 7 | 8 | Future createPrintRequest(Map request) async { 9 | try { 10 | final collection = db.collection('threed_print_requests'); 11 | await collection.insert(request); 12 | } catch (e) { 13 | throw Exception('Failed to create 3D print request: $e'); 14 | } 15 | } 16 | 17 | Future>> getRequestsByEmail(String email) async { 18 | try { 19 | final collection = db.collection('threed_print_requests'); 20 | final requests = await collection.find(where.eq('email', email)).toList(); 21 | return requests; 22 | } catch (e) { 23 | throw Exception('Failed to fetch 3D print requests: $e'); 24 | } 25 | } 26 | 27 | Future>> getPrintRequestsForApproval( 28 | String adminEmail) async { 29 | try { 30 | final collection = db.collection('threed_print_requests'); 31 | final selector = where 32 | .eq('status', 'pending') 33 | .and(where.oneFrom('approvalsRequired', [adminEmail])) 34 | .or(where.oneFrom('approvedBy', [adminEmail])) 35 | .or(where.oneFrom('rejectedBy', [adminEmail])) 36 | .sortBy('requestDate', descending: true); 37 | 38 | final requests = await collection.find(selector).toList(); 39 | return requests; 40 | } catch (e) { 41 | print('Error fetching requests: $e'); 42 | throw Exception('Failed to fetch 3D print requests: $e'); 43 | } 44 | } 45 | 46 | Future updatePrintRequest(String id, String adminEmail, String status, 47 | {String? comment}) async { 48 | try { 49 | final collection = db.collection('threed_print_requests'); 50 | final objectId = ObjectId.fromHexString(id); 51 | 52 | final update = { 53 | '\$set': { 54 | 'status': status, 55 | 'updatedAt': DateTime.now().toIso8601String(), 56 | if (comment != null) 'comment': comment, 57 | }, 58 | }; 59 | 60 | if (status == 'approved') { 61 | update['\$addToSet'] = {'approvedBy': adminEmail}; 62 | } else if (status == 'rejected') { 63 | update['\$addToSet'] = {'rejectedBy': adminEmail}; 64 | } 65 | 66 | await collection.updateOne( 67 | where.id(objectId), 68 | update, 69 | ); 70 | } catch (e) { 71 | throw Exception('Failed to update 3D print request: $e'); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/presentation/widgets/bottom_navbar_vending.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavBarVending extends StatefulWidget { 4 | const BottomNavBarVending({super.key}); 5 | 6 | @override 7 | BottomNavBarVendingState createState() => BottomNavBarVendingState(); 8 | } 9 | 10 | class BottomNavBarVendingState extends State { 11 | int currentPageIndex = 0; 12 | 13 | @override 14 | void initState() { 15 | super.initState(); 16 | } 17 | 18 | @override 19 | void didChangeDependencies() { 20 | super.didChangeDependencies(); 21 | _setCurrentPageIndex(); 22 | } 23 | 24 | void _setCurrentPageIndex() { 25 | final routeName = ModalRoute.of(context)?.settings.name; 26 | switch (routeName) { 27 | case '/vending-dashboard': 28 | currentPageIndex = 0; 29 | break; 30 | case '/vending-orders': 31 | currentPageIndex = 1; 32 | break; 33 | case '/profile': 34 | currentPageIndex = 2; 35 | break; 36 | default: 37 | currentPageIndex = 0; 38 | } 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | const items = [ 44 | NavigationDestination( 45 | icon: Icon(Icons.home_outlined), 46 | selectedIcon: Icon(Icons.home), 47 | label: 'Vending Dashboard', 48 | ), 49 | NavigationDestination( 50 | icon: Icon(Icons.list_outlined), 51 | selectedIcon: Icon(Icons.list), 52 | label: "Orders"), 53 | NavigationDestination( 54 | icon: Icon(Icons.person_outline), 55 | selectedIcon: Icon(Icons.person), 56 | label: 'Profile', 57 | ), 58 | ]; 59 | return NavigationBar( 60 | destinations: items, 61 | selectedIndex: currentPageIndex, 62 | onDestinationSelected: (index) { 63 | _navigateToPage(context, index); 64 | }); 65 | } 66 | 67 | void _navigateToPage(BuildContext context, int index) { 68 | switch (index) { 69 | case 0: 70 | Navigator.pushNamedAndRemoveUntil( 71 | context, '/vending-dashboard', (route) => false); 72 | break; 73 | case 1: 74 | Navigator.pushNamedAndRemoveUntil( 75 | context, '/vending-orders', (route) => false); 76 | break; 77 | case 2: 78 | Navigator.pushReplacementNamed(context, '/profile'); 79 | break; 80 | default: 81 | Navigator.pushNamedAndRemoveUntil( 82 | context, '/vending-dashboard', (route) => false); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/components/ui/drawer.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { Drawer as DrawerPrimitive } from "vaul" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Drawer = ({ 9 | shouldScaleBackground = true, 10 | ...props 11 | }) => ( 12 | 13 | ) 14 | Drawer.displayName = "Drawer" 15 | 16 | const DrawerTrigger = DrawerPrimitive.Trigger 17 | 18 | const DrawerPortal = DrawerPrimitive.Portal 19 | 20 | const DrawerClose = DrawerPrimitive.Close 21 | 22 | const DrawerOverlay = React.forwardRef(({ className, ...props }, ref) => ( 23 | 27 | )) 28 | DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName 29 | 30 | const DrawerContent = React.forwardRef(({ className, children, ...props }, ref) => ( 31 | 32 | 33 | 40 |
41 | {children} 42 | 43 | 44 | )) 45 | DrawerContent.displayName = "DrawerContent" 46 | 47 | const DrawerHeader = ({ 48 | className, 49 | ...props 50 | }) => ( 51 |
54 | ) 55 | DrawerHeader.displayName = "DrawerHeader" 56 | 57 | const DrawerFooter = ({ 58 | className, 59 | ...props 60 | }) => ( 61 |
62 | ) 63 | DrawerFooter.displayName = "DrawerFooter" 64 | 65 | const DrawerTitle = React.forwardRef(({ className, ...props }, ref) => ( 66 | 70 | )) 71 | DrawerTitle.displayName = DrawerPrimitive.Title.displayName 72 | 73 | const DrawerDescription = React.forwardRef(({ className, ...props }, ref) => ( 74 | 78 | )) 79 | DrawerDescription.displayName = DrawerPrimitive.Description.displayName 80 | 81 | export { 82 | Drawer, 83 | DrawerPortal, 84 | DrawerOverlay, 85 | DrawerTrigger, 86 | DrawerClose, 87 | DrawerContent, 88 | DrawerHeader, 89 | DrawerFooter, 90 | DrawerTitle, 91 | DrawerDescription, 92 | } 93 | -------------------------------------------------------------------------------- /src/components/HomeContent.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useSession } from "next-auth/react"; 4 | import { useRouter } from "next/navigation"; 5 | import { useEffect, useState } from "react"; 6 | import { Button } from "@/components/ui/button"; 7 | import { signIn, signOut } from "next-auth/react"; 8 | import { Loader2 } from "lucide-react"; 9 | import { 10 | Card, 11 | CardContent, 12 | CardDescription, 13 | CardHeader, 14 | CardTitle, 15 | } from "@/components/ui/card"; 16 | import { Progress } from "@/components/ui/progress"; 17 | 18 | export default function HomeContent() { 19 | const { data: session, status } = useSession(); 20 | const router = useRouter(); 21 | const [progress, setProgress] = useState(0); 22 | 23 | useEffect(() => { 24 | if (status === "authenticated") { 25 | let timer = setTimeout(() => { 26 | router.push("/dashboard"); 27 | }, 3000); // Redirect after 3 seconds 28 | 29 | // Simulate progress 30 | let interval = setInterval(() => { 31 | setProgress((prevProgress) => { 32 | if (prevProgress >= 100) { 33 | clearInterval(interval); 34 | return 100; 35 | } 36 | return prevProgress + 10; 37 | }); 38 | }, 300); 39 | 40 | return () => { 41 | clearTimeout(timer); 42 | clearInterval(interval); 43 | }; 44 | } 45 | }, [status, router]); 46 | 47 | if (status === "loading") { 48 | return ( 49 | 50 | 51 | 52 | 53 | 54 | ); 55 | } 56 | 57 | if (session) { 58 | return ( 59 | 60 | 61 | Welcome, {session.user.name} 62 | Redirecting to your dashboard... 63 | 64 | 65 |
66 | 67 |

68 | Loading your personalized dashboard 69 |

70 |
71 |
72 |
73 | ); 74 | } 75 | 76 | return ( 77 | 78 | 79 | Get Started 80 | Sign in to access campus services 81 | 82 | 83 | 86 | 87 | 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /lib/models/gate_pass.dart: -------------------------------------------------------------------------------- 1 | class GatePass { 2 | final String email; 3 | final String name; 4 | final String rollNo; 5 | final String branch; 6 | final String className; 7 | final String batch; 8 | final String reason; 9 | final String date; 10 | final String timeFrom; 11 | final String timeTo; 12 | final String advisor; 13 | final String? faculty; 14 | final bool includePrincipal; 15 | final List approvalsRequired; 16 | final List approvedBy; 17 | final List rejectedBy; 18 | final String status; 19 | final DateTime requestDate; 20 | 21 | GatePass({ 22 | required this.email, 23 | required this.name, 24 | required this.rollNo, 25 | required this.branch, 26 | required this.className, 27 | required this.batch, 28 | required this.reason, 29 | required this.date, 30 | required this.timeFrom, 31 | required this.timeTo, 32 | required this.advisor, 33 | this.faculty, 34 | required this.includePrincipal, 35 | required this.approvalsRequired, 36 | required this.approvedBy, 37 | required this.rejectedBy, 38 | required this.status, 39 | required this.requestDate, 40 | }); 41 | 42 | factory GatePass.fromJson(Map json) { 43 | return GatePass( 44 | email: json['email'] as String, 45 | name: json['name'] as String, 46 | rollNo: json['rollNo'] as String, 47 | branch: json['branch'] as String, 48 | className: json['class'] as String, 49 | batch: json['batch'] as String, 50 | reason: json['reason'] as String, 51 | date: json['date'] as String, 52 | timeFrom: json['timeFrom'] as String, 53 | timeTo: json['timeTo'] as String, 54 | advisor: json['advisor'] as String, 55 | faculty: json['faculty'] as String?, 56 | includePrincipal: json['includePrincipal'] as bool, 57 | approvalsRequired: List.from(json['approvalsRequired'] ?? []), 58 | approvedBy: List.from(json['approvedBy'] ?? []), 59 | rejectedBy: List.from(json['rejectedBy'] ?? []), 60 | status: json['status'] as String, 61 | requestDate: DateTime.parse(json['requestDate'] as String), 62 | ); 63 | } 64 | 65 | Map toJson() => { 66 | 'email': email, 67 | 'name': name, 68 | 'rollNo': rollNo, 69 | 'branch': branch, 70 | 'class': className, 71 | 'batch': batch, 72 | 'reason': reason, 73 | 'date': date, 74 | 'timeFrom': timeFrom, 75 | 'timeTo': timeTo, 76 | 'advisor': advisor, 77 | 'faculty': faculty, 78 | 'includePrincipal': includePrincipal, 79 | 'approvalsRequired': approvalsRequired, 80 | 'approvedBy': approvedBy, 81 | 'rejectedBy': rejectedBy, 82 | 'status': status, 83 | 'requestDate': requestDate.toIso8601String(), 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /lib/models/pink_slip.dart: -------------------------------------------------------------------------------- 1 | class PinkSlip { 2 | final String email; 3 | final String name; 4 | final String rollNo; 5 | final String branch; 6 | final String className; 7 | final String batch; 8 | final String reason; 9 | final String date; 10 | final String timeFrom; 11 | final String timeTo; 12 | final String advisor; 13 | final String? faculty; 14 | final bool includePrincipal; 15 | final List approvalsRequired; 16 | final List approvedBy; 17 | final List rejectedBy; 18 | final String status; 19 | final DateTime requestDate; 20 | 21 | PinkSlip({ 22 | required this.email, 23 | required this.name, 24 | required this.rollNo, 25 | required this.branch, 26 | required this.className, 27 | required this.batch, 28 | required this.reason, 29 | required this.date, 30 | required this.timeFrom, 31 | required this.timeTo, 32 | required this.advisor, 33 | this.faculty, 34 | required this.includePrincipal, 35 | required this.approvalsRequired, 36 | required this.approvedBy, 37 | required this.rejectedBy, 38 | required this.status, 39 | required this.requestDate, 40 | }); 41 | 42 | factory PinkSlip.fromJson(Map json) { 43 | return PinkSlip( 44 | email: json['email'] as String, 45 | name: json['name'] as String, 46 | rollNo: json['rollNo'] as String, 47 | branch: json['branch'] as String, 48 | className: json['class'] as String, 49 | batch: json['batch'] as String, 50 | reason: json['reason'] as String, 51 | date: json['date'] as String, 52 | timeFrom: json['timeFrom'] as String, 53 | timeTo: json['timeTo'] as String, 54 | advisor: json['advisor'] as String, 55 | faculty: json['faculty'] as String?, 56 | includePrincipal: json['includePrincipal'] as bool, 57 | approvalsRequired: List.from(json['approvalsRequired'] ?? []), 58 | approvedBy: List.from(json['approvedBy'] ?? []), 59 | rejectedBy: List.from(json['rejectedBy'] ?? []), 60 | status: json['status'] as String, 61 | requestDate: DateTime.parse(json['requestDate'] as String), 62 | ); 63 | } 64 | 65 | Map toJson() => { 66 | 'email': email, 67 | 'name': name, 68 | 'rollNo': rollNo, 69 | 'branch': branch, 70 | 'class': className, 71 | 'batch': batch, 72 | 'reason': reason, 73 | 'date': date, 74 | 'timeFrom': timeFrom, 75 | 'timeTo': timeTo, 76 | 'advisor': advisor, 77 | 'faculty': faculty, 78 | 'includePrincipal': includePrincipal, 79 | 'approvalsRequired': approvalsRequired, 80 | 'approvedBy': approvedBy, 81 | 'rejectedBy': rejectedBy, 82 | 'status': status, 83 | 'requestDate': requestDate.toIso8601String(), 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /lib/helper/database/lab_permission_db.dart: -------------------------------------------------------------------------------- 1 | import 'package:mongo_dart/mongo_dart.dart'; 2 | import 'db_service.dart'; 3 | 4 | Future>> getPermissionsForApproval( 5 | String facultyEmail) async { 6 | final db = DBService().db; 7 | final permissions = await db.collection('lab_permissions').find({ 8 | r'$or': [ 9 | { 10 | r'$and': [ 11 | {'status': 'pending'}, 12 | {'approvalsRequired': facultyEmail} 13 | ] 14 | }, 15 | {'approvedBy': facultyEmail}, 16 | {'rejectedBy': facultyEmail}, 17 | ] 18 | }).toList(); 19 | return permissions; 20 | } 21 | 22 | Future updateLabPermission( 23 | String permissionId, String facultyEmail, String status) async { 24 | final db = DBService().db; 25 | final collection = db.collection('lab_permissions'); 26 | 27 | // Get the current permission document 28 | final permission = 29 | await collection.findOne(where.id(ObjectId.parse(permissionId))); 30 | if (permission == null) throw Exception('Permission not found'); 31 | 32 | final List approvedBy = 33 | List.from(permission['approvedBy'] ?? []); 34 | final List rejectedBy = 35 | List.from(permission['rejectedBy'] ?? []); 36 | final List approvalsRequired = 37 | List.from(permission['approvalsRequired'] ?? []); 38 | 39 | // Update the appropriate lists based on the status 40 | if (status == 'approved') { 41 | if (!approvedBy.contains(facultyEmail)) { 42 | approvedBy.add(facultyEmail); 43 | } 44 | rejectedBy.remove(facultyEmail); 45 | } else if (status == 'rejected') { 46 | if (!rejectedBy.contains(facultyEmail)) { 47 | rejectedBy.add(facultyEmail); 48 | } 49 | approvedBy.remove(facultyEmail); 50 | } 51 | 52 | // Remove the faculty from approvalsRequired 53 | approvalsRequired.remove(facultyEmail); 54 | 55 | // Determine the overall status 56 | String overallStatus = 'pending'; 57 | if (rejectedBy.isNotEmpty) { 58 | overallStatus = 'rejected'; 59 | } else if (approvalsRequired.isEmpty && approvedBy.isNotEmpty) { 60 | overallStatus = 'approved'; 61 | } 62 | 63 | // Update the document 64 | await collection.updateOne( 65 | where.id(ObjectId.parse(permissionId)), 66 | { 67 | r'$set': { 68 | 'status': overallStatus, 69 | 'approvedBy': approvedBy, 70 | 'rejectedBy': rejectedBy, 71 | 'approvalsRequired': approvalsRequired, 72 | } 73 | }, 74 | ); 75 | } 76 | 77 | Future createLabPermission(Map permission) async { 78 | final db = DBService().db; 79 | await db.collection('lab_permissions').insert(permission); 80 | } 81 | 82 | Future>> getLabPermissionsByEmail( 83 | String email) async { 84 | final db = DBService().db; 85 | return await db.collection('lab_permissions').find({'email': email}).toList(); 86 | } 87 | -------------------------------------------------------------------------------- /lib/presentation/providers/theme_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | // Your existing ThemeProvider 4 | class ThemeProvider extends InheritedWidget { 5 | final ThemeMode themeMode; 6 | final Function(ThemeMode) updateTheme; 7 | 8 | const ThemeProvider({ 9 | super.key, 10 | required this.themeMode, 11 | required this.updateTheme, 12 | required super.child, 13 | }); 14 | 15 | static ThemeProvider? of(BuildContext context) { 16 | return context.dependOnInheritedWidgetOfExactType(); 17 | } 18 | 19 | @override 20 | bool updateShouldNotify(ThemeProvider oldWidget) { 21 | return themeMode != oldWidget.themeMode; 22 | } 23 | } 24 | 25 | // Add a Theme class to manage your theme data 26 | class AppTheme { 27 | // Light Theme 28 | static ThemeData lightTheme = ThemeData( 29 | useMaterial3: true, 30 | brightness: Brightness.light, 31 | colorScheme: ColorScheme.fromSeed( 32 | seedColor: Colors.blue, 33 | brightness: Brightness.light, 34 | primary: Colors.blue, 35 | secondary: Colors.blue.shade700, 36 | tertiary: Colors.blue.shade300, 37 | surface: Colors.white, 38 | onPrimary: Colors.white, 39 | onSecondary: Colors.white, 40 | onSurface: Colors.black87, 41 | ), 42 | // Card theme 43 | cardTheme: CardTheme( 44 | elevation: 2, 45 | shape: RoundedRectangleBorder( 46 | borderRadius: BorderRadius.circular(12), 47 | ), 48 | ), 49 | // AppBar theme 50 | appBarTheme: const AppBarTheme( 51 | centerTitle: true, 52 | elevation: 0, 53 | ), 54 | // Input decoration theme 55 | inputDecorationTheme: InputDecorationTheme( 56 | border: OutlineInputBorder( 57 | borderRadius: BorderRadius.circular(12), 58 | ), 59 | filled: true, 60 | ), 61 | ); 62 | 63 | // Dark Theme 64 | static ThemeData darkTheme = ThemeData( 65 | useMaterial3: true, 66 | brightness: Brightness.dark, 67 | colorScheme: ColorScheme.fromSeed( 68 | seedColor: Colors.blue, 69 | brightness: Brightness.dark, 70 | primary: Colors.blue, 71 | secondary: Colors.blue.shade300, 72 | tertiary: Colors.blue.shade200, 73 | surface: const Color(0xFF1E1E1E), 74 | onPrimary: Colors.white, 75 | onSecondary: Colors.white, 76 | onSurface: Colors.white, 77 | ), 78 | // Card theme 79 | cardTheme: CardTheme( 80 | elevation: 2, 81 | shape: RoundedRectangleBorder( 82 | borderRadius: BorderRadius.circular(12), 83 | ), 84 | ), 85 | // AppBar theme 86 | appBarTheme: const AppBarTheme( 87 | centerTitle: true, 88 | elevation: 0, 89 | ), 90 | // Input decoration theme 91 | inputDecorationTheme: InputDecorationTheme( 92 | border: OutlineInputBorder( 93 | borderRadius: BorderRadius.circular(12), 94 | ), 95 | filled: true, 96 | ), 97 | ); 98 | } 99 | -------------------------------------------------------------------------------- /linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | 12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 13 | # which isn't available in 3.10. 14 | function(list_prepend LIST_NAME PREFIX) 15 | set(NEW_LIST "") 16 | foreach(element ${${LIST_NAME}}) 17 | list(APPEND NEW_LIST "${PREFIX}${element}") 18 | endforeach(element) 19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 20 | endfunction() 21 | 22 | # === Flutter Library === 23 | # System-level dependencies. 24 | find_package(PkgConfig REQUIRED) 25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 28 | 29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 30 | 31 | # Published to parent scope for install step. 32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 36 | 37 | list(APPEND FLUTTER_LIBRARY_HEADERS 38 | "fl_basic_message_channel.h" 39 | "fl_binary_codec.h" 40 | "fl_binary_messenger.h" 41 | "fl_dart_project.h" 42 | "fl_engine.h" 43 | "fl_json_message_codec.h" 44 | "fl_json_method_codec.h" 45 | "fl_message_codec.h" 46 | "fl_method_call.h" 47 | "fl_method_channel.h" 48 | "fl_method_codec.h" 49 | "fl_method_response.h" 50 | "fl_plugin_registrar.h" 51 | "fl_plugin_registry.h" 52 | "fl_standard_message_codec.h" 53 | "fl_standard_method_codec.h" 54 | "fl_string_codec.h" 55 | "fl_value.h" 56 | "fl_view.h" 57 | "flutter_linux.h" 58 | ) 59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 60 | add_library(flutter INTERFACE) 61 | target_include_directories(flutter INTERFACE 62 | "${EPHEMERAL_DIR}" 63 | ) 64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 65 | target_link_libraries(flutter INTERFACE 66 | PkgConfig::GTK 67 | PkgConfig::GLIB 68 | PkgConfig::GIO 69 | ) 70 | add_dependencies(flutter flutter_assemble) 71 | 72 | # === Flutter tool backend === 73 | # _phony_ is a non-existent file to force this command to run every time, 74 | # since currently there's no way to get a full input/output list from the 75 | # flutter tool. 76 | add_custom_command( 77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 79 | COMMAND ${CMAKE_COMMAND} -E env 80 | ${FLUTTER_TOOL_ENVIRONMENT} 81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} 83 | VERBATIM 84 | ) 85 | add_custom_target(flutter_assemble DEPENDS 86 | "${FLUTTER_LIBRARY}" 87 | ${FLUTTER_LIBRARY_HEADERS} 88 | ) 89 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 23 | 27 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /lib/helper/database/lost_id_db.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/helper/database/db_service.dart'; 2 | import 'package:mongo_dart/mongo_dart.dart'; 3 | 4 | Future>> getIdRequestsForApproval( 5 | String adminEmail) async { 6 | final db = DBService().db; 7 | final requests = await db.collection('id_card_requests').find({ 8 | r'$or': [ 9 | { 10 | r'$and': [ 11 | {'status': 'pending'}, 12 | {'approvalsRequired': adminEmail} 13 | ] 14 | }, 15 | {'approvedBy': adminEmail}, 16 | {'rejectedBy': adminEmail}, 17 | ] 18 | }).toList(); 19 | return requests; 20 | } 21 | 22 | Future updateIdRequest( 23 | String requestId, String adminEmail, String status) async { 24 | final db = DBService().db; 25 | final collection = db.collection('id_card_requests'); 26 | 27 | final request = await collection.findOne(where.id(ObjectId.parse(requestId))); 28 | if (request == null) throw Exception('Request not found'); 29 | 30 | final List approvedBy = 31 | List.from(request['approvedBy'] ?? []); 32 | final List rejectedBy = 33 | List.from(request['rejectedBy'] ?? []); 34 | final List approvalsRequired = 35 | List.from(request['approvalsRequired'] ?? []); 36 | 37 | if (status == 'accepted') { 38 | if (!approvedBy.contains(adminEmail)) { 39 | approvedBy.add(adminEmail); 40 | } 41 | rejectedBy.remove(adminEmail); 42 | } else if (status == 'rejected') { 43 | if (!rejectedBy.contains(adminEmail)) { 44 | rejectedBy.add(adminEmail); 45 | } 46 | approvedBy.remove(adminEmail); 47 | } 48 | 49 | approvalsRequired.remove(adminEmail); 50 | 51 | String overallStatus = 'pending'; 52 | if (rejectedBy.isNotEmpty) { 53 | overallStatus = 'rejected'; 54 | } else if (approvalsRequired.isEmpty && approvedBy.isNotEmpty) { 55 | overallStatus = 'accepted'; 56 | } 57 | 58 | await collection.updateOne( 59 | where.id(ObjectId.parse(requestId)), 60 | { 61 | r'$set': { 62 | 'status': overallStatus, 63 | 'approvedBy': approvedBy, 64 | 'rejectedBy': rejectedBy, 65 | 'approvalsRequired': approvalsRequired, 66 | } 67 | }, 68 | ); 69 | } 70 | 71 | Future createIdRequest(Map request) async { 72 | final db = DBService().db; 73 | await db.collection('id_card_requests').insert(request); 74 | } 75 | 76 | Future hasExistingRequest(String email) async { 77 | final db = DBService().db; 78 | final request = await db.collection('id_card_requests').findOne({ 79 | 'email': email, 80 | 'status': {r'$ne': 'completed'} 81 | }); 82 | return request != null; 83 | } 84 | 85 | Future> getIdRequest(String email) async { 86 | final db = DBService().db; 87 | final request = 88 | await db.collection('id_card_requests').findOne({'email': email}); 89 | if (request == null) throw Exception('No request found'); 90 | return request; 91 | } 92 | 93 | Future markRequestCompleted(String email) async { 94 | final db = DBService().db; 95 | await db.collection('id_card_requests').updateOne( 96 | where.eq('email', email), 97 | { 98 | r'$set': { 99 | 'status': 'completed', 100 | } 101 | }, 102 | ); 103 | } 104 | -------------------------------------------------------------------------------- /lib/helper/database/vehicle_pass_db.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/helper/database/db_service.dart'; 2 | import 'package:mongo_dart/mongo_dart.dart'; 3 | 4 | Future>> getVehiclePassRequestsForApproval( 5 | String adminEmail) async { 6 | final db = DBService().db; 7 | final requests = await db.collection('vehicle_pass_requests').find({ 8 | r'$or': [ 9 | { 10 | r'$and': [ 11 | {'status': 'pending'}, 12 | {'approvalsRequired': adminEmail} 13 | ] 14 | }, 15 | {'approvedBy': adminEmail}, 16 | {'rejectedBy': adminEmail}, 17 | ] 18 | }).toList(); 19 | return requests; 20 | } 21 | 22 | Future updateVehiclePassRequest( 23 | String requestId, String adminEmail, String status) async { 24 | final db = DBService().db; 25 | final collection = db.collection('vehicle_pass_requests'); 26 | 27 | final request = await collection.findOne(where.id(ObjectId.parse(requestId))); 28 | if (request == null) throw Exception('Request not found'); 29 | 30 | final List approvedBy = 31 | List.from(request['approvedBy'] ?? []); 32 | final List rejectedBy = 33 | List.from(request['rejectedBy'] ?? []); 34 | final List approvalsRequired = 35 | List.from(request['approvalsRequired'] ?? []); 36 | 37 | if (status == 'approved') { 38 | if (!approvedBy.contains(adminEmail)) { 39 | approvedBy.add(adminEmail); 40 | } 41 | rejectedBy.remove(adminEmail); 42 | } else if (status == 'rejected') { 43 | if (!rejectedBy.contains(adminEmail)) { 44 | rejectedBy.add(adminEmail); 45 | } 46 | approvedBy.remove(adminEmail); 47 | } 48 | 49 | approvalsRequired.remove(adminEmail); 50 | 51 | String overallStatus = 'pending'; 52 | if (rejectedBy.isNotEmpty) { 53 | overallStatus = 'rejected'; 54 | } else if (approvalsRequired.isEmpty && approvedBy.isNotEmpty) { 55 | overallStatus = 'approved'; 56 | } 57 | 58 | await collection.updateOne( 59 | where.id(ObjectId.parse(requestId)), 60 | { 61 | r'$set': { 62 | 'status': overallStatus, 63 | 'approvedBy': approvedBy, 64 | 'rejectedBy': rejectedBy, 65 | 'approvalsRequired': approvalsRequired, 66 | } 67 | }, 68 | ); 69 | } 70 | 71 | Future createVehiclePassRequest(Map request) async { 72 | final db = DBService().db; 73 | await db.collection('vehicle_pass_requests').insert(request); 74 | } 75 | 76 | Future hasExistingRequest(String email) async { 77 | final db = DBService().db; 78 | final request = await db.collection('vehicle_pass_requests').findOne({ 79 | 'email': email, 80 | 'status': {r'$ne': 'completed'} 81 | }); 82 | return request != null; 83 | } 84 | 85 | Future> getVehiclePassRequest(String email) async { 86 | final db = DBService().db; 87 | final request = 88 | await db.collection('vehicle_pass_requests').findOne({'email': email}); 89 | if (request == null) throw Exception('No request found'); 90 | return request; 91 | } 92 | 93 | Future markRequestCompleted(String email) async { 94 | final db = DBService().db; 95 | await db.collection('vehicle_pass_requests').updateOne( 96 | where.eq('email', email), 97 | { 98 | r'$set': { 99 | 'status': 'completed', 100 | } 101 | }, 102 | ); 103 | } 104 | -------------------------------------------------------------------------------- /lib/helper/database/leave_form_db.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/helper/database/db_service.dart'; 2 | import 'package:mongo_dart/mongo_dart.dart'; 3 | 4 | Future createLeaveForm(Map formData) async { 5 | final dbService = DBService(); 6 | if (!dbService.isConnected) { 7 | await dbService.connect(); 8 | } 9 | final collection = dbService.db.collection('leave_forms'); 10 | await collection.insert(formData); 11 | } 12 | 13 | Future>> getFormsForApproval( 14 | String facultyEmail) async { 15 | final dbService = DBService(); 16 | if (!dbService.isConnected) { 17 | await dbService.connect(); 18 | } 19 | final collection = dbService.db.collection('leave_forms'); 20 | 21 | // Get all forms where the faculty is either required to approve, has approved, or has rejected 22 | final forms = await collection.find({ 23 | r'$or': [ 24 | {'approvalsRequired': facultyEmail}, 25 | {'approvedBy': facultyEmail}, 26 | {'rejectedBy': facultyEmail}, 27 | ] 28 | }).toList(); 29 | 30 | // Sort by date in descending order 31 | forms.sort((a, b) => 32 | DateTime.parse(b['createdAt']).compareTo(DateTime.parse(a['createdAt']))); 33 | 34 | return forms; 35 | } 36 | 37 | Future>> getFormsByEmail(String email) async { 38 | final dbService = DBService(); 39 | if (!dbService.isConnected) { 40 | await dbService.connect(); 41 | } 42 | final collection = dbService.db.collection('leave_forms'); 43 | return await collection.find(where.eq('email', email)).toList(); 44 | } 45 | 46 | Future updateLeaveForm(String id, String email, String status) async { 47 | try { 48 | final dbService = DBService(); 49 | if (!dbService.isConnected) { 50 | await dbService.connect(); 51 | } 52 | final collection = dbService.db.collection('leave_forms'); 53 | final doc = 54 | await collection.findOne(where.eq('_id', ObjectId.fromHexString(id))); 55 | if (doc == null) { 56 | throw Exception('Leave form not found'); 57 | } 58 | 59 | final List approvalsRequired = 60 | List.from(doc['approvalsRequired'] ?? []); 61 | final List approvedBy = List.from(doc['approvedBy'] ?? []); 62 | final List rejectedBy = List.from(doc['rejectedBy'] ?? []); 63 | 64 | if (status == 'approved') { 65 | if (!approvedBy.contains(email)) { 66 | approvedBy.add(email); 67 | } 68 | approvalsRequired.remove(email); 69 | } else if (status == 'rejected') { 70 | if (!rejectedBy.contains(email)) { 71 | rejectedBy.add(email); 72 | } 73 | approvalsRequired.clear(); // Clear remaining approvals on rejection 74 | } 75 | 76 | String overallStatus; 77 | if (rejectedBy.isNotEmpty) { 78 | overallStatus = 'rejected'; 79 | } else if (approvalsRequired.isEmpty && approvedBy.isNotEmpty) { 80 | overallStatus = 'approved'; 81 | } else { 82 | overallStatus = 'pending'; 83 | } 84 | 85 | await collection.update( 86 | where.eq('_id', ObjectId.fromHexString(id)), 87 | modify 88 | .set('approvalsRequired', approvalsRequired) 89 | .set('approvedBy', approvedBy) 90 | .set('rejectedBy', rejectedBy) 91 | .set('status', overallStatus) 92 | .set('lastUpdated', DateTime.now().toIso8601String()), 93 | ); 94 | } catch (e) { 95 | throw Exception('Failed to update leave form: $e'); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /windows/runner/Runner.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | #include "resource.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "winres.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (United States) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_APP_ICON ICON "resources\\app_icon.ico" 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) 64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0,0 67 | #endif 68 | 69 | #if defined(FLUTTER_VERSION) 70 | #define VERSION_AS_STRING FLUTTER_VERSION 71 | #else 72 | #define VERSION_AS_STRING "1.0.0" 73 | #endif 74 | 75 | VS_VERSION_INFO VERSIONINFO 76 | FILEVERSION VERSION_AS_NUMBER 77 | PRODUCTVERSION VERSION_AS_NUMBER 78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 79 | #ifdef _DEBUG 80 | FILEFLAGS VS_FF_DEBUG 81 | #else 82 | FILEFLAGS 0x0L 83 | #endif 84 | FILEOS VOS__WINDOWS32 85 | FILETYPE VFT_APP 86 | FILESUBTYPE 0x0L 87 | BEGIN 88 | BLOCK "StringFileInfo" 89 | BEGIN 90 | BLOCK "040904e4" 91 | BEGIN 92 | VALUE "CompanyName", "me.xditya" "\0" 93 | VALUE "FileDescription", "csms" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "csms" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2024 me.xditya. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "csms.exe" "\0" 98 | VALUE "ProductName", "csms" "\0" 99 | VALUE "ProductVersion", VERSION_AS_STRING "\0" 100 | END 101 | END 102 | BLOCK "VarFileInfo" 103 | BEGIN 104 | VALUE "Translation", 0x409, 1252 105 | END 106 | END 107 | 108 | #endif // English (United States) resources 109 | ///////////////////////////////////////////////////////////////////////////// 110 | 111 | 112 | 113 | #ifndef APSTUDIO_INVOKED 114 | ///////////////////////////////////////////////////////////////////////////// 115 | // 116 | // Generated from the TEXTINCLUDE 3 resource. 117 | // 118 | 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | -------------------------------------------------------------------------------- /src/components/ui/dialog.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as DialogPrimitive from "@radix-ui/react-dialog" 5 | import { Cross2Icon } from "@radix-ui/react-icons" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const Dialog = DialogPrimitive.Root 10 | 11 | const DialogTrigger = DialogPrimitive.Trigger 12 | 13 | const DialogPortal = DialogPrimitive.Portal 14 | 15 | const DialogClose = DialogPrimitive.Close 16 | 17 | const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => ( 18 | 25 | )) 26 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName 27 | 28 | const DialogContent = React.forwardRef(({ className, children, ...props }, ref) => ( 29 | 30 | 31 | 38 | {children} 39 | 41 | 42 | Close 43 | 44 | 45 | 46 | )) 47 | DialogContent.displayName = DialogPrimitive.Content.displayName 48 | 49 | const DialogHeader = ({ 50 | className, 51 | ...props 52 | }) => ( 53 |
56 | ) 57 | DialogHeader.displayName = "DialogHeader" 58 | 59 | const DialogFooter = ({ 60 | className, 61 | ...props 62 | }) => ( 63 |
66 | ) 67 | DialogFooter.displayName = "DialogFooter" 68 | 69 | const DialogTitle = React.forwardRef(({ className, ...props }, ref) => ( 70 | 74 | )) 75 | DialogTitle.displayName = DialogPrimitive.Title.displayName 76 | 77 | const DialogDescription = React.forwardRef(({ className, ...props }, ref) => ( 78 | 82 | )) 83 | DialogDescription.displayName = DialogPrimitive.Description.displayName 84 | 85 | export { 86 | Dialog, 87 | DialogPortal, 88 | DialogOverlay, 89 | DialogTrigger, 90 | DialogClose, 91 | DialogContent, 92 | DialogHeader, 93 | DialogFooter, 94 | DialogTitle, 95 | DialogDescription, 96 | } 97 | -------------------------------------------------------------------------------- /src/hooks/use-toast.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | // Inspired by react-hot-toast library 3 | import * as React from "react" 4 | 5 | const TOAST_LIMIT = 1 6 | const TOAST_REMOVE_DELAY = 1000000 7 | 8 | const actionTypes = { 9 | ADD_TOAST: "ADD_TOAST", 10 | UPDATE_TOAST: "UPDATE_TOAST", 11 | DISMISS_TOAST: "DISMISS_TOAST", 12 | REMOVE_TOAST: "REMOVE_TOAST" 13 | } 14 | 15 | let count = 0 16 | 17 | function genId() { 18 | count = (count + 1) % Number.MAX_SAFE_INTEGER 19 | return count.toString(); 20 | } 21 | 22 | const toastTimeouts = new Map() 23 | 24 | const addToRemoveQueue = (toastId) => { 25 | if (toastTimeouts.has(toastId)) { 26 | return 27 | } 28 | 29 | const timeout = setTimeout(() => { 30 | toastTimeouts.delete(toastId) 31 | dispatch({ 32 | type: "REMOVE_TOAST", 33 | toastId: toastId, 34 | }) 35 | }, TOAST_REMOVE_DELAY) 36 | 37 | toastTimeouts.set(toastId, timeout) 38 | } 39 | 40 | export const reducer = (state, action) => { 41 | switch (action.type) { 42 | case "ADD_TOAST": 43 | return { 44 | ...state, 45 | toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), 46 | }; 47 | 48 | case "UPDATE_TOAST": 49 | return { 50 | ...state, 51 | toasts: state.toasts.map((t) => 52 | t.id === action.toast.id ? { ...t, ...action.toast } : t), 53 | }; 54 | 55 | case "DISMISS_TOAST": { 56 | const { toastId } = action 57 | 58 | // ! Side effects ! - This could be extracted into a dismissToast() action, 59 | // but I'll keep it here for simplicity 60 | if (toastId) { 61 | addToRemoveQueue(toastId) 62 | } else { 63 | state.toasts.forEach((toast) => { 64 | addToRemoveQueue(toast.id) 65 | }) 66 | } 67 | 68 | return { 69 | ...state, 70 | toasts: state.toasts.map((t) => 71 | t.id === toastId || toastId === undefined 72 | ? { 73 | ...t, 74 | open: false, 75 | } 76 | : t), 77 | }; 78 | } 79 | case "REMOVE_TOAST": 80 | if (action.toastId === undefined) { 81 | return { 82 | ...state, 83 | toasts: [], 84 | } 85 | } 86 | return { 87 | ...state, 88 | toasts: state.toasts.filter((t) => t.id !== action.toastId), 89 | }; 90 | } 91 | } 92 | 93 | const listeners = [] 94 | 95 | let memoryState = { toasts: [] } 96 | 97 | function dispatch(action) { 98 | memoryState = reducer(memoryState, action) 99 | listeners.forEach((listener) => { 100 | listener(memoryState) 101 | }) 102 | } 103 | 104 | function toast({ 105 | ...props 106 | }) { 107 | const id = genId() 108 | 109 | const update = (props) => 110 | dispatch({ 111 | type: "UPDATE_TOAST", 112 | toast: { ...props, id }, 113 | }) 114 | const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) 115 | 116 | dispatch({ 117 | type: "ADD_TOAST", 118 | toast: { 119 | ...props, 120 | id, 121 | open: true, 122 | onOpenChange: (open) => { 123 | if (!open) dismiss() 124 | }, 125 | }, 126 | }) 127 | 128 | return { 129 | id: id, 130 | dismiss, 131 | update, 132 | } 133 | } 134 | 135 | function useToast() { 136 | const [state, setState] = React.useState(memoryState) 137 | 138 | React.useEffect(() => { 139 | listeners.push(setState) 140 | return () => { 141 | const index = listeners.indexOf(setState) 142 | if (index > -1) { 143 | listeners.splice(index, 1) 144 | } 145 | }; 146 | }, [state]) 147 | 148 | return { 149 | ...state, 150 | toast, 151 | dismiss: (toastId) => dispatch({ type: "DISMISS_TOAST", toastId }), 152 | }; 153 | } 154 | 155 | export { useToast, toast } 156 | -------------------------------------------------------------------------------- /lib/presentation/providers/vending_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/helper/data/vending_items.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:csms/helper/database/balance_db.dart'; 4 | import 'package:csms/helper/database/vending_db.dart'; 5 | import 'package:csms/helper/config.dart'; 6 | import 'package:flutter/material.dart'; 7 | 8 | class VendingProvider extends ChangeNotifier { 9 | final Map _selectedItems = {}; 10 | final List _orders = []; 11 | double _walletBalance = 0.0; 12 | final VendingDB _vendingDB; 13 | 14 | VendingProvider(this._vendingDB); 15 | 16 | Map get selectedItems => _selectedItems; 17 | List get orders => _orders; 18 | double get walletBalance => _walletBalance; 19 | 20 | double get totalCost { 21 | double total = 0; 22 | for (var entry in _selectedItems.entries) { 23 | final item = vendingItems.firstWhere((i) => i.id == entry.key); 24 | total += item.price * entry.value; 25 | } 26 | return total; 27 | } 28 | 29 | void updateQuantity(String itemId, int delta) { 30 | final currentQty = _selectedItems[itemId] ?? 0; 31 | final newQty = currentQty + delta; 32 | 33 | if (newQty <= 0) { 34 | _selectedItems.remove(itemId); 35 | } else { 36 | _selectedItems[itemId] = newQty; 37 | } 38 | notifyListeners(); 39 | } 40 | 41 | Future loadWalletBalance() async { 42 | final session = await account.get(); 43 | _walletBalance = await getBalance(session.email); 44 | notifyListeners(); 45 | } 46 | 47 | Future processPurchase() async { 48 | final session = await account.get(); 49 | 50 | if (_selectedItems.isEmpty) { 51 | throw 'Please select items to purchase.'; 52 | } 53 | 54 | if (totalCost > _walletBalance) { 55 | throw 'Insufficient balance. Please add funds to continue.'; 56 | } 57 | 58 | try { 59 | await updateBalance(session.email, -totalCost, "vending machine"); 60 | _walletBalance -= totalCost; 61 | 62 | final orderDetails = 63 | await _vendingDB.addOrder(session.email, _selectedItems); 64 | 65 | _orders.insert( 66 | 0, 67 | Order( 68 | items: Map.from(_selectedItems), 69 | status: 'Placed', 70 | total: totalCost, 71 | hash: orderDetails['hash'], 72 | )); 73 | 74 | _selectedItems.clear(); 75 | notifyListeners(); 76 | } catch (e) { 77 | if (_walletBalance != walletBalance) { 78 | await updateBalance(session.email, totalCost, "vending machine refund"); 79 | _walletBalance += totalCost; 80 | } 81 | throw 'Failed to process purchase: ${e.toString()}'; 82 | } 83 | } 84 | 85 | Future loadOrders() async { 86 | final session = await account.get(); 87 | final dbOrders = await _vendingDB.getAllOrders(session.email); 88 | 89 | _orders.clear(); 90 | _orders.addAll( 91 | dbOrders.map((order) => Order( 92 | items: Map.from(order['items'] as Map), 93 | status: (order['status'] is bool) 94 | ? (order['status'] ? 'Completed' : 'Placed') 95 | : order['status'] as String? ?? 'Placed', 96 | total: (order['totalCost'] as num).toDouble(), 97 | hash: order['hash']?.toString() ?? 'unknown', 98 | )), 99 | ); 100 | notifyListeners(); 101 | } 102 | } 103 | 104 | class Order { 105 | final Map items; 106 | final String status; 107 | final double total; 108 | final String hash; 109 | final DateTime timestamp; 110 | 111 | Order({ 112 | required this.items, 113 | String? status, 114 | required this.total, 115 | required this.hash, 116 | DateTime? timestamp, 117 | }) : status = status ?? 'Placed', 118 | timestamp = timestamp ?? DateTime.now(); 119 | } 120 | -------------------------------------------------------------------------------- /windows/runner/win32_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_WIN32_WINDOW_H_ 2 | #define RUNNER_WIN32_WINDOW_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be 11 | // inherited from by classes that wish to specialize with custom 12 | // rendering and input handling 13 | class Win32Window { 14 | public: 15 | struct Point { 16 | unsigned int x; 17 | unsigned int y; 18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {} 19 | }; 20 | 21 | struct Size { 22 | unsigned int width; 23 | unsigned int height; 24 | Size(unsigned int width, unsigned int height) 25 | : width(width), height(height) {} 26 | }; 27 | 28 | Win32Window(); 29 | virtual ~Win32Window(); 30 | 31 | // Creates a win32 window with |title| that is positioned and sized using 32 | // |origin| and |size|. New windows are created on the default monitor. Window 33 | // sizes are specified to the OS in physical pixels, hence to ensure a 34 | // consistent size this function will scale the inputted width and height as 35 | // as appropriate for the default monitor. The window is invisible until 36 | // |Show| is called. Returns true if the window was created successfully. 37 | bool Create(const std::wstring& title, const Point& origin, const Size& size); 38 | 39 | // Show the current window. Returns true if the window was successfully shown. 40 | bool Show(); 41 | 42 | // Release OS resources associated with window. 43 | void Destroy(); 44 | 45 | // Inserts |content| into the window tree. 46 | void SetChildContent(HWND content); 47 | 48 | // Returns the backing Window handle to enable clients to set icon and other 49 | // window properties. Returns nullptr if the window has been destroyed. 50 | HWND GetHandle(); 51 | 52 | // If true, closing this window will quit the application. 53 | void SetQuitOnClose(bool quit_on_close); 54 | 55 | // Return a RECT representing the bounds of the current client area. 56 | RECT GetClientArea(); 57 | 58 | protected: 59 | // Processes and route salient window messages for mouse handling, 60 | // size change and DPI. Delegates handling of these to member overloads that 61 | // inheriting classes can handle. 62 | virtual LRESULT MessageHandler(HWND window, 63 | UINT const message, 64 | WPARAM const wparam, 65 | LPARAM const lparam) noexcept; 66 | 67 | // Called when CreateAndShow is called, allowing subclass window-related 68 | // setup. Subclasses should return false if setup fails. 69 | virtual bool OnCreate(); 70 | 71 | // Called when Destroy is called. 72 | virtual void OnDestroy(); 73 | 74 | private: 75 | friend class WindowClassRegistrar; 76 | 77 | // OS callback called by message pump. Handles the WM_NCCREATE message which 78 | // is passed when the non-client area is being created and enables automatic 79 | // non-client DPI scaling so that the non-client area automatically 80 | // responds to changes in DPI. All other messages are handled by 81 | // MessageHandler. 82 | static LRESULT CALLBACK WndProc(HWND const window, 83 | UINT const message, 84 | WPARAM const wparam, 85 | LPARAM const lparam) noexcept; 86 | 87 | // Retrieves a class instance pointer for |window| 88 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 89 | 90 | // Update the window frame's theme to match the system theme. 91 | static void UpdateTheme(HWND const window); 92 | 93 | bool quit_on_close_ = false; 94 | 95 | // window handle for top level window. 96 | HWND window_handle_ = nullptr; 97 | 98 | // window handle for hosted content. 99 | HWND child_content_ = nullptr; 100 | }; 101 | 102 | #endif // RUNNER_WIN32_WINDOW_H_ 103 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/components/ui/toast.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import * as React from "react" 3 | import { Cross2Icon } from "@radix-ui/react-icons" 4 | import * as ToastPrimitives from "@radix-ui/react-toast" 5 | import { cva } from "class-variance-authority"; 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const ToastProvider = ToastPrimitives.Provider 10 | 11 | const ToastViewport = React.forwardRef(({ className, ...props }, ref) => ( 12 | 19 | )) 20 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName 21 | 22 | const toastVariants = cva( 23 | "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", 24 | { 25 | variants: { 26 | variant: { 27 | default: "border bg-background text-foreground", 28 | destructive: 29 | "destructive group border-destructive bg-destructive text-destructive-foreground", 30 | }, 31 | }, 32 | defaultVariants: { 33 | variant: "default", 34 | }, 35 | } 36 | ) 37 | 38 | const Toast = React.forwardRef(({ className, variant, ...props }, ref) => { 39 | return ( 40 | () 44 | ); 45 | }) 46 | Toast.displayName = ToastPrimitives.Root.displayName 47 | 48 | const ToastAction = React.forwardRef(({ className, ...props }, ref) => ( 49 | 56 | )) 57 | ToastAction.displayName = ToastPrimitives.Action.displayName 58 | 59 | const ToastClose = React.forwardRef(({ className, ...props }, ref) => ( 60 | 68 | 69 | 70 | )) 71 | ToastClose.displayName = ToastPrimitives.Close.displayName 72 | 73 | const ToastTitle = React.forwardRef(({ className, ...props }, ref) => ( 74 | 78 | )) 79 | ToastTitle.displayName = ToastPrimitives.Title.displayName 80 | 81 | const ToastDescription = React.forwardRef(({ className, ...props }, ref) => ( 82 | 83 | )) 84 | ToastDescription.displayName = ToastPrimitives.Description.displayName 85 | 86 | export { ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction }; 87 | -------------------------------------------------------------------------------- /windows/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.14) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 12 | 13 | # Set fallback configurations for older versions of the flutter tool. 14 | if (NOT DEFINED FLUTTER_TARGET_PLATFORM) 15 | set(FLUTTER_TARGET_PLATFORM "windows-x64") 16 | endif() 17 | 18 | # === Flutter Library === 19 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") 20 | 21 | # Published to parent scope for install step. 22 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 23 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 24 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 25 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) 26 | 27 | list(APPEND FLUTTER_LIBRARY_HEADERS 28 | "flutter_export.h" 29 | "flutter_windows.h" 30 | "flutter_messenger.h" 31 | "flutter_plugin_registrar.h" 32 | "flutter_texture_registrar.h" 33 | ) 34 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 35 | add_library(flutter INTERFACE) 36 | target_include_directories(flutter INTERFACE 37 | "${EPHEMERAL_DIR}" 38 | ) 39 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 40 | add_dependencies(flutter flutter_assemble) 41 | 42 | # === Wrapper === 43 | list(APPEND CPP_WRAPPER_SOURCES_CORE 44 | "core_implementations.cc" 45 | "standard_codec.cc" 46 | ) 47 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 48 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 49 | "plugin_registrar.cc" 50 | ) 51 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 52 | list(APPEND CPP_WRAPPER_SOURCES_APP 53 | "flutter_engine.cc" 54 | "flutter_view_controller.cc" 55 | ) 56 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 57 | 58 | # Wrapper sources needed for a plugin. 59 | add_library(flutter_wrapper_plugin STATIC 60 | ${CPP_WRAPPER_SOURCES_CORE} 61 | ${CPP_WRAPPER_SOURCES_PLUGIN} 62 | ) 63 | apply_standard_settings(flutter_wrapper_plugin) 64 | set_target_properties(flutter_wrapper_plugin PROPERTIES 65 | POSITION_INDEPENDENT_CODE ON) 66 | set_target_properties(flutter_wrapper_plugin PROPERTIES 67 | CXX_VISIBILITY_PRESET hidden) 68 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 69 | target_include_directories(flutter_wrapper_plugin PUBLIC 70 | "${WRAPPER_ROOT}/include" 71 | ) 72 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 73 | 74 | # Wrapper sources needed for the runner. 75 | add_library(flutter_wrapper_app STATIC 76 | ${CPP_WRAPPER_SOURCES_CORE} 77 | ${CPP_WRAPPER_SOURCES_APP} 78 | ) 79 | apply_standard_settings(flutter_wrapper_app) 80 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 81 | target_include_directories(flutter_wrapper_app PUBLIC 82 | "${WRAPPER_ROOT}/include" 83 | ) 84 | add_dependencies(flutter_wrapper_app flutter_assemble) 85 | 86 | # === Flutter tool backend === 87 | # _phony_ is a non-existent file to force this command to run every time, 88 | # since currently there's no way to get a full input/output list from the 89 | # flutter tool. 90 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") 91 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) 92 | add_custom_command( 93 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 94 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} 95 | ${CPP_WRAPPER_SOURCES_APP} 96 | ${PHONY_OUTPUT} 97 | COMMAND ${CMAKE_COMMAND} -E env 98 | ${FLUTTER_TOOL_ENVIRONMENT} 99 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" 100 | ${FLUTTER_TARGET_PLATFORM} $ 101 | VERBATIM 102 | ) 103 | add_custom_target(flutter_assemble DEPENDS 104 | "${FLUTTER_LIBRARY}" 105 | ${FLUTTER_LIBRARY_HEADERS} 106 | ${CPP_WRAPPER_SOURCES_CORE} 107 | ${CPP_WRAPPER_SOURCES_PLUGIN} 108 | ${CPP_WRAPPER_SOURCES_APP} 109 | ) 110 | -------------------------------------------------------------------------------- /lib/helper/database/vending_db.dart: -------------------------------------------------------------------------------- 1 | import 'package:csms/helper/data/vending_items.dart'; 2 | import 'package:mongo_dart/mongo_dart.dart'; 3 | import 'package:crypto/crypto.dart'; 4 | import 'dart:convert'; 5 | 6 | class VendingDB { 7 | static const String _collectionName = 'vending_orders'; 8 | final Db _db; 9 | 10 | VendingDB(this._db); 11 | 12 | Future _ensureConnection() async { 13 | if (_db.state != State.open) { 14 | await _db.open(); 15 | } 16 | } 17 | 18 | Future> addOrder( 19 | String email, Map items) async { 20 | await _ensureConnection(); 21 | final collection = _db.collection(_collectionName); 22 | 23 | // Calculate total cost 24 | final totalCost = items.entries.fold( 25 | 0.0, 26 | (total, entry) => 27 | total + 28 | (vendingItems.firstWhere((item) => item.id == entry.key).price * 29 | entry.value)); 30 | 31 | // Generate a unique hash for this order 32 | final timestamp = DateTime.now().millisecondsSinceEpoch.toString(); 33 | final hashInput = '$email$timestamp${items.toString()}'; 34 | final orderHash = sha256.convert(utf8.encode(hashInput)).toString(); 35 | 36 | // Create the order entry 37 | final orderDetails = { 38 | 'hash': orderHash, 39 | 'items': items, 40 | 'timestamp': timestamp, 41 | 'status': 'Placed', 42 | 'totalCost': totalCost, 43 | }; 44 | 45 | // Create or update the document with the new order 46 | await collection.updateOne( 47 | where.eq('email', email), 48 | { 49 | '\$set': { 50 | 'orders.$orderHash': [orderDetails] 51 | } 52 | }, 53 | upsert: true, 54 | ); 55 | 56 | return orderDetails; 57 | } 58 | 59 | Future?> getOrders(String email) async { 60 | final collection = _db.collection(_collectionName); 61 | 62 | final result = await collection.findOne(where.eq('email', email)); 63 | return result?['orders'] as Map?; 64 | } 65 | 66 | Future>> getAllOrders([String? email]) async { 67 | await _ensureConnection(); 68 | final collection = _db.collection(_collectionName); 69 | 70 | // If no email is provided, get all orders 71 | final query = email != null ? where.eq('email', email) : where; 72 | final results = await collection.find(query).toList(); 73 | 74 | List> allOrders = []; 75 | 76 | for (var result in results) { 77 | if (result.containsKey('orders')) { 78 | final orders = result['orders'] as Map; 79 | final userEmail = result['email'] as String; 80 | 81 | orders.forEach((hash, orderData) { 82 | if (orderData is List && orderData.isNotEmpty) { 83 | var order = Map.from(orderData[0] as Map); 84 | order['hash'] = hash; 85 | order['userEmail'] = userEmail; // Add user email to order details 86 | allOrders.add(order); 87 | } 88 | }); 89 | } 90 | } 91 | 92 | // Sort by timestamp (most recent first) 93 | allOrders.sort((a, b) => 94 | int.parse(b['timestamp']).compareTo(int.parse(a['timestamp']))); 95 | 96 | return allOrders; 97 | } 98 | 99 | Future?> getOrderByHash( 100 | String email, String hash) async { 101 | await _ensureConnection(); 102 | final collection = _db.collection(_collectionName); 103 | 104 | final result = await collection.findOne( 105 | where.eq('email', email).and(where.eq('orders.hash', hash)), 106 | ); 107 | 108 | if (result == null || !result.containsKey('orders')) { 109 | return null; 110 | } 111 | 112 | final orders = result['orders'] as List; 113 | return orders.firstWhere( 114 | (order) => order['hash'] == hash, 115 | orElse: () => null, 116 | ) as Map?; 117 | } 118 | 119 | Future deleteOrder(String email, String hash) async { 120 | final collection = _db.collection(_collectionName); 121 | 122 | await collection.updateOne( 123 | where.eq('email', email), 124 | { 125 | '\$unset': {'orders.$hash': 1} 126 | }, 127 | ); 128 | } 129 | 130 | Future clearAllOrders(String email) async { 131 | final collection = _db.collection(_collectionName); 132 | 133 | await collection.updateOne( 134 | where.eq('email', email), 135 | { 136 | '\$set': {'orders': {}} 137 | }, 138 | ); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.14) 3 | project(csms LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "csms") 8 | 9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 10 | # versions of CMake. 11 | cmake_policy(VERSION 3.14...3.25) 12 | 13 | # Define build configuration option. 14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 15 | if(IS_MULTICONFIG) 16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 17 | CACHE STRING "" FORCE) 18 | else() 19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 20 | set(CMAKE_BUILD_TYPE "Debug" CACHE 21 | STRING "Flutter build mode" FORCE) 22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 23 | "Debug" "Profile" "Release") 24 | endif() 25 | endif() 26 | # Define settings for the Profile build mode. 27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 31 | 32 | # Use Unicode for all projects. 33 | add_definitions(-DUNICODE -D_UNICODE) 34 | 35 | # Compilation settings that should be applied to most targets. 36 | # 37 | # Be cautious about adding new options here, as plugins use this function by 38 | # default. In most cases, you should add new options to specific targets instead 39 | # of modifying this function. 40 | function(APPLY_STANDARD_SETTINGS TARGET) 41 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 43 | target_compile_options(${TARGET} PRIVATE /EHsc) 44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 46 | endfunction() 47 | 48 | # Flutter library and tool build rules. 49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 50 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 51 | 52 | # Application build; see runner/CMakeLists.txt. 53 | add_subdirectory("runner") 54 | 55 | 56 | # Generated plugin build rules, which manage building the plugins and adding 57 | # them to the application. 58 | include(flutter/generated_plugins.cmake) 59 | 60 | 61 | # === Installation === 62 | # Support files are copied into place next to the executable, so that it can 63 | # run in place. This is done instead of making a separate bundle (as on Linux) 64 | # so that building and running from within Visual Studio will work. 65 | set(BUILD_BUNDLE_DIR "$") 66 | # Make the "install" step default, as it's required to run. 67 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 68 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 69 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 70 | endif() 71 | 72 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 73 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 74 | 75 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 76 | COMPONENT Runtime) 77 | 78 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 79 | COMPONENT Runtime) 80 | 81 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 82 | COMPONENT Runtime) 83 | 84 | if(PLUGIN_BUNDLED_LIBRARIES) 85 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 86 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 87 | COMPONENT Runtime) 88 | endif() 89 | 90 | # Copy the native assets provided by the build.dart from all packages. 91 | set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") 92 | install(DIRECTORY "${NATIVE_ASSETS_DIR}" 93 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 94 | COMPONENT Runtime) 95 | 96 | # Fully re-copy the assets directory on each build to avoid having stale files 97 | # from a previous install. 98 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 99 | install(CODE " 100 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 101 | " COMPONENT Runtime) 102 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 103 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 104 | 105 | # Install the AOT library on non-Debug builds only. 106 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 107 | CONFIGURATIONS Profile;Release 108 | COMPONENT Runtime) 109 | -------------------------------------------------------------------------------- /linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen* screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "csms"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } else { 47 | gtk_window_set_title(window, "csms"); 48 | } 49 | 50 | gtk_window_set_default_size(window, 1280, 720); 51 | gtk_widget_show(GTK_WIDGET(window)); 52 | 53 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 55 | 56 | FlView* view = fl_view_new(project); 57 | gtk_widget_show(GTK_WIDGET(view)); 58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 59 | 60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 61 | 62 | gtk_widget_grab_focus(GTK_WIDGET(view)); 63 | } 64 | 65 | // Implements GApplication::local_command_line. 66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { 67 | MyApplication* self = MY_APPLICATION(application); 68 | // Strip out the first argument as it is the binary name. 69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 70 | 71 | g_autoptr(GError) error = nullptr; 72 | if (!g_application_register(application, nullptr, &error)) { 73 | g_warning("Failed to register: %s", error->message); 74 | *exit_status = 1; 75 | return TRUE; 76 | } 77 | 78 | g_application_activate(application); 79 | *exit_status = 0; 80 | 81 | return TRUE; 82 | } 83 | 84 | // Implements GApplication::startup. 85 | static void my_application_startup(GApplication* application) { 86 | //MyApplication* self = MY_APPLICATION(object); 87 | 88 | // Perform any actions required at application startup. 89 | 90 | G_APPLICATION_CLASS(my_application_parent_class)->startup(application); 91 | } 92 | 93 | // Implements GApplication::shutdown. 94 | static void my_application_shutdown(GApplication* application) { 95 | //MyApplication* self = MY_APPLICATION(object); 96 | 97 | // Perform any actions required at application shutdown. 98 | 99 | G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); 100 | } 101 | 102 | // Implements GObject::dispose. 103 | static void my_application_dispose(GObject* object) { 104 | MyApplication* self = MY_APPLICATION(object); 105 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 106 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 107 | } 108 | 109 | static void my_application_class_init(MyApplicationClass* klass) { 110 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 111 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 112 | G_APPLICATION_CLASS(klass)->startup = my_application_startup; 113 | G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; 114 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 115 | } 116 | 117 | static void my_application_init(MyApplication* self) {} 118 | 119 | MyApplication* my_application_new() { 120 | return MY_APPLICATION(g_object_new(my_application_get_type(), 121 | "application-id", APPLICATION_ID, 122 | "flags", G_APPLICATION_NON_UNIQUE, 123 | nullptr)); 124 | } 125 | --------------------------------------------------------------------------------