diff --git a/.gitignore b/.gitignore index 5d6fa2d..29a3a50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,5 @@ -# Do not remove or rename entries in this file, only add new ones -# See https://github.com/flutter/flutter/issues/128635 for more context. - # Miscellaneous *.class -*.lock *.log *.pyc *.swp @@ -20,46 +16,10 @@ migrate_working_dir/ *.iws .idea/ -# Visual Studio Code related -.classpath -.project -.settings/ -.vscode/* -.ccls-cache - -# This file, on the master branch, should never exist or be checked-in. -# -# On a *final* release branch, that is, what will ship to stable or beta, the -# file can be force added (git add --force) and checked-in in order to effectively -# "pin" the engine artifact version so the flutter tool does not need to use git -# to determine the engine artifacts. -# -# See https://github.com/flutter/flutter/blob/main/docs/tool/Engine-artifacts.md. -/bin/internal/engine.version - -# Flutter repo-specific -/bin/cache/ -/bin/internal/bootstrap.bat -/bin/internal/bootstrap.sh -/bin/internal/engine.realm -/bin/mingit/ -/dev/benchmarks/mega_gallery/ -/dev/bots/.recipe_deps -/dev/bots/android_tools/ -/dev/devicelab/ABresults*.json -/dev/docs/doc/ -/dev/docs/api_docs.zip -/dev/docs/flutter.docs.zip -/dev/docs/lib/ -/dev/docs/pubspec.yaml -/dev/integration_tests/**/xcuserdata -/dev/integration_tests/**/Pods -/packages/flutter/coverage/ -version -analysis_benchmark.json - -# packages file containing multi-root paths -.packages.generated +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ # Flutter/Dart/Pub related **/doc/api/ @@ -67,97 +27,17 @@ analysis_benchmark.json .dart_tool/ .flutter-plugins .flutter-plugins-dependencies -**/generated_plugin_registrant.dart -.packages -.pub-preload-cache/ .pub-cache/ .pub/ -build/ -flutter_*.png -linked_*.ds -unlinked.ds -unlinked_spec.ds +/build/ -# Android related -**/android/**/gradle-wrapper.jar -.gradle/ -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/**/GeneratedPluginRegistrant.java -**/android/key.properties -*.jks -local.properties -**/.cxx/ - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/.last_build_id -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/ephemeral -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# macOS -**/Flutter/ephemeral/ -**/Pods/ -**/macos/Flutter/GeneratedPluginRegistrant.swift -**/macos/Flutter/ephemeral -**/xcuserdata/ - -# Windows -**/windows/flutter/ephemeral/ -**/windows/flutter/generated_plugin_registrant.cc -**/windows/flutter/generated_plugin_registrant.h -**/windows/flutter/generated_plugins.cmake - -# Linux -**/linux/flutter/ephemeral/ -**/linux/flutter/generated_plugin_registrant.cc -**/linux/flutter/generated_plugin_registrant.h -**/linux/flutter/generated_plugins.cmake - -# Coverage -coverage/ - -# Symbols +# Symbolication related app.*.symbols -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -!/dev/ci/**/Gemfile.lock -!.vscode/settings.json +# Obfuscation related +app.*.map.json -# Monorepo -.cipd -.gclient -.gclient_entries -.python-version -.gclient_previous_custom_vars -.gclient_previous_sync_commits \ No newline at end of file +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/android/settings.gradle b/android/settings.gradle index a42444d..b9e43bd 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.2.1" apply false + id "com.android.application" version "8.1.0" apply false id "org.jetbrains.kotlin.android" version "1.8.22" apply false } diff --git a/assets/auth_background.jpg b/assets/auth_background.jpg index 4ef1982..7a75ac9 100644 Binary files a/assets/auth_background.jpg and b/assets/auth_background.jpg differ diff --git a/assets/logo/logo_dark.png b/assets/logo/logo_dark.png index ba9c246..4049058 100644 Binary files a/assets/logo/logo_dark.png and b/assets/logo/logo_dark.png differ diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart index 9f3059c..978112e 100644 --- a/lib/controller/auth/login_controller.dart +++ b/lib/controller/auth/login_controller.dart @@ -10,12 +10,12 @@ class LoginController extends MyController { bool showPassword = false, isChecked = false; - final String _dummyEmail = "admin@marcobms.com"; - final String _dummyPassword = "User@123"; + final String _dummyEmail = "demo@example.com"; + final String _dummyPassword = "1234567"; @override void onInit() { - basicValidator.addField('username', required: true, label: "User_Name", validators: [MyEmailValidator()], controller: TextEditingController(text: _dummyEmail)); + basicValidator.addField('email', required: true, label: "Email", validators: [MyEmailValidator()], controller: TextEditingController(text: _dummyEmail)); basicValidator.addField('password', required: true, label: "Password", validators: [MyLengthValidator(min: 6, max: 10)], controller: TextEditingController(text: _dummyPassword)); diff --git a/lib/controller/dashboard/attendance_controller.dart b/lib/controller/dashboard/attendance_controller.dart new file mode 100644 index 0000000..51b1b67 --- /dev/null +++ b/lib/controller/dashboard/attendance_controller.dart @@ -0,0 +1,42 @@ +import 'package:marco/controller/my_controller.dart'; +import 'package:marco/helpers/widgets/my_text_utils.dart'; +import 'package:marco/model/chart_model.dart'; +import 'package:marco/model/job_recent_application_model.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; + +class AttendanceController extends MyController { + int isSelectedListingPerformanceTime = 0; + List? chartData; + TooltipBehavior? columnToolTip; + List recentApplication = []; + List dummyTexts = List.generate(12, (index) => MyTextUtils.getDummyText(60)); + + @override + void onInit() { + chartData = [ + ChartSampleData(x: 'Jan', y: 4, secondSeriesYValue: 8), + ChartSampleData(x: 'Feb', y: 9, secondSeriesYValue: 7), + ChartSampleData(x: 'Mar', y: 6, secondSeriesYValue: 5), + ChartSampleData(x: 'Apr', y: 8, secondSeriesYValue: 3), + ChartSampleData(x: 'May', y: 7, secondSeriesYValue: 9), + ChartSampleData(x: 'Jun', y: 10, secondSeriesYValue: 6), + ChartSampleData(x: 'Jul', y: 5, secondSeriesYValue: 4), + ChartSampleData(x: 'Aug', y: 3, secondSeriesYValue: 2), + ChartSampleData(x: 'Sep', y: 6, secondSeriesYValue: 10), + ChartSampleData(x: 'Oct', y: 4, secondSeriesYValue: 8), + ChartSampleData(x: 'Nov', y: 9, secondSeriesYValue: 6), + ChartSampleData(x: 'Dec', y: 7, secondSeriesYValue: 5), + ]; + columnToolTip = TooltipBehavior(enable: true); + JobRecentApplicationModel.dummyList.then((value) { + recentApplication = value.sublist(0, 5); + update(); + }); + super.onInit(); + } + + void onSelectListingPerformanceTimeToggle(index) { + isSelectedListingPerformanceTime = index; + update(); + } +} diff --git a/lib/controller/dashboard/attendance_screen_controller.dart b/lib/controller/dashboard/attendance_screen_controller.dart deleted file mode 100644 index 20c13b4..0000000 --- a/lib/controller/dashboard/attendance_screen_controller.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:get/get.dart'; -import 'package:marco/helpers/services/api_service.dart'; -import 'package:marco/model/attendance_model.dart'; -import 'package:marco/model/project_model.dart'; // Assuming you have a ProjectModel for the projects. -import 'package:marco/model/employee_model.dart'; // Assuming you have an EmployeeModel for the employees. - -class AttendanceController extends GetxController { - List attendances = []; - List projects = []; // List of projects - String? selectedProjectId; // Currently selected project ID - List employees = []; // Employees of the selected project - - @override - void onInit() { - super.onInit(); - fetchProjects(); // Fetch projects when initializing - } - - // Fetch projects from API -Future fetchProjects() async { - var response = await ApiService.getProjects(); // Call the project API - - if (response != null) { - projects = response - .map((json) => ProjectModel.fromJson(json)) - .toList(); - - // Set default to the first project if available - if (projects.isNotEmpty) { - selectedProjectId = projects.first.id.toString(); - await fetchEmployeesByProject(selectedProjectId); // Fetch employees for the first project - } - - update(['attendance_dashboard_controller']); // Notify GetBuilder with your tag - } else { - print("No projects data found or failed to fetch data."); - } -} - - - // Fetch employees by project ID - Future fetchEmployeesByProject(String? projectId) async { - if (projectId == null) return; - - var response = await ApiService.getEmployeesByProject(int.parse(projectId)); - - if (response != null) { - employees = response - .map((json) => EmployeeModel.fromJson(json)) - .toList(); - update(); // Trigger UI rebuild - } else { - print("Failed to fetch employees for project $projectId."); - } - } -} diff --git a/lib/helpers/services/api_service.dart b/lib/helpers/services/api_service.dart deleted file mode 100644 index cf130cc..0000000 --- a/lib/helpers/services/api_service.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:marco/helpers/services/storage/local_storage.dart'; - -class ApiService { - static const String baseUrl = "https://api.marcoaiot.com/api"; - - // Fetch the list of projects - static Future?> getProjects() async { - try { - String? jwtToken = LocalStorage.getJwtToken(); - if (jwtToken == null) { - print("No JWT token found. Please log in."); - return null; - } - - final response = await http.get( - Uri.parse("$baseUrl/project/list"), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $jwtToken', // Add Authorization header - }, - ); - - if (response.statusCode == 200) { - final json = jsonDecode(response.body); - print("Response body: ${response.body}"); - if (json['success'] == true) { - return json['data']; // Return the data if success is true - } else { - print("Error: ${json['message']}"); - } - } else { - print("Error fetching projects: ${response.statusCode}"); - print("Response body: ${response.body}"); - } - } catch (e) { - print("Exception while fetching projects: $e"); - } - return null; - } - - // Fetch employees by project ID - static Future?> getEmployeesByProject(int projectId) async { - try { - String? jwtToken = LocalStorage.getJwtToken(); - if (jwtToken == null) { - print("No JWT token found. Please log in."); - return null; - } - - final response = await http.get( - Uri.parse("$baseUrl/attendance/project/team?projectId=$projectId"), // Ensure correct endpoint - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $jwtToken', - }, - ); - - if (response.statusCode == 200) { - final json = jsonDecode(response.body); - print("Response body: ${response.body}"); - if (json['success'] == true) { - return json['data']; // Return employee data - } else { - print("Error: ${json['message']}"); - } - } else { - print("Error fetching employees: ${response.statusCode}"); - print("Response body: ${response.body}"); - } - } catch (e) { - print("Exception while fetching employees: $e"); - } - return null; - } -} diff --git a/lib/helpers/services/auth_service.dart b/lib/helpers/services/auth_service.dart index c9ef4d5..5ada735 100644 --- a/lib/helpers/services/auth_service.dart +++ b/lib/helpers/services/auth_service.dart @@ -1,50 +1,22 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; import 'package:marco/helpers/services/storage/local_storage.dart'; +import 'package:marco/model/user.dart'; class AuthService { static bool isLoggedIn = false; - static Future?> loginUser(Map data) async { - try { - final response = await http.post( - Uri.parse('https://api.marcoaiot.com/api/auth/login'), - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(data), - ); + static User get dummyUser => User(-1, "demo@example.com", "Denish", "Navadiya"); - if (response.statusCode == 200) { - isLoggedIn = true; - - // Parse the response to get the JWT and refresh tokens - final responseData = jsonDecode(response.body); - - // Adjusted for the actual response structure - final jwtToken = responseData['data']['token']; // Ensure this matches your actual response - - // Save the JWT token in local storage - await LocalStorage.setJwtToken(jwtToken); - print("JWT Token: $jwtToken"); - - // Optionally save refresh token if available - final refreshToken = responseData['data']['refreshToken']; - if (refreshToken != null) { - await LocalStorage.setRefreshToken(refreshToken); - print("Refresh Token: $refreshToken"); - } - - // Save the login state in local storage - await LocalStorage.setLoggedInUser(true); - - // Return null to indicate success - return null; - } else if (response.statusCode == 401) { - return {"password": "Invalid email or password"}; - } else { - return {"error": "Something went wrong. Please try again."}; - } - } catch (e) { - return {"error": "Network error. Please check your connection."}; + static Future?> loginUser( + Map data) async { + await Future.delayed(Duration(seconds: 1)); + if (data['email'] != dummyUser.email) { + return {"email": "This email is not registered"}; + } else if (data['password'] != "1234567") { + return {"password": "Password is incorrect"}; } + + isLoggedIn = true; + await LocalStorage.setLoggedInUser(true); + return null; } } diff --git a/lib/helpers/services/storage/local_storage.dart b/lib/helpers/services/storage/local_storage.dart index 1408585..7718c10 100644 --- a/lib/helpers/services/storage/local_storage.dart +++ b/lib/helpers/services/storage/local_storage.dart @@ -7,8 +7,6 @@ class LocalStorage { static const String _loggedInUserKey = "user"; static const String _themeCustomizerKey = "theme_customizer"; static const String _languageKey = "lang_code"; - static const String _jwtTokenKey = "jwt_token"; - static const String _refreshTokenKey = "refresh_token"; static SharedPreferences? _preferencesInstance; @@ -49,34 +47,4 @@ class LocalStorage { static Future removeLoggedInUser() async { return preferences.remove(_loggedInUserKey); } - - // Add methods to handle JWT and Refresh Token - static Future setToken(String key, String token) { - return preferences.setString(key, token); - } - - static String? getToken(String key) { - return preferences.getString(key); - } - - static Future removeToken(String key) { - return preferences.remove(key); - } - - // Convenience methods for getting the JWT and Refresh tokens - static String? getJwtToken() { - return getToken(_jwtTokenKey); - } - - static String? getRefreshToken() { - return getToken(_refreshTokenKey); - } - - static Future setJwtToken(String jwtToken) { - return setToken(_jwtTokenKey, jwtToken); - } - - static Future setRefreshToken(String refreshToken) { - return setToken(_refreshTokenKey, refreshToken); - } } diff --git a/lib/model/attendance_model.dart b/lib/model/attendance_model.dart deleted file mode 100644 index f12657c..0000000 --- a/lib/model/attendance_model.dart +++ /dev/null @@ -1,37 +0,0 @@ -class AttendanceModel { - final int id; - final String name; - final String projectAddress; - final String contactPerson; - final DateTime startDate; - final DateTime endDate; - final int teamSize; - final int completedWork; - final int plannedWork; - - AttendanceModel({ - required this.id, - required this.name, - required this.projectAddress, - required this.contactPerson, - required this.startDate, - required this.endDate, - required this.teamSize, - required this.completedWork, - required this.plannedWork, - }); - -factory AttendanceModel.fromJson(Map json) { - return AttendanceModel( - id: int.tryParse(json['id'].toString()) ?? 0, - name: json['name'] ?? '', - projectAddress: json['projectAddress'] ?? '', - contactPerson: json['contactPerson'] ?? '', - startDate: DateTime.tryParse(json['startDate'].toString()) ?? DateTime.now(), - endDate: DateTime.tryParse(json['endDate'].toString()) ?? DateTime.now(), - teamSize: int.tryParse(json['teamSize'].toString()) ?? 0, - completedWork: int.tryParse(json['completedWork'].toString()) ?? 0, - plannedWork: int.tryParse(json['plannedWork'].toString()) ?? 0, - ); -} -} diff --git a/lib/model/employee_model.dart b/lib/model/employee_model.dart deleted file mode 100644 index f73a24c..0000000 --- a/lib/model/employee_model.dart +++ /dev/null @@ -1,28 +0,0 @@ -class EmployeeModel { - final int id; - final String name; - final String designation; - final String checkIn; - final String checkOut; - final int actions; - - EmployeeModel({ - required this.id, - required this.name, - required this.designation, - required this.checkIn, - required this.checkOut, - required this.actions, - }); - - factory EmployeeModel.fromJson(Map json) { - return EmployeeModel( - id: json['employeeId'] ?? 0, - name: '${json['firstName']} ${json['lastName']}', - designation: json['jobRoleName'] ?? '', - checkIn: json['checkIn'] ?? '-', // Make sure your API returns this field - checkOut: json['checkOut'] ?? '-', - actions: json['actions'] ?? 0, // Make sure your API returns this field - ); - } -} diff --git a/lib/model/project_model.dart b/lib/model/project_model.dart deleted file mode 100644 index dc020fd..0000000 --- a/lib/model/project_model.dart +++ /dev/null @@ -1,62 +0,0 @@ -class ProjectModel { - final int id; // Unique identifier for the project - final String name; // Name of the project - final String projectAddress; // Address of the project - final String contactPerson; // Contact person for the project - final DateTime startDate; // Start date of the project - final DateTime endDate; // End date of the project - final int teamSize; // Number of people in the team - final int completedWork; // Completed work percentage - final int plannedWork; // Planned work for the project - final int projectStatusId; // Status ID for the project - final int tenantId; // Tenant ID associated with the project - - // Constructor - ProjectModel({ - required this.id, - required this.name, - required this.projectAddress, - required this.contactPerson, - required this.startDate, - required this.endDate, - required this.teamSize, - required this.completedWork, - required this.plannedWork, - required this.projectStatusId, - required this.tenantId, - }); - - // Factory method to create an instance of ProjectModel from a JSON object - factory ProjectModel.fromJson(Map json) { - return ProjectModel( - id: json['id'], - name: json['name'], - projectAddress: json['projectAddress'], - contactPerson: json['contactPerson'], - startDate: DateTime.parse(json['startDate']), - endDate: DateTime.parse(json['endDate']), - teamSize: json['teamSize'], - completedWork: json['completedWork'], - plannedWork: json['plannedWork'], - projectStatusId: json['projectStatusId'], - tenantId: json['tenantId'], - ); - } - - // Method to convert the ProjectModel instance back to a JSON object - Map toJson() { - return { - 'id': id, - 'name': name, - 'projectAddress': projectAddress, - 'contactPerson': contactPerson, - 'startDate': startDate.toIso8601String(), - 'endDate': endDate.toIso8601String(), - 'teamSize': teamSize, - 'completedWork': completedWork, - 'plannedWork': plannedWork, - 'projectStatusId': projectStatusId, - 'tenantId': tenantId, - }; - } -} diff --git a/lib/model/user.dart b/lib/model/user.dart index 53656f2..f1c11f1 100644 --- a/lib/model/user.dart +++ b/lib/model/user.dart @@ -1,9 +1,9 @@ import 'package:marco/model/identifier_model.dart'; class User extends IdentifierModel { - final String username, firstName, lastName; + final String email, firstName, lastName; - User(super.id, this.username, this.firstName, this.lastName); + User(super.id, this.email, this.firstName, this.lastName); String get name => "$firstName $lastName"; diff --git a/lib/res/assets_res.dart b/lib/res/assets_res.dart deleted file mode 100644 index f055fc7..0000000 --- a/lib/res/assets_res.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Generated file. Do not edit. -// This file is generated by the iFlutter - -// ignore_for_file: constant_identifier_names -// ignore_for_file: lines_longer_than_80_chars -class AssetsRes { - AssetsRes._(); - - static const String PROJECT_NAME = 'marco'; - static const String PROJECT_VERSION = '1.0.0+1'; -} diff --git a/lib/routes.dart b/lib/routes.dart index 9fb7aec..8789773 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -9,8 +9,8 @@ import 'package:marco/view/dashboard/ecommerce_screen.dart'; import 'package:marco/view/error_pages/coming_soon_screen.dart'; import 'package:marco/view/error_pages/error_404_screen.dart'; import 'package:marco/view/error_pages/error_500_screen.dart'; -// import 'package:marco/view/dashboard/attendance_screen.dart'; -import 'package:marco/view/dashboard/attendanceScreen.dart'; +import 'package:marco/view/dashboard/attendance_screen.dart'; + class AuthMiddleware extends GetMiddleware { @override RouteSettings? redirect(String? route) { @@ -23,7 +23,7 @@ getPageRoute() { GetPage(name: '/', page: () => const EcommerceScreen(), middlewares: [AuthMiddleware()]), // Dashboard - GetPage(name: '/dashboard/attendance', page: () => AttendanceScreen(), middlewares: [AuthMiddleware()]), + GetPage(name: '/dashboard/attendance', page: () => const AttendanceScreen(), middlewares: [AuthMiddleware()]), // Authentication GetPage(name: '/auth/login', page: () => LoginScreen()), diff --git a/lib/view/auth/login_screen.dart b/lib/view/auth/login_screen.dart index eb99c61..04e0a6a 100644 --- a/lib/view/auth/login_screen.dart +++ b/lib/view/auth/login_screen.dart @@ -9,7 +9,6 @@ import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/widgets/my_text_style.dart'; import 'package:marco/view/layouts/auth_layout.dart'; -import 'package:marco/images.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -18,7 +17,7 @@ class LoginScreen extends StatefulWidget { State createState() => _LoginScreenState(); } -class _LoginScreenState extends State with UIMixin { +class _LoginScreenState extends State with UIMixin{ late LoginController controller; @override @@ -30,198 +29,114 @@ class _LoginScreenState extends State with UIMixin { @override Widget build(BuildContext context) { return AuthLayout( - child: GetBuilder( + child: GetBuilder( init: controller, tag: 'login_controller', builder: (controller) { - return Form( - key: controller.basicValidator.formKey, - child: SingleChildScrollView( - padding: MySpacing.xy(2, 40), - child: Container( - width: double.infinity, - padding: MySpacing.all(24), - decoration: BoxDecoration( - color: theme.colorScheme.primary.withOpacity(0.02), - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: contentTheme.primary.withOpacity(0.5), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - /// Logo - Center( - child: Image.asset( - Images.logoDark, - height: 120, - fit: BoxFit.contain, - ), - ), - MySpacing.height(20), - - /// Welcome Text - Center( - child: MyText.bodyLarge("Welcome Back!", fontWeight: 600), - ), - MySpacing.height(4), - Center( - child: MyText.bodySmall("Please sign in to continue."), - ), - MySpacing.height(20), - - /// Email Field - MyText.bodySmall("Email Address", fontWeight: 600), - MySpacing.height(8), - Material( - elevation: 2, - shadowColor: contentTheme.secondary.withAlpha(30), - borderRadius: BorderRadius.circular(12), - child: TextFormField( - validator: - controller.basicValidator.getValidation('username'), - controller: - controller.basicValidator.getController('username'), - keyboardType: TextInputType.emailAddress, - style: MyTextStyle.labelMedium(), - decoration: InputDecoration( - hintText: "Enter your email", - hintStyle: MyTextStyle.bodySmall(xMuted: true), - filled: true, - fillColor: theme.cardColor, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(2), - borderSide: BorderSide.none, - ), - prefixIcon: const Icon(LucideIcons.mail, size: 18), - contentPadding: MySpacing.xy(12, 16), - ), - ), - ), - MySpacing.height(16), - - /// Password Field Label - MyText.bodySmall("Password", fontWeight: 600), - MySpacing.height(8), - Material( - elevation: 2, - shadowColor: contentTheme.secondary.withAlpha(25), - borderRadius: BorderRadius.circular(12), - child: TextFormField( - validator: - controller.basicValidator.getValidation('password'), - controller: - controller.basicValidator.getController('password'), - keyboardType: TextInputType.visiblePassword, - obscureText: !controller.showPassword, - style: MyTextStyle.labelMedium(), - decoration: InputDecoration( - hintText: "Enter your password", - hintStyle: MyTextStyle.bodySmall(xMuted: true), - filled: true, - fillColor: theme.cardColor, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(2), - borderSide: BorderSide.none, - ), - prefixIcon: const Icon(LucideIcons.lock, size: 18), - suffixIcon: InkWell( - onTap: controller.onChangeShowPassword, - child: Icon( - controller.showPassword - ? LucideIcons.eye - : LucideIcons.eye_off, - size: 18, - ), - ), - contentPadding: MySpacing.all(3), - ), - ), - ), - - MySpacing.height(16), - - /// Remember Me + Forgot Password - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return Form( + key: controller.basicValidator.formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + MyText.titleLarge("Sign in with email", fontWeight: 600), + MySpacing.height(12), + MyText.bodyMedium("Make a new doc to bring your words, data and terms together. For free", fontWeight: 600, xMuted: true), + MySpacing.height(12), + TextFormField( + validator: controller.basicValidator.getValidation('email'), + controller: controller.basicValidator.getController('email'), + keyboardType: TextInputType.emailAddress, + style: MyTextStyle.labelMedium(), + decoration: InputDecoration( + labelText: "Email Address", + labelStyle: MyTextStyle.bodySmall(xMuted: true), + border: OutlineInputBorder(borderSide: BorderSide.none), + filled: true, + fillColor: contentTheme.secondary.withAlpha(36), + prefixIcon: const Icon(LucideIcons.mail, size: 16), + contentPadding: MySpacing.all(14), + isDense: true, + isCollapsed: true, + floatingLabelBehavior: FloatingLabelBehavior.never), + ), + MySpacing.height(20), + TextFormField( + validator: controller.basicValidator.getValidation('password'), + controller: controller.basicValidator.getController('password'), + keyboardType: TextInputType.visiblePassword, + obscureText: !controller.showPassword, + style: MyTextStyle.labelMedium(), + decoration: InputDecoration( + labelText: "Password", + labelStyle: MyTextStyle.bodySmall(xMuted: true), + border: OutlineInputBorder(borderSide: BorderSide.none), + filled: true, + fillColor: contentTheme.secondary.withAlpha(36), + prefixIcon: const Icon(LucideIcons.mail, size: 16), + contentPadding: MySpacing.all(16), + isCollapsed: true, + isDense: true, + floatingLabelBehavior: FloatingLabelBehavior.never, + suffixIcon: InkWell( + onTap: controller.onChangeShowPassword, + child: Icon(controller.showPassword ? LucideIcons.eye : LucideIcons.eye_off, size: 16), + )), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () => controller.onChangeCheckBox(!controller.isChecked), + child: Row( children: [ - InkWell( - onTap: () => controller - .onChangeCheckBox(!controller.isChecked), - child: Row( - children: [ - Checkbox( - onChanged: controller.onChangeCheckBox, - value: controller.isChecked, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - fillColor: WidgetStatePropertyAll( - contentTheme.secondary), - checkColor: contentTheme.onPrimary, - visualDensity: getCompactDensity, - materialTapTargetSize: - MaterialTapTargetSize.shrinkWrap, - ), - MySpacing.width(8), - MyText.bodySmall("Remember Me"), - ], - ), - ), - MyButton.text( - onPressed: controller.goToForgotPassword, - elevation: 0, - padding: MySpacing.xy(8, 0), - splashColor: contentTheme.secondary.withAlpha(36), - child: MyText.bodySmall( - 'Forgot password?', - fontWeight: 600, - color: contentTheme.secondary, - ), + Checkbox( + onChanged: controller.onChangeCheckBox, + value: controller.isChecked, + fillColor: WidgetStatePropertyAll(Colors.white), + activeColor: theme.colorScheme.primary, + checkColor: contentTheme.primary, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: getCompactDensity, ), + MySpacing.width(8), + MyText.bodySmall("Remember Me"), ], ), - MySpacing.height(28), - - /// Login Button - Center( - child: MyButton.rounded( - onPressed: controller.onLogin, - elevation: 2, - padding: MySpacing.xy(24, 16), - borderRadiusAll: 16, - backgroundColor: contentTheme.primary, - child: MyText.labelMedium( - 'Login', - fontWeight: 600, - color: contentTheme.onPrimary, - ), - ), - ), - MySpacing.height(16), - - /// Register Link - Center( - child: MyButton.text( - onPressed: controller.gotoRegister, - elevation: 0, - padding: MySpacing.xy(12, 8), - splashColor: contentTheme.secondary.withAlpha(30), - child: MyText.bodySmall( - "Request a Demo", - color: contentTheme.secondary, - fontWeight: 600, - ), - ), - ), - ], + ), + MyButton.text( + onPressed: controller.goToForgotPassword, + elevation: 0, + padding: MySpacing.xy(8, 0), + splashColor: contentTheme.secondary.withAlpha(36), + child: MyText.bodySmall('Forgot password?', color: contentTheme.secondary), + ), + ], + ), + MySpacing.height(28), + Center( + child: MyButton.rounded( + onPressed: controller.onLogin, + elevation: 0, + padding: MySpacing.xy(20, 16), + backgroundColor: contentTheme.primary, + child: MyText.labelMedium('Login', color: contentTheme.onPrimary), ), ), - ), - ); - }, - ), + Center( + child: MyButton.text( + onPressed: controller.gotoRegister, + elevation: 0, + padding: MySpacing.x(16), + splashColor: contentTheme.secondary.withValues(alpha:0.1), + child: MyText.bodySmall('I haven\'t account'), + ), + ), + ], + ), + ); + },), ); } } diff --git a/lib/view/dashboard/attendanceScreen.dart b/lib/view/dashboard/attendanceScreen.dart deleted file mode 100644 index e2f70cf..0000000 --- a/lib/view/dashboard/attendanceScreen.dart +++ /dev/null @@ -1,200 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_lucide/flutter_lucide.dart'; -import 'package:get/get.dart'; -import 'package:marco/helpers/theme/app_theme.dart'; -import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; -import 'package:marco/helpers/utils/my_shadow.dart'; -import 'package:marco/helpers/utils/utils.dart'; -import 'package:marco/helpers/widgets/my_breadcrumb.dart'; -import 'package:marco/helpers/widgets/my_breadcrumb_item.dart'; -import 'package:marco/helpers/widgets/my_card.dart'; -import 'package:marco/helpers/widgets/my_container.dart'; -import 'package:marco/helpers/widgets/my_flex.dart'; -import 'package:marco/helpers/widgets/my_flex_item.dart'; -import 'package:marco/helpers/widgets/my_list_extension.dart'; -import 'package:marco/helpers/widgets/my_spacing.dart'; -import 'package:marco/helpers/widgets/my_text.dart'; -import 'package:marco/view/layouts/layout.dart'; -import 'package:marco/controller/dashboard/attendance_screen_controller.dart'; - -class AttendanceScreen extends StatefulWidget { - const AttendanceScreen({super.key}); - - @override - State createState() => _AttendanceScreenState(); -} - -class _AttendanceScreenState extends State with UIMixin { - AttendanceController attendanceController = Get.put(AttendanceController()); - - @override - Widget build(BuildContext context) { - return Layout( - child: GetBuilder( - init: attendanceController, - tag: 'attendance_dashboard_controller', - builder: (controller) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: MySpacing.x(flexSpacing), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - MyText.titleMedium("Attendance", - fontSize: 18, fontWeight: 600), - MyBreadcrumb( - children: [ - MyBreadcrumbItem(name: 'Dashboard'), - MyBreadcrumbItem(name: 'Attendance', active: true), - ], - ), - ], - ), - ), - MySpacing.height(flexSpacing), - Padding( - padding: MySpacing.x(flexSpacing / 2), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MySpacing.height(flexSpacing), - MyFlex( - children: [ - MyFlexItem(child: attendanceTableCard()), - ], - ), - ], - ), - ), - ], - ); - }, - ), - ); - } - - Widget attendanceTableCard() { - return MyCard.bordered( - borderRadiusAll: 4, - border: Border.all(color: Colors.grey.withAlpha(50)), - shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), - paddingAll: 24, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: MyContainer.bordered( - padding: MySpacing.xy(8, 4), - child: PopupMenuButton( - onSelected: (value) { - setState(() { - attendanceController.selectedProjectId = value; - attendanceController.fetchEmployeesByProject(value); - }); - }, - itemBuilder: (BuildContext context) { - return attendanceController.projects.map((project) { - return PopupMenuItem( - value: project.id.toString(), - height: 32, - child: MyText.bodySmall( - project.name, - color: theme.colorScheme.onSurface, - fontWeight: 600, - ), - ); - }).toList(); - }, - color: theme.cardTheme.color, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - MyText.labelSmall( - attendanceController.selectedProjectId != null - ? attendanceController.projects - .firstWhereOrNull((proj) => - proj.id.toString() == - attendanceController - .selectedProjectId) - ?.name ?? - 'Select a Project' - : 'Select a Project', - color: theme.colorScheme.onSurface, - ), - Icon(LucideIcons.chevron_down, - size: 16, color: theme.colorScheme.onSurface), - ], - ), - ), - ), - ), - ], - ), - MySpacing.height(24), - attendanceController.employees.isEmpty - ? const Center(child: CircularProgressIndicator()) - : SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: DataTable( - sortAscending: true, - columnSpacing: 88, - onSelectAll: (_) => {}, - headingRowColor: WidgetStatePropertyAll( - contentTheme.primary.withAlpha(40)), - dataRowMaxHeight: 60, - showBottomBorder: true, - clipBehavior: Clip.antiAliasWithSaveLayer, - border: TableBorder.all( - borderRadius: BorderRadius.circular(4), - style: BorderStyle.solid, - width: 0.4, - color: Colors.grey, - ), - columns: [ - DataColumn( - label: MyText.labelLarge('ID', - color: contentTheme.primary)), - DataColumn( - label: MyText.labelLarge('Name', - color: contentTheme.primary)), - DataColumn( - label: MyText.labelLarge('Designation', - color: contentTheme.primary)), - DataColumn( - label: MyText.labelLarge('Check In', - color: contentTheme.primary)), - DataColumn( - label: MyText.labelLarge('Check Out', - color: contentTheme.primary)), - DataColumn( - label: MyText.labelLarge('Actions', - color: contentTheme.primary)), - ], - rows: attendanceController.employees - .mapIndexed((index, employee) => DataRow(cells: [ - DataCell(MyText.bodyMedium(employee.id.toString(), - fontWeight: 600)), - DataCell(MyText.bodyMedium(employee.name, - fontWeight: 600)), - DataCell(MyText.bodyMedium(employee.designation, - fontWeight: 600)), - DataCell(MyText.bodyMedium(employee.checkIn, - fontWeight: 600)), - DataCell(MyText.bodyMedium(employee.checkOut, - fontWeight: 600)), - DataCell(MyText.bodyMedium(employee.actions.toString(), - fontWeight: 600)), - ])) - .toList(), - ), - ), - ], - ), - ); - } -} diff --git a/lib/view/dashboard/attendance_screen.dart b/lib/view/dashboard/attendance_screen.dart new file mode 100644 index 0000000..d81c95f --- /dev/null +++ b/lib/view/dashboard/attendance_screen.dart @@ -0,0 +1,435 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; +import 'package:get/get.dart'; +import 'package:marco/helpers/theme/app_theme.dart'; +import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; +import 'package:marco/helpers/utils/my_shadow.dart'; +import 'package:marco/helpers/utils/utils.dart'; +import 'package:marco/helpers/widgets/my_breadcrumb.dart'; +import 'package:marco/helpers/widgets/my_breadcrumb_item.dart'; +import 'package:marco/helpers/widgets/my_card.dart'; +import 'package:marco/helpers/widgets/my_container.dart'; +import 'package:marco/helpers/widgets/my_flex.dart'; +import 'package:marco/helpers/widgets/my_flex_item.dart'; +import 'package:marco/helpers/widgets/my_list_extension.dart'; +import 'package:marco/helpers/widgets/my_spacing.dart'; +import 'package:marco/helpers/widgets/my_text.dart'; +import 'package:marco/images.dart'; +import 'package:marco/model/chart_model.dart'; +import 'package:marco/view/layouts/layout.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:marco/controller/dashboard/attendance_controller.dart'; +class AttendanceScreen extends StatefulWidget { + const AttendanceScreen({super.key}); + + @override + State createState() => _AttendanceScreenState(); +} + +class _AttendanceScreenState extends State with UIMixin { + AttendanceController controller = Get.put(AttendanceController()); + + @override + Widget build(BuildContext context) { + return Layout( + child: GetBuilder( + init: controller, + tag: 'attendance_dashboard_controller', + builder: (controller) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: MySpacing.x(flexSpacing), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + MyText.titleMedium("Attendance", fontSize: 18, fontWeight: 600), + MyBreadcrumb( + children: [ + MyBreadcrumbItem(name: 'Dashboard'), + MyBreadcrumbItem(name: 'Attendance', active: true), + ], + ), + ], + ), + ), + MySpacing.height(flexSpacing), + Padding( + padding: MySpacing.x(flexSpacing / 2), + child: MyFlex( + children: [ + MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.briefcase, '245', 'EMPLOYEES IN SYSTEM', contentTheme.primary)), + MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.file_text, '3201', 'CANDIDATES IN DATA', contentTheme.secondary)), + MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.map_pin, '56', 'LOCATIONS SERVED', contentTheme.success)), + MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.user_plus, '312', 'RECRUITER NETWORK', contentTheme.info)), + MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.credit_card, '689', 'ACTIVE SUBSCRIPTIONS', contentTheme.purple)), + MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.cloud_upload, '82%', 'RESUME UPLOAD RATE', contentTheme.pink)), + MyFlexItem(sizes: 'lg-4', child: workingFormat()), + MyFlexItem(sizes: 'lg-8 md-6', child: listingPerformance()), + MyFlexItem(sizes: 'lg-4 md-6', child: recentCandidate()), + MyFlexItem(sizes: 'lg-4 md-6', child: mostViewedCVs()), + MyFlexItem(sizes: 'lg-4 md-6', child: recentChat()), + MyFlexItem(child: recentApplication()), + ], + )), + ], + ); + }, + ), + ); + } + + Widget stats(IconData? icon, String title, String subTitle, Color color) { + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + child: Row( + children: [ + MyContainer( + paddingAll: 12, + color: color, + child: Icon(icon, color: contentTheme.light, size: 16), + ), + MySpacing.width(16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.titleMedium(title, fontWeight: 600), + MySpacing.height(4), + MyText.labelSmall(subTitle, xMuted: true, maxLines: 1, overflow: TextOverflow.ellipsis), + ], + ), + ) + ], + ), + ); + } + + Widget workingFormat() { + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + height: 408, + child: Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ + MyText.bodyMedium("Working Format", height: .8, fontWeight: 600), + SfCircularChart(legend: Legend(isVisible: true, position: LegendPosition.bottom, overflowMode: LegendItemOverflowMode.wrap), series: [ + DoughnutSeries( + explode: true, + dataSource: [ + ChartSampleData(x: 'OnSite', y: 55, text: '55%'), + ChartSampleData(x: 'Remote', y: 31, text: '31%'), + ChartSampleData(x: 'Hybrid', y: 7.7, text: '7.7%'), + ], + xValueMapper: (ChartSampleData data, _) => data.x as String, + yValueMapper: (ChartSampleData data, _) => data.y, + dataLabelMapper: (ChartSampleData data, _) => data.text, + dataLabelSettings: DataLabelSettings(isVisible: true)) + ]) + ]), + ); + } + + Widget listingPerformance() { + Widget isSelectTime(String title, int index) { + bool isSelect = controller.isSelectedListingPerformanceTime == index; + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 0, position: MyShadowPosition.bottom), + paddingAll: 4, + color: isSelect ? contentTheme.secondary.withValues(alpha:0.15) : null, + onTap: () => controller.onSelectListingPerformanceTimeToggle(index), + child: MyText.labelSmall(title, fontWeight: 600, color: isSelect ? contentTheme.secondary : null), + ); + } + + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: MyText.bodyMedium("Listing Performance", fontWeight: 600, overflow: TextOverflow.ellipsis), + ), + isSelectTime("Day", 0), + MySpacing.width(12), + isSelectTime("Week", 1), + MySpacing.width(12), + isSelectTime("Month", 2), + ], + ), + MySpacing.height(24), + SizedBox( + height: 310, + child: SfCartesianChart( + margin: MySpacing.zero, + plotAreaBorderWidth: 0, + primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)), + primaryYAxis: NumericAxis( + maximum: 20, + minimum: 0, + interval: 4, + axisLine: AxisLine(width: 0), + majorTickLines: MajorTickLines(size: 0), + ), + series: [ + ColumnSeries( + width: .7, + spacing: .2, + dataSource: controller.chartData, + color: theme.colorScheme.primary, + xValueMapper: (ChartSampleData sales, _) => sales.x as String, + yValueMapper: (ChartSampleData sales, _) => sales.y, + name: 'Views'), + ColumnSeries( + dataSource: controller.chartData, + width: .7, + spacing: .2, + color: theme.colorScheme.secondary, + xValueMapper: (ChartSampleData sales, _) => sales.x as String, + yValueMapper: (ChartSampleData sales, _) => sales.secondSeriesYValue, + name: 'Application') + ], + legend: Legend(isVisible: true, position: LegendPosition.bottom), + tooltipBehavior: controller.columnToolTip), + ) + ], + ), + ); + } + + Widget recentCandidate() { + Widget candidatesData(String image, title, subtitle) { + return Row( + children: [ + MyContainer.rounded( + paddingAll: 0, + height: 44, + width: 44, + clipBehavior: Clip.antiAliasWithSaveLayer, + child: Image.asset(image, fit: BoxFit.cover), + ), + MySpacing.width(12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.bodyMedium(title, fontWeight: 600), + MyText.bodySmall(subtitle, fontWeight: 600, xMuted: true, maxLines: 1, overflow: TextOverflow.visible) + ], + ), + ) + ], + ); + } + + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.bodyMedium("Recent Candidate", fontWeight: 600), + MySpacing.height(24), + candidatesData(Images.avatars[3], "Sophia Williams", controller.dummyTexts[0]), + MySpacing.height(24), + candidatesData(Images.avatars[4], "Ethan Johnson", controller.dummyTexts[1]), + MySpacing.height(24), + candidatesData(Images.avatars[5], "Olivia Martinez", controller.dummyTexts[2]), + MySpacing.height(24), + candidatesData(Images.avatars[6], "Liam Brown", controller.dummyTexts[3]), + MySpacing.height(24), + candidatesData(Images.avatars[7], "Ava Davis", controller.dummyTexts[4]), + MySpacing.height(24), + candidatesData(Images.avatars[8], "Mason Lee", controller.dummyTexts[5]), + ], + )); + } + + Widget mostViewedCVs() { + Widget cv(String title) { + return Row( + children: [ + MyContainer.rounded( + paddingAll: 0, + height: 44, + width: 44, + clipBehavior: Clip.antiAliasWithSaveLayer, + color: contentTheme.primary.withAlpha(40), + child: Icon(LucideIcons.file_text, color: contentTheme.primary), + ), + MySpacing.width(12), + Expanded(child: MyText.bodyMedium(title, fontWeight: 600, overflow: TextOverflow.ellipsis)), + InkWell(onTap: () {}, child: Icon(LucideIcons.download)) + ], + ); + } + + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.bodyMedium("Most Viewed CV's", fontWeight: 600), + MySpacing.height(24), + cv("Isabella Green"), + MySpacing.height(24), + cv("James Turner"), + MySpacing.height(24), + cv("Charlotte Scott"), + MySpacing.height(24), + cv("Oliver King"), + MySpacing.height(24), + cv("Lucas Carter"), + MySpacing.height(24), + cv("Mia Brooks"), + ], + ), + ); + } + + Widget recentChat() { + Widget chat(String image, name, message) { + return Row( + children: [ + MyContainer.rounded( + paddingAll: 0, + height: 44, + width: 44, + clipBehavior: Clip.antiAliasWithSaveLayer, + child: Image.asset(image, fit: BoxFit.cover), + ), + MySpacing.width(16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.bodyMedium(name, fontWeight: 600), + MyText.labelSmall(message, fontWeight: 600, maxLines: 1, muted: true, overflow: TextOverflow.ellipsis), + ], + )), + MySpacing.width(28), + Icon(LucideIcons.message_square, size: 20) + ], + ); + } + + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + MyText.bodyMedium("Recent Chat", fontWeight: 600), + MySpacing.height(24), + chat(Images.avatars[0], "Sophia", controller.dummyTexts[6]), + MySpacing.height(24), + chat(Images.avatars[1], "Liam", controller.dummyTexts[5]), + MySpacing.height(24), + chat(Images.avatars[2], "Charlotte", controller.dummyTexts[4]), + MySpacing.height(24), + chat(Images.avatars[3], "Oliver", controller.dummyTexts[3]), + MySpacing.height(24), + chat(Images.avatars[4], "Amelia", controller.dummyTexts[2]), + MySpacing.height(24), + chat(Images.avatars[5], "James", controller.dummyTexts[1]) + ])); + } + + Widget recentApplication() { + return MyCard.bordered( + borderRadiusAll: 4, + border: Border.all(color: Colors.grey.withValues(alpha:.2)), + shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom), + paddingAll: 24, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.bodyMedium("Recent Application", fontWeight: 600), + MySpacing.height(24), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: DataTable( + sortAscending: true, + columnSpacing: 88, + onSelectAll: (_) => {}, + headingRowColor: WidgetStatePropertyAll(contentTheme.primary.withAlpha(40)), + dataRowMaxHeight: 60, + showBottomBorder: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + border: TableBorder.all(borderRadius: BorderRadius.circular(4), style: BorderStyle.solid, width: .4, color: Colors.grey), + columns: [ + DataColumn(label: MyText.labelLarge('S.No', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Candidate', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Category', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Designation', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Mail', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Location', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Date', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Type', color: contentTheme.primary)), + DataColumn(label: MyText.labelLarge('Action', color: contentTheme.primary)), + ], + rows: controller.recentApplication + .mapIndexed((index, data) => DataRow(cells: [ + DataCell(MyText.bodyMedium("#${data.id}", fontWeight: 600)), + DataCell(Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + MyContainer( + height: 40, + width: 40, + paddingAll: 0, + child: Image.asset(Images.avatars[index % Images.avatars.length], fit: BoxFit.cover), + ), + MySpacing.width(24), + MyText.labelMedium(data.candidate, fontWeight: 600) + ], + )), + DataCell(MyText.labelMedium(data.category, fontWeight: 600)), + DataCell(MyText.labelMedium(data.designation, fontWeight: 600)), + DataCell(MyText.labelMedium(data.mail, fontWeight: 600)), + DataCell(MyText.labelMedium(data.location, fontWeight: 600)), + DataCell(MyText.labelMedium("${Utils.getDateStringFromDateTime(data.date)}", fontWeight: 600)), + DataCell(MyText.labelMedium(data.type, fontWeight: 600)), + DataCell(Row( + children: [ + MyContainer( + onTap: () {}, + color: contentTheme.primary, + paddingAll: 8, + child: Icon(LucideIcons.download, size: 16, color: contentTheme.onPrimary), + ), + MySpacing.width(12), + MyContainer( + onTap: () {}, + color: contentTheme.secondary, + paddingAll: 8, + child: Icon(LucideIcons.pencil, size: 16, color: contentTheme.onPrimary), + ), + ], + )) + ])) + .toList()), + ) + ], + ), + ); + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 0795ff4..8d64b90 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,16 +5,12 @@ import FlutterMacOS import Foundation -import file_picker -import geolocator_apple import path_provider_foundation import quill_native_bridge_macos import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) - GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) QuillNativeBridgePlugin.register(with: registry.registrar(forPlugin: "QuillNativeBridgePlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index ae4dd33..f074c30 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -157,10 +157,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: cacfdc5abe93e64d418caa9256eef663499ad791bb688d9fd12c85a311968fba + sha256: "89500471922dd3a89ab0d6e13ab4a2268c25474bff4ca7c628f55c76e0ced1de" url: "https://pub.dev" source: hosted - version: "8.3.2" + version: "8.1.5" file_selector_linux: dependency: transitive description: @@ -185,14 +185,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.3+3" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -301,54 +293,6 @@ packages: description: flutter source: sdk version: "0.0.0" - geolocator: - dependency: "direct main" - description: - name: geolocator - sha256: "5c23f3613f50586c0bbb2b8f970240ae66b3bd992088cf60dd5ee2e6f7dde3a8" - url: "https://pub.dev" - source: hosted - version: "9.0.2" - geolocator_android: - dependency: transitive - description: - name: geolocator_android - sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d - url: "https://pub.dev" - source: hosted - version: "4.6.2" - geolocator_apple: - dependency: transitive - description: - name: geolocator_apple - sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 - url: "https://pub.dev" - source: hosted - version: "2.3.13" - geolocator_platform_interface: - dependency: transitive - description: - name: geolocator_platform_interface - sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" - url: "https://pub.dev" - source: hosted - version: "4.2.6" - geolocator_web: - dependency: transitive - description: - name: geolocator_web - sha256: "102e7da05b48ca6bf0a5bda0010f886b171d1a08059f01bfe02addd0175ebece" - url: "https://pub.dev" - source: hosted - version: "2.2.1" - geolocator_windows: - dependency: transitive - description: - name: geolocator_windows - sha256: "4f4218f122a6978d0ad655fa3541eea74c67417440b09f0657238810d5af6bdc" - url: "https://pub.dev" - source: hosted - version: "0.1.3" get: dependency: "direct main" description: @@ -422,7 +366,7 @@ packages: source: hosted version: "0.15.5" http: - dependency: "direct main" + dependency: transitive description: name: http sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 @@ -581,54 +525,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" - permission_handler: - dependency: "direct main" - description: - name: permission_handler - sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" - url: "https://pub.dev" - source: hosted - version: "11.4.0" - permission_handler_android: - dependency: transitive - description: - name: permission_handler_android - sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc - url: "https://pub.dev" - source: hosted - version: "12.1.0" - permission_handler_apple: - dependency: transitive - description: - name: permission_handler_apple - sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 - url: "https://pub.dev" - source: hosted - version: "9.4.7" - permission_handler_html: - dependency: transitive - description: - name: permission_handler_html - sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.dev" - source: hosted - version: "0.1.3+5" - permission_handler_platform_interface: - dependency: transitive - description: - name: permission_handler_platform_interface - sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.dev" - source: hosted - version: "4.3.0" - permission_handler_windows: - dependency: transitive - description: - name: permission_handler_windows - sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.dev" - source: hosted - version: "0.2.1" platform: dependency: transitive description: @@ -810,14 +706,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.1" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" stack_trace: dependency: transitive description: @@ -1010,14 +898,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" - uuid: - dependency: transitive - description: - name: uuid - sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff - url: "https://pub.dev" - source: hosted - version: "4.5.1" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 12a850f..8b242a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,9 +58,6 @@ dependencies: appflowy_board: ^0.1.2 syncfusion_flutter_calendar: ^28.2.6 syncfusion_flutter_maps: ^28.1.33 - http: ^1.2.2 - geolocator: ^9.0.1 - permission_handler: ^11.3.0 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index b2cbd25..043a96f 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,17 +7,11 @@ #include "generated_plugin_registrant.h" #include -#include -#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); - GeolocatorWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("GeolocatorWindows")); - PermissionHandlerWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 92c9a0d..a95e267 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,8 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows - geolocator_windows - permission_handler_windows url_launcher_windows )