Remove Sales, Comment Task, and Report Task screens; update pubspec.yaml to clean up asset paths.
@ -1,192 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"first_name": "James Carter",
|
||||
"email": "james.carter@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "How is your day going?",
|
||||
"send_at": "2024-11-15T10:05:10Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "Reminder about the project meeting tomorrow",
|
||||
"send_at": "2023-06-20T14:23:11Z",
|
||||
"from_me": true
|
||||
},
|
||||
{
|
||||
"message": "Can we meet today for a quick chat?",
|
||||
"send_at": "2023-04-19T17:30:08Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "Yes, all is good. See you tomorrow at 2 PM for the meeting",
|
||||
"send_at": "2023-03-22T11:09:45Z",
|
||||
"from_me": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"first_name": "Sophia Lee",
|
||||
"email": "sophia.lee@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Are we meeting today for the weekly catch-up?",
|
||||
"send_at": "2023-09-10T08:45:36Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "Please review these updated documents",
|
||||
"send_at": "2023-11-17T11:22:33Z",
|
||||
"from_me": true
|
||||
},
|
||||
{
|
||||
"message": "Good morning, How are you? When is our next meeting?",
|
||||
"send_at": "2023-05-13T09:25:18Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"first_name": "Ethan Scott",
|
||||
"email": "ethan.scott@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Are you available for a quick call? Need to discuss something",
|
||||
"send_at": "2023-12-05T07:40:21Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "Let's meet today, shall we?",
|
||||
"send_at": "2023-03-17T14:00:12Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"first_name": "Olivia Brown",
|
||||
"email": "olivia.brown@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Let's meet today for a team discussion",
|
||||
"send_at": "2023-05-30T11:55:10Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "Hope you're having a great day. Let's catch up soon",
|
||||
"send_at": "2023-07-12T12:36:44Z",
|
||||
"from_me": true
|
||||
},
|
||||
{
|
||||
"message": "I need to go buy some groceries this afternoon, I'll be a bit late.",
|
||||
"send_at": "2024-01-10T13:20:45Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"first_name": "Charlotte Miller",
|
||||
"email": "charlotte.miller@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Are you available for a quick chat?",
|
||||
"send_at": "2023-11-11T16:50:09Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "I just sent you the updated contract documents for review.",
|
||||
"send_at": "2023-10-04T18:22:56Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"first_name": "Jackson Harris",
|
||||
"email": "jackson.harris@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "How's everything going? Any updates on the project?",
|
||||
"send_at": "2023-08-25T11:10:30Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "Sending over the latest draft for your review",
|
||||
"send_at": "2023-12-02T10:14:50Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"first_name": "Aiden Cooper",
|
||||
"email": "aiden.cooper@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Do you have time today for a discussion?",
|
||||
"send_at": "2023-10-05T09:18:22Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "The new update is ready for deployment, please check it.",
|
||||
"send_at": "2024-01-25T11:29:13Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"first_name": "Lily King",
|
||||
"email": "lily.king@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Would you be able to meet today for a catch-up?",
|
||||
"send_at": "2023-06-18T13:12:09Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "I have finished reviewing the files, please take a look.",
|
||||
"send_at": "2023-12-18T16:47:02Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"first_name": "Max Taylor",
|
||||
"email": "max.taylor@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Please check the attached file and confirm if everything is okay.",
|
||||
"send_at": "2023-09-29T14:10:33Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "Sending over the revised schedule for the next phase.",
|
||||
"send_at": "2024-01-02T17:12:11Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"first_name": "Avery Clark",
|
||||
"email": "avery.clark@example.com",
|
||||
"messages": [
|
||||
{
|
||||
"message": "Are we ready for the meeting today?",
|
||||
"send_at": "2023-08-22T12:43:50Z",
|
||||
"from_me": false
|
||||
},
|
||||
{
|
||||
"message": "I updated the timeline. Let me know if you have any questions.",
|
||||
"send_at": "2023-12-15T10:55:29Z",
|
||||
"from_me": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -1,82 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"asset": "Alaska Air Group, Inc.",
|
||||
"date": "2024-06-17T12:59:41Z",
|
||||
"ip_address": "113.9.18.110",
|
||||
"status": "Unpaid",
|
||||
"amount": 7061
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"asset": "T2 Biosystems, Inc.",
|
||||
"date": "2024-09-09T00:20:08Z",
|
||||
"ip_address": "45.51.68.143",
|
||||
"status": "Unpaid",
|
||||
"amount": 5677
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"asset": "North American Energy Partners, Inc.",
|
||||
"date": "2024-07-17T10:46:42Z",
|
||||
"ip_address": "221.131.122.193",
|
||||
"status": "Unpaid",
|
||||
"amount": 5420
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"asset": "Finjan Holdings, Inc.",
|
||||
"date": "2024-01-20T20:10:26Z",
|
||||
"ip_address": "50.242.43.22",
|
||||
"status": "Success",
|
||||
"amount": 6433
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"asset": "Omega Healthcare Investors, Inc.",
|
||||
"date": "2024-11-14T23:08:09Z",
|
||||
"ip_address": "109.125.5.131",
|
||||
"status": "Success",
|
||||
"amount": 6317
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"asset": "MediciNova, Inc.",
|
||||
"date": "2024-01-12T18:20:33Z",
|
||||
"ip_address": "54.103.156.190",
|
||||
"status": "Unpaid",
|
||||
"amount": 7952
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"asset": "PowerShares LadderRite 0-5 Year Corporate Bond Portfolio",
|
||||
"date": "2024-04-26T00:44:42Z",
|
||||
"ip_address": "169.190.183.205",
|
||||
"status": "Success",
|
||||
"amount": 6294
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"asset": "VelocityShares Daily 2x VIX Medium-Term ETN",
|
||||
"date": "2024-02-01T12:47:59Z",
|
||||
"ip_address": "144.189.211.137",
|
||||
"status": "Success",
|
||||
"amount": 4419
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"asset": "Liberty TripAdvisor Holdings, Inc.",
|
||||
"date": "2023-12-29T14:49:59Z",
|
||||
"ip_address": "166.41.221.149",
|
||||
"status": "Unpaid",
|
||||
"amount": 4195
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"asset": "Scorpio Tankers Inc.",
|
||||
"date": "2023-12-02T11:36:44Z",
|
||||
"ip_address": "27.151.0.226",
|
||||
"status": "Success",
|
||||
"amount": 8395
|
||||
}
|
||||
]
|
@ -1,202 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"first_name": "Sabina",
|
||||
"last_name": "Brothwood",
|
||||
"project_name": "Wunsch, DuBuque and Green",
|
||||
"phone_number": "541-568-8047",
|
||||
"balance": "31907",
|
||||
"order_count": 7,
|
||||
"last_order": "2022-10-07T03:43:16Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"first_name": "Felic",
|
||||
"last_name": "Parlor",
|
||||
"project_name": "Dare LLC",
|
||||
"phone_number": "866-349-3385",
|
||||
"balance": "02260",
|
||||
"order_count": 26,
|
||||
"last_order": "2023-07-12T07:52:19Z"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"first_name": "Marnie",
|
||||
"last_name": "Kofax",
|
||||
"project_name": "Von LLC",
|
||||
"phone_number": "821-779-3766",
|
||||
"balance": "663",
|
||||
"order_count": 21,
|
||||
"last_order": "2022-10-14T21:19:33Z"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"first_name": "Tine",
|
||||
"last_name": "Meron",
|
||||
"project_name": "Stracke Inc",
|
||||
"phone_number": "901-149-2915",
|
||||
"balance": "84",
|
||||
"order_count": 8,
|
||||
"last_order": "2023-04-06T12:36:09Z"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"first_name": "Shanon",
|
||||
"last_name": "Ivashchenko",
|
||||
"project_name": "Satterfield, Schultz and Jones",
|
||||
"phone_number": "452-728-1072",
|
||||
"balance": "0878",
|
||||
"order_count": 34,
|
||||
"last_order": "2023-04-03T15:07:21Z"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"first_name": "Guthrey",
|
||||
"last_name": "Crossland",
|
||||
"project_name": "Medhurst and Sons",
|
||||
"phone_number": "212-991-7314",
|
||||
"balance": "0291",
|
||||
"order_count": 7,
|
||||
"last_order": "2022-12-03T04:24:53Z"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"first_name": "Florie",
|
||||
"last_name": "Chestnutt",
|
||||
"project_name": "Beer-Kunze",
|
||||
"phone_number": "935-525-9749",
|
||||
"balance": "07984",
|
||||
"order_count": 69,
|
||||
"last_order": "2023-01-14T10:42:28Z"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"first_name": "Wittie",
|
||||
"last_name": "Damsell",
|
||||
"project_name": "Daniel, Legros and Roberts",
|
||||
"phone_number": "632-787-4799",
|
||||
"balance": "22844",
|
||||
"order_count": 41,
|
||||
"last_order": "2023-01-18T09:38:50Z"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"first_name": "Aimee",
|
||||
"last_name": "Dibdall",
|
||||
"project_name": "Schuster LLC",
|
||||
"phone_number": "404-339-9261",
|
||||
"balance": "460",
|
||||
"order_count": 41,
|
||||
"last_order": "2023-04-15T03:08:51Z"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"first_name": "Inna",
|
||||
"last_name": "Juggins",
|
||||
"project_name": "Johnson Group",
|
||||
"phone_number": "769-573-9516",
|
||||
"balance": "77",
|
||||
"order_count": 18,
|
||||
"last_order": "2022-09-13T05:14:51Z"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"first_name": "Cathyleen",
|
||||
"last_name": "Went",
|
||||
"project_name": "DuBuque LLC",
|
||||
"phone_number": "558-736-4450",
|
||||
"balance": "24",
|
||||
"order_count": 98,
|
||||
"last_order": "2023-07-05T05:26:12Z"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"first_name": "Kora",
|
||||
"last_name": "Dowderswell",
|
||||
"project_name": "Harber, Daugherty and West",
|
||||
"phone_number": "721-147-2917",
|
||||
"balance": "32",
|
||||
"order_count": 5,
|
||||
"last_order": "2022-10-22T07:47:42Z"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"first_name": "Loni",
|
||||
"last_name": "Armin",
|
||||
"project_name": "Fadel-Kerluke",
|
||||
"phone_number": "251-582-9867",
|
||||
"balance": "2122",
|
||||
"order_count": 4,
|
||||
"last_order": "2023-01-26T19:56:37Z"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"first_name": "Kalle",
|
||||
"last_name": "Spybey",
|
||||
"project_name": "Kshlerin, Torp and Koelpin",
|
||||
"phone_number": "245-661-6328",
|
||||
"balance": "61034",
|
||||
"order_count": 70,
|
||||
"last_order": "2022-12-29T15:38:20Z"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"first_name": "Verena",
|
||||
"last_name": "Skerme",
|
||||
"project_name": "Dach, Abshire and Crooks",
|
||||
"phone_number": "227-694-0272",
|
||||
"balance": "68921",
|
||||
"order_count": 3,
|
||||
"last_order": "2022-11-29T23:02:11Z"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"first_name": "Lisle",
|
||||
"last_name": "McGowan",
|
||||
"project_name": "White, Murphy and Sawayn",
|
||||
"phone_number": "196-817-6277",
|
||||
"balance": "7250",
|
||||
"order_count": 34,
|
||||
"last_order": "2023-06-14T11:10:56Z"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"first_name": "Bryce",
|
||||
"last_name": "Pires",
|
||||
"project_name": "Crooks Group",
|
||||
"phone_number": "424-217-0372",
|
||||
"balance": "549",
|
||||
"order_count": 50,
|
||||
"last_order": "2023-01-08T17:58:09Z"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"first_name": "Ibrahim",
|
||||
"last_name": "Battram",
|
||||
"project_name": "Schmidt, Feil and Schaden",
|
||||
"phone_number": "836-473-5900",
|
||||
"balance": "3",
|
||||
"order_count": 86,
|
||||
"last_order": "2023-08-05T01:46:22Z"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"first_name": "Josepha",
|
||||
"last_name": "Grishkov",
|
||||
"project_name": "Welch-Wisozk",
|
||||
"phone_number": "928-393-5306",
|
||||
"balance": "528",
|
||||
"order_count": 38,
|
||||
"last_order": "2023-08-18T19:01:25Z"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"first_name": "Ellis",
|
||||
"last_name": "Barfoot",
|
||||
"project_name": "Davis, Ondricka and Schaefer",
|
||||
"phone_number": "169-236-9311",
|
||||
"balance": "169",
|
||||
"order_count": 11,
|
||||
"last_order": "2023-02-21T16:29:59Z"
|
||||
}
|
||||
]
|
@ -1,72 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"image": "assets/dummy/dummy_1.jpg",
|
||||
"name": "Meir O'Leahy",
|
||||
"user_name": "moleahy0",
|
||||
"contact_number": "817-666-8080"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"image": "assets/dummy/dummy_2.jpg",
|
||||
"name": "Ernie Ayling",
|
||||
"user_name": "eayling1",
|
||||
"contact_number": "890-910-3243"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"image": "assets/dummy/dummy_3.jpg",
|
||||
"name": "Mead Ezzle",
|
||||
"user_name": "mezzle2",
|
||||
"contact_number": "293-162-4468"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"image": "assets/dummy/dummy_4.jpg",
|
||||
"name": "Esta Norewood",
|
||||
"user_name": "enorewood3",
|
||||
"contact_number": "532-164-0604"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"image": "assets/dummy/dummy_5.jpg",
|
||||
"name": "Bartram Cottell",
|
||||
"user_name": "bcottell4",
|
||||
"contact_number": "940-143-2842"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"image": "assets/dummy/dummy_1.jpg",
|
||||
"name": "Nicola Reolfo",
|
||||
"user_name": "nreolfo5",
|
||||
"contact_number": "356-558-8324"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"image": "assets/dummy/dummy_2.jpg",
|
||||
"name": "Normy Gilhoolie",
|
||||
"user_name": "ngilhoolie6",
|
||||
"contact_number": "256-770-5288"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"image": "assets/dummy/dummy_3.jpg",
|
||||
"name": "Octavia Margerrison",
|
||||
"user_name": "omargerrison7",
|
||||
"contact_number": "744-595-1968"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"image": "assets/dummy/dummy_4.jpg",
|
||||
"name": "Stella Barriball",
|
||||
"user_name": "sbarriball8",
|
||||
"contact_number": "906-522-1874"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"image": "assets/dummy/dummy_5.jpg",
|
||||
"name": "Panchito Chase",
|
||||
"user_name": "pchase9",
|
||||
"contact_number": "929-922-7735"
|
||||
}
|
||||
]
|
@ -1,102 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"candidate": "Patrica",
|
||||
"category": "Manufacture",
|
||||
"designation": "Sr.UI Developer",
|
||||
"mail": "pbeedie0@ustream.tv",
|
||||
"location": "Pojan",
|
||||
"date": "2024-08-09T06:03:25Z",
|
||||
"type": "Freelancer"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"candidate": "Angelique",
|
||||
"category": "Marketing",
|
||||
"designation": "Team Lead",
|
||||
"mail": "asamwayes1@fotki.com",
|
||||
"location": "Jiangluo",
|
||||
"date": "2023-11-17T10:23:18Z",
|
||||
"type": "Hybride"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"candidate": "Garnet",
|
||||
"category": "Marketing",
|
||||
"designation": "Team Lead",
|
||||
"mail": "gjarrelt2@dailymail.co.uk",
|
||||
"location": "Wissembourg",
|
||||
"date": "2024-03-18T15:31:21Z",
|
||||
"type": "Freelancer"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"candidate": "Guglielmo",
|
||||
"category": "Manufacture",
|
||||
"designation": "Sales Executive",
|
||||
"mail": "gcarlone3@ted.com",
|
||||
"location": "Aoqiao",
|
||||
"date": "2024-04-08T22:04:13Z",
|
||||
"type": "Part Time"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"candidate": "Reggie",
|
||||
"category": "Manufacture",
|
||||
"designation": "Team Lead",
|
||||
"mail": "rmacieiczyk4@booking.com",
|
||||
"location": "Insrom",
|
||||
"date": "2024-01-09T06:29:40Z",
|
||||
"type": "Freelancer"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"candidate": "Florri",
|
||||
"category": "Manufacture",
|
||||
"designation": "Sales Executive",
|
||||
"mail": "fharesign5@yellowbook.com",
|
||||
"location": "Itambacuri",
|
||||
"date": "2024-09-05T11:09:36Z",
|
||||
"type": "Part Time"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"candidate": "Annabella",
|
||||
"category": "Manufacture",
|
||||
"designation": "Team Lead",
|
||||
"mail": "aossipenko6@ucoz.com",
|
||||
"location": "Watthana Nakhon",
|
||||
"date": "2024-07-27T16:17:23Z",
|
||||
"type": "Full Time"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"candidate": "Arlene",
|
||||
"category": "Manufacture",
|
||||
"designation": "Team Lead",
|
||||
"mail": "agook7@google.com.hk",
|
||||
"location": "Hayama",
|
||||
"date": "2024-09-14T13:32:31Z",
|
||||
"type": "Freelancer"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"candidate": "Shurlocke",
|
||||
"category": "Manufacture",
|
||||
"designation": "Sales Executive",
|
||||
"mail": "sgallehawk8@squidoo.com",
|
||||
"location": "Bel Air Rivière Sèche",
|
||||
"date": "2024-06-18T00:23:24Z",
|
||||
"type": "Freelancer"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"candidate": "Ricoriki",
|
||||
"category": "Service",
|
||||
"designation": "Sales Executive",
|
||||
"mail": "rgillio9@mapy.cz",
|
||||
"location": "Tawangsari",
|
||||
"date": "2024-06-14T19:59:41Z",
|
||||
"type": "Freelancer"
|
||||
}
|
||||
]
|
@ -1,112 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"first_name": "Bordy",
|
||||
"email": "bjeffreys0@macromedia.com",
|
||||
"phone_number": "217-779-9808",
|
||||
"company_name": "Voonyx",
|
||||
"status": "Won Lead",
|
||||
"location": "Presidencia Roque Sáenz Peña",
|
||||
"date": "2024-06-20T06:26:12Z",
|
||||
"amount": 52397
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"first_name": "Collin",
|
||||
"email": "cgething1@paginegialle.it",
|
||||
"phone_number": "124-897-0512",
|
||||
"company_name": "Rhyzio",
|
||||
"status": "New Lead",
|
||||
"location": "Nombre de Jesús",
|
||||
"date": "2023-11-20T12:12:32Z",
|
||||
"amount": 58203
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"first_name": "Bear",
|
||||
"email": "bfowlds2@booking.com",
|
||||
"phone_number": "391-249-1041",
|
||||
"company_name": "Blogtag",
|
||||
"status": "Lost Lead",
|
||||
"location": "Shani",
|
||||
"date": "2024-11-09T07:57:49Z",
|
||||
"amount": 18717
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"first_name": "Robers",
|
||||
"email": "raujouanet3@google.cn",
|
||||
"phone_number": "128-604-5632",
|
||||
"company_name": "Quire",
|
||||
"status": "Lost Lead",
|
||||
"location": "Benghazi",
|
||||
"date": "2023-12-09T17:33:39Z",
|
||||
"amount": 11267
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"first_name": "Shirlene",
|
||||
"email": "sjoiris4@theglobeandmail.com",
|
||||
"phone_number": "471-884-5686",
|
||||
"company_name": "Voonder",
|
||||
"status": "New Lead",
|
||||
"location": "Krasnaye",
|
||||
"date": "2024-01-15T03:06:07Z",
|
||||
"amount": 66877
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"first_name": "Erik",
|
||||
"email": "ebudden5@zdnet.com",
|
||||
"phone_number": "957-550-9950",
|
||||
"company_name": "Digitube",
|
||||
"status": "Won Lead",
|
||||
"location": "Taouloukoult",
|
||||
"date": "2024-01-21T03:05:01Z",
|
||||
"amount": 55766
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"first_name": "Sabina",
|
||||
"email": "sdenman6@ning.com",
|
||||
"phone_number": "612-207-4109",
|
||||
"company_name": "Kwinu",
|
||||
"status": "Lost Lead",
|
||||
"location": "Minneapolis",
|
||||
"date": "2024-05-19T15:59:28Z",
|
||||
"amount": 24691
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"first_name": "Andi",
|
||||
"email": "aschruyer7@imdb.com",
|
||||
"phone_number": "410-936-5855",
|
||||
"company_name": "Photojam",
|
||||
"status": "Won Lead",
|
||||
"location": "Masina",
|
||||
"date": "2024-09-30T18:31:07Z",
|
||||
"amount": 7228
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"first_name": "Kathy",
|
||||
"email": "kstandall8@woothemes.com",
|
||||
"phone_number": "840-267-7381",
|
||||
"company_name": "Quinu",
|
||||
"status": "Won Lead",
|
||||
"location": "Shashi",
|
||||
"date": "2024-04-21T18:00:25Z",
|
||||
"amount": 85726
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"first_name": "Lenka",
|
||||
"email": "llennon9@hexun.com",
|
||||
"phone_number": "962-993-3146",
|
||||
"company_name": "Skaboo",
|
||||
"status": "Won Lead",
|
||||
"location": "Shireet",
|
||||
"date": "2024-06-19T12:27:05Z",
|
||||
"amount": 10069
|
||||
}
|
||||
]
|
@ -1,197 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Mints - Striped Red",
|
||||
"description": "Laceration of ulnar artery at wrs/hnd lv of unsp arm",
|
||||
"price": 54,
|
||||
"stock": 72,
|
||||
"category": "Scallops 60/80 Iqf",
|
||||
"order_counts": 10,
|
||||
"created_at": "2022-07-20T09:52:34Z",
|
||||
"rating": 2.49,
|
||||
"rating_count": 42,
|
||||
"sku": "RCII"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Pasta - Ravioli",
|
||||
"description": "Oth disp fx of upper end l humer, subs for fx w delay heal",
|
||||
"price": 35,
|
||||
"stock": 64,
|
||||
"category": "Chocolate - Mi - Amere Semi",
|
||||
"order_counts": 45,
|
||||
"created_at": "2023-03-25T22:32:10Z",
|
||||
"rating": 4.66,
|
||||
"rating_count": 82,
|
||||
"sku": "RDS.A"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Soup - Campbells Chili",
|
||||
"description": "Nondisp fx of anterior wall of left acetab, init for opn fx",
|
||||
"price": 27,
|
||||
"stock": 21,
|
||||
"category": "Tomatoes - Cherry, Yellow",
|
||||
"order_counts": 53,
|
||||
"created_at": "2022-05-18T15:56:06Z",
|
||||
"rating": 3.05,
|
||||
"rating_count": 66,
|
||||
"sku": "STNG"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Fennel - Seeds",
|
||||
"description": "Displ spiral fx shaft of ulna, r arm, 7thD",
|
||||
"price": 124,
|
||||
"stock": 56,
|
||||
"category": "Squid - U - 10 Thailand",
|
||||
"order_counts": 13,
|
||||
"created_at": "2022-04-21T11:32:39Z",
|
||||
"rating": 0.59,
|
||||
"rating_count": 55,
|
||||
"sku": "FEUZ"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Salt - Celery",
|
||||
"description": "Interstitial myositis, lower leg",
|
||||
"price": 25,
|
||||
"stock": 78,
|
||||
"category": "Gatorade - Lemon Lime",
|
||||
"order_counts": 30,
|
||||
"created_at": "2023-01-01T01:15:44Z",
|
||||
"rating": 1.42,
|
||||
"rating_count": 10,
|
||||
"sku": "VER"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Flour - Chickpea",
|
||||
"description": "Oth fx upr end unsp rad, 7thJ",
|
||||
"price": 131,
|
||||
"stock": 50,
|
||||
"category": "Sweet Pea Sprouts",
|
||||
"order_counts": 11,
|
||||
"created_at": "2023-04-09T04:41:43Z",
|
||||
"rating": 4.05,
|
||||
"rating_count": 24,
|
||||
"sku": "HDS"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Chips - Miss Vickies",
|
||||
"description": "Contusion of right hip, initial encounter",
|
||||
"price": 52,
|
||||
"stock": 63,
|
||||
"category": "Extract - Almond",
|
||||
"order_counts": 62,
|
||||
"created_at": "2022-06-24T05:25:56Z",
|
||||
"rating": 3.35,
|
||||
"rating_count": 6,
|
||||
"sku": "MACQW"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Ice Cream - Super Sandwich",
|
||||
"description": "Acute post-traumatic headache",
|
||||
"price": 87,
|
||||
"stock": 44,
|
||||
"category": "Bread - Wheat Baguette",
|
||||
"order_counts": 63,
|
||||
"created_at": "2022-07-06T05:37:09Z",
|
||||
"rating": 0.96,
|
||||
"rating_count": 38,
|
||||
"sku": "AA"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Alize Gold Passion",
|
||||
"description": "War op involving explosion of marine weapons, civilian",
|
||||
"price": 113,
|
||||
"stock": 72,
|
||||
"category": "Lid - Translucent, 3.5 And 6 Oz",
|
||||
"order_counts": 23,
|
||||
"created_at": "2022-07-09T18:19:37Z",
|
||||
"rating": 3.25,
|
||||
"rating_count": 64,
|
||||
"sku": "EVOK"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Mushrooms - Honey",
|
||||
"description": "Sltr-haris Type IV physl fx low end l femr, 7thP",
|
||||
"price": 98,
|
||||
"stock": 64,
|
||||
"category": "Lemon Balm - Fresh",
|
||||
"order_counts": 5,
|
||||
"created_at": "2022-08-05T22:14:06Z",
|
||||
"rating": 3.51,
|
||||
"rating_count": 0,
|
||||
"sku": "TDG"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "Bread Base - Goodhearth",
|
||||
"description": "Unspecified injury of axillary artery",
|
||||
"price": 81,
|
||||
"stock": 56,
|
||||
"category": "Beef - Bones, Marrow",
|
||||
"order_counts": 76,
|
||||
"created_at": "2023-04-22T03:11:41Z",
|
||||
"rating": 4.07,
|
||||
"rating_count": 22,
|
||||
"sku": "GPAC"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "Veal - Heart",
|
||||
"description": "Laceration without foreign body of left buttock, subs encntr",
|
||||
"price": 93,
|
||||
"stock": 13,
|
||||
"category": "Peach - Fresh",
|
||||
"order_counts": 12,
|
||||
"created_at": "2023-02-18T16:15:16Z",
|
||||
"rating": 2.08,
|
||||
"rating_count": 87,
|
||||
"sku": "PAH"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "Tomatoes - Grape",
|
||||
"description": "Nondisplaced bicondylar fracture of left tibia",
|
||||
"price": 132,
|
||||
"stock": 13,
|
||||
"category": "Veal - Striploin",
|
||||
"order_counts": 24,
|
||||
"created_at": "2022-06-08T20:49:59Z",
|
||||
"rating": 3.32,
|
||||
"rating_count": 82,
|
||||
"sku": "ENZL"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"name": "Tomato Paste",
|
||||
"description": "Abrasion of unspecified part of neck, initial encounter",
|
||||
"price": 48,
|
||||
"stock": 24,
|
||||
"category": "Juice - Tomato, 48 Oz",
|
||||
"order_counts": 4,
|
||||
"created_at": "2022-12-03T04:03:52Z",
|
||||
"rating": 4.11,
|
||||
"rating_count": 66,
|
||||
"sku": "LTEA"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "Cheese - Roquefort Pappillon",
|
||||
"description": "Wedge comprsn fx first thor vertebra, init for opn fx",
|
||||
"price": 15,
|
||||
"stock": 68,
|
||||
"category": "Veal - Insides, Grains",
|
||||
"order_counts": 72,
|
||||
"created_at": "2022-09-22T06:22:33Z",
|
||||
"rating": 1.54,
|
||||
"rating_count": 40,
|
||||
"sku": "AIF"
|
||||
}
|
||||
]
|
@ -1,102 +0,0 @@
|
||||
[
|
||||
{
|
||||
"order_id": "TWT76911",
|
||||
"customer_name": "Robinson",
|
||||
"location": "Lyubokhna",
|
||||
"order_date": "2023-09-17T00:35:06Z",
|
||||
"quantity": 6,
|
||||
"payments": "COD",
|
||||
"price": 336,
|
||||
"status": "New"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT23890",
|
||||
"customer_name": "Claudina",
|
||||
"location": "Maracha",
|
||||
"order_date": "2023-09-11T15:01:04Z",
|
||||
"quantity": 8,
|
||||
"payments": "American Express",
|
||||
"price": 428,
|
||||
"status": "Shopping"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT84616",
|
||||
"customer_name": "Dewain",
|
||||
"location": "Fuji",
|
||||
"order_date": "2023-12-26T02:42:54Z",
|
||||
"quantity": 6,
|
||||
"payments": "Credit Card",
|
||||
"price": 410,
|
||||
"status": "Shopping"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT66711",
|
||||
"customer_name": "Margette",
|
||||
"location": "Chicago",
|
||||
"order_date": "2024-01-09T18:24:04Z",
|
||||
"quantity": 10,
|
||||
"payments": "Paypal",
|
||||
"price": 268,
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT50711",
|
||||
"customer_name": "Brittany",
|
||||
"location": "Hakha",
|
||||
"order_date": "2023-09-28T14:17:02Z",
|
||||
"quantity": 2,
|
||||
"payments": "Visa Card",
|
||||
"price": 229,
|
||||
"status": "New"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT37588",
|
||||
"customer_name": "Venus",
|
||||
"location": "Sioguí Arriba",
|
||||
"order_date": "2023-10-16T18:22:32Z",
|
||||
"quantity": 5,
|
||||
"payments": "Visa Card",
|
||||
"price": 211,
|
||||
"status": "Delivered"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT36092",
|
||||
"customer_name": "Norry",
|
||||
"location": "Hongqi",
|
||||
"order_date": "2024-01-28T16:50:34Z",
|
||||
"quantity": 7,
|
||||
"payments": "American Express",
|
||||
"price": 111,
|
||||
"status": "Shopping"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT99659",
|
||||
"customer_name": "Rabbi",
|
||||
"location": "Macari",
|
||||
"order_date": "2023-03-27T17:42:51Z",
|
||||
"quantity": 9,
|
||||
"payments": "COD",
|
||||
"price": 268,
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT21952",
|
||||
"customer_name": "Hesther",
|
||||
"location": "København",
|
||||
"order_date": "2024-02-08T00:16:01Z",
|
||||
"quantity": 9,
|
||||
"payments": "Credit Card",
|
||||
"price": 392,
|
||||
"status": "Delivered"
|
||||
},
|
||||
{
|
||||
"order_id": "TWT66885",
|
||||
"customer_name": "Sioux",
|
||||
"location": "Taohua",
|
||||
"order_date": "2023-10-23T16:25:29Z",
|
||||
"quantity": 1,
|
||||
"payments": "Paypal",
|
||||
"price": 337,
|
||||
"status": "New"
|
||||
}
|
||||
]
|
@ -1,82 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Marketing Manager",
|
||||
"assign_to": "Hercules",
|
||||
"date": "2024-03-10T00:14:27Z",
|
||||
"priority": "High",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Community Outreach Specialist",
|
||||
"assign_to": "Fayre",
|
||||
"date": "2024-10-07T06:24:18Z",
|
||||
"priority": "High",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Senior Quality Engineer",
|
||||
"assign_to": "Nancy",
|
||||
"date": "2024-01-11T18:22:29Z",
|
||||
"priority": "Medium",
|
||||
"status": "In Progress"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "VP Sales",
|
||||
"assign_to": "Jemimah",
|
||||
"date": "2024-06-17T17:57:40Z",
|
||||
"priority": "Low",
|
||||
"status": "Finished"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "Sales Associate",
|
||||
"assign_to": "Raquel",
|
||||
"date": "2024-05-06T11:11:43Z",
|
||||
"priority": "Medium",
|
||||
"status": "Finished"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"title": "Dental Hygienist",
|
||||
"assign_to": "Vasili",
|
||||
"date": "2024-05-31T21:16:27Z",
|
||||
"priority": "High",
|
||||
"status": "Finished"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"title": "Occupational Therapist",
|
||||
"assign_to": "Lulu",
|
||||
"date": "2024-03-28T21:07:00Z",
|
||||
"priority": "Medium",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"title": "Analyst Programmer",
|
||||
"assign_to": "Egor",
|
||||
"date": "2023-12-11T08:16:01Z",
|
||||
"priority": "High",
|
||||
"status": "Finished"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"title": "Research Assistant III",
|
||||
"assign_to": "Max",
|
||||
"date": "2024-02-15T21:59:34Z",
|
||||
"priority": "High",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"title": "Developer II",
|
||||
"assign_to": "Kaela",
|
||||
"date": "2024-06-24T07:29:47Z",
|
||||
"priority": "High",
|
||||
"status": "Cancelled"
|
||||
}
|
||||
]
|
@ -1,47 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"product_name": "Theobald",
|
||||
"quantity": 2,
|
||||
"customer": "Theobald Southcott",
|
||||
"status": "Shipped",
|
||||
"price": 361,
|
||||
"order_date": "2023-12-11T23:48:54Z"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"product_name": "Carla",
|
||||
"quantity": 3,
|
||||
"customer": "Carla Grgic",
|
||||
"status": "Pending",
|
||||
"price": 329,
|
||||
"order_date": "2024-05-25T09:37:51Z"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"product_name": "Liana",
|
||||
"quantity": 3,
|
||||
"customer": "Liana Swannell",
|
||||
"status": "Delivery",
|
||||
"price": 120,
|
||||
"order_date": "2024-04-06T19:02:14Z"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"product_name": "Radcliffe",
|
||||
"quantity": 4,
|
||||
"customer": "Radcliffe Venard",
|
||||
"status": "Shipped",
|
||||
"price": 750,
|
||||
"order_date": "2024-10-27T10:44:12Z"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"product_name": "Delmer",
|
||||
"quantity": 3,
|
||||
"customer": "Delmer Vamplew",
|
||||
"status": "Delivery",
|
||||
"price": 469,
|
||||
"order_date": "2024-10-16T15:55:22Z"
|
||||
}
|
||||
]
|
@ -1,91 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Finish report",
|
||||
"description": "Complete the quarterly report for the team meeting.",
|
||||
"due_date": "2024-07-14T00:37:09Z",
|
||||
"priority": "High",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Team meeting",
|
||||
"description": "Attend the weekly project meeting and provide updates.",
|
||||
"due_date": "2024-04-18T01:25:27Z",
|
||||
"priority": "Medium",
|
||||
"status": "Completed"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Buy groceries",
|
||||
"description": "Purchase ingredients for dinner and weekly supplies.",
|
||||
"due_date": "2024-02-17T16:32:03Z",
|
||||
"priority": "Low",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Update website",
|
||||
"description": "Update the homepage with new content and images.",
|
||||
"due_date": "2024-07-16T15:49:59Z",
|
||||
"priority": "Medium",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "Send emails",
|
||||
"description": "Send out follow-up emails to clients from last week's meeting.",
|
||||
"due_date": "2024-09-24T11:08:14Z",
|
||||
"priority": "High",
|
||||
"status": "Completed"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"title": "Organize workspace",
|
||||
"description": "Declutter desk and organize office supplies.",
|
||||
"due_date": "2024-10-06T11:49:14Z",
|
||||
"priority": "Low",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"title": "Prepare presentation",
|
||||
"description": "Create slides for next week's client pitch.",
|
||||
"due_date": "2024-05-20T04:38:51Z",
|
||||
"priority": "High",
|
||||
"status": "In Progress"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"title": "Write blog post",
|
||||
"description": "Write a blog post about industry trends for the company website.",
|
||||
"due_date": "2024-01-13T07:46:34Z",
|
||||
"priority": "Medium",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"title": "Schedule doctor's appointment",
|
||||
"description": "Call and book a check-up appointment with the doctor.",
|
||||
"due_date": "2024-09-22T10:54:21Z",
|
||||
"priority": "Low",
|
||||
"status": "Pending"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"title": "Review budget",
|
||||
"description": "Review and adjust monthly budget for expenses.",
|
||||
"due_date": "2024-08-20T03:57:48Z",
|
||||
"priority": "Medium",
|
||||
"status": "Pending"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,62 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"first_name": "Roobbie",
|
||||
"last_name": "Ivashintsov",
|
||||
"email": "rivashintsov0@symantec.com"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"first_name": "Cissy",
|
||||
"last_name": "Salmons",
|
||||
"email": "csalmons1@unicef.org"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"first_name": "Jillene",
|
||||
"last_name": "Besnardeau",
|
||||
"email": "jbesnardeau2@china.com.cn"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"first_name": "Catriona",
|
||||
"last_name": "Wrennall",
|
||||
"email": "cwrennall3@godaddy.com"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"first_name": "Risa",
|
||||
"last_name": "Rumens",
|
||||
"email": "rrumens4@un.org"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"first_name": "Gianina",
|
||||
"last_name": "Pavlenkov",
|
||||
"email": "gpavlenkov5@ted.com"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"first_name": "Tripp",
|
||||
"last_name": "Blowick",
|
||||
"email": "tblowick6@reuters.com"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"first_name": "Ephrem",
|
||||
"last_name": "Pfertner",
|
||||
"email": "epfertner7@godaddy.com"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"first_name": "Jacinda",
|
||||
"last_name": "Tomkies",
|
||||
"email": "jtomkies8@si.edu"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"first_name": "Traver",
|
||||
"last_name": "Poile",
|
||||
"email": "tpoile9@phoca.cz"
|
||||
}
|
||||
]
|
@ -1,56 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"session_duration": "2023-08-18T14:47:41Z",
|
||||
"channel": "Organic Search",
|
||||
"session": 547,
|
||||
"bounce_rate": 27.2,
|
||||
"target_reached": 843,
|
||||
"page_per_session": 4.4
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"session_duration": "2023-04-20T20:13:24Z",
|
||||
"channel": "Direct",
|
||||
"session": 855,
|
||||
"bounce_rate": 25.8,
|
||||
"target_reached": 998,
|
||||
"page_per_session": 6.6
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"session_duration": "2023-09-05T02:15:03Z",
|
||||
"channel": "Referral",
|
||||
"session": 337,
|
||||
"bounce_rate": 12.4,
|
||||
"target_reached": 509,
|
||||
"page_per_session": 8.0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"session_duration": "2023-06-23T13:50:55Z",
|
||||
"channel": "Social",
|
||||
"session": 279,
|
||||
"bounce_rate": 40.4,
|
||||
"target_reached": 860,
|
||||
"page_per_session": 7.3
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"session_duration": "2023-09-14T09:01:34Z",
|
||||
"channel": "Email",
|
||||
"session": 118,
|
||||
"bounce_rate": 46.2,
|
||||
"target_reached": 168,
|
||||
"page_per_session": 3.0
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"session_duration": "2023-07-14T01:46:51Z",
|
||||
"channel": "Paid Search",
|
||||
"session": 205,
|
||||
"bounce_rate": 32.8,
|
||||
"target_reached": 583,
|
||||
"page_per_session": 2.5
|
||||
}
|
||||
]
|
Before Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 179 KiB |
Before Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 277 KiB |
Before Width: | Height: | Size: 341 KiB |
Before Width: | Height: | Size: 396 KiB |
Before Width: | Height: | Size: 316 KiB |
Before Width: | Height: | Size: 375 KiB |
Before Width: | Height: | Size: 380 KiB |
@ -1,52 +0,0 @@
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/model/chart_model.dart';
|
||||
import 'package:marco/model/visitor_by_channels_model.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class AnalyticsController extends MyController {
|
||||
String selectActivity = "Year";
|
||||
List<VisitorByChannelsModel> visitorByChannel = [];
|
||||
final TooltipBehavior columnChartToolTip = TooltipBehavior(enable: true, format: 'point.x : point.y', tooltipPosition: TooltipPosition.pointer);
|
||||
final TooltipBehavior audienceOverview = TooltipBehavior(enable: true, format: 'point.x : point.y', tooltipPosition: TooltipPosition.pointer);
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
VisitorByChannelsModel.dummyList.then((value) {
|
||||
visitorByChannel = value;
|
||||
update();
|
||||
});
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void onSelectedActivity(String time) {
|
||||
selectActivity = time;
|
||||
update();
|
||||
}
|
||||
|
||||
void removeData(index) {
|
||||
visitorByChannel.removeAt(index);
|
||||
update();
|
||||
}
|
||||
|
||||
final List<ChartSampleData> columnChart = <ChartSampleData>[
|
||||
ChartSampleData(x: 2010, y: 32, yValue: 50),
|
||||
ChartSampleData(x: 2011, y: 44, yValue: 40),
|
||||
ChartSampleData(x: 2012, y: 40, yValue: 60),
|
||||
ChartSampleData(x: 2013, y: 50, yValue: 38),
|
||||
ChartSampleData(x: 2014, y: 10, yValue: 28),
|
||||
ChartSampleData(x: 2015, y: 20, yValue: 16),
|
||||
ChartSampleData(x: 2016, y: 30, yValue: 50),
|
||||
];
|
||||
|
||||
final List<ChartSampleData> audienceOverviewChart = [
|
||||
ChartSampleData(x: 2018, y: 50, yValue: 38),
|
||||
ChartSampleData(x: 2019, y: 10, yValue: 28),
|
||||
ChartSampleData(x: 2020, y: 32, yValue: 50),
|
||||
ChartSampleData(x: 2020, y: 44, yValue: 40),
|
||||
ChartSampleData(x: 2020, y: 40, yValue: 60),
|
||||
ChartSampleData(x: 2020, y: 50, yValue: 38),
|
||||
ChartSampleData(x: 2021, y: 10, yValue: 28),
|
||||
ChartSampleData(x: 2022, y: 20, yValue: 16),
|
||||
ChartSampleData(x: 2023, y: 30, yValue: 50)
|
||||
];
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/model/chart_model.dart';
|
||||
import 'package:marco/model/lead_report_model.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class CrmController extends MyController {
|
||||
List<ChartSampleData>? chartData;
|
||||
List<LeadReportModel> leadReport = [];
|
||||
TooltipBehavior? tooltipBehavior;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
tooltipBehavior = TooltipBehavior(enable: true);
|
||||
chartData = <ChartSampleData>[
|
||||
ChartSampleData(x: 'Jan', y: 10, secondSeriesYValue: 5),
|
||||
ChartSampleData(x: 'Feb', y: 12, secondSeriesYValue: 8),
|
||||
ChartSampleData(x: 'Mar', y: 14, secondSeriesYValue: 9),
|
||||
ChartSampleData(x: 'Apr', y: 11, secondSeriesYValue: 7),
|
||||
ChartSampleData(x: 'May', y: 15, secondSeriesYValue: 10),
|
||||
ChartSampleData(x: 'Jun', y: 9, secondSeriesYValue: 6),
|
||||
ChartSampleData(x: 'Jul', y: 13, secondSeriesYValue: 7),
|
||||
ChartSampleData(x: 'Aug', y: 12, secondSeriesYValue: 8),
|
||||
ChartSampleData(x: 'Sep', y: 14, secondSeriesYValue: 10),
|
||||
ChartSampleData(x: 'Oct', y: 15, secondSeriesYValue: 12),
|
||||
ChartSampleData(x: 'Nov', y: 13, secondSeriesYValue: 9),
|
||||
ChartSampleData(x: 'Dec', y: 11, secondSeriesYValue: 6),
|
||||
];
|
||||
|
||||
LeadReportModel.dummyList.then((value) {
|
||||
leadReport = value.sublist(0, 5);
|
||||
update();
|
||||
});
|
||||
super.onInit();
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/model/chart_model.dart';
|
||||
import 'package:marco/model/coin_growth_model.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class CryptoController extends MyController {
|
||||
List<ChartSampleData>? chartData;
|
||||
DateTimeIntervalType intervalType = DateTimeIntervalType.months;
|
||||
List<CoinGrowthModel> coinGrowth = [];
|
||||
|
||||
bool enableSolidCandle = false;
|
||||
|
||||
TrackballBehavior? trackballBehavior;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
CoinGrowthModel.dummyList.then((value) {
|
||||
coinGrowth = value.sublist(0, 5);
|
||||
update();
|
||||
});
|
||||
chartData = <ChartSampleData>[
|
||||
ChartSampleData(x: 'Jan', y: 50, secondSeriesYValue: 40, thirdSeriesYValue: 45),
|
||||
ChartSampleData(x: 'Feb', y: 47, secondSeriesYValue: 39, thirdSeriesYValue: 48),
|
||||
ChartSampleData(x: 'Mar', y: 55, secondSeriesYValue: 42, thirdSeriesYValue: 50),
|
||||
ChartSampleData(x: 'Apr', y: 60, secondSeriesYValue: 45, thirdSeriesYValue: 53),
|
||||
ChartSampleData(x: 'May', y: 70, secondSeriesYValue: 50, thirdSeriesYValue: 58),
|
||||
ChartSampleData(x: 'Jun', y: 75, secondSeriesYValue: 55, thirdSeriesYValue: 62),
|
||||
ChartSampleData(x: 'Jul', y: 80, secondSeriesYValue: 58, thirdSeriesYValue: 65),
|
||||
ChartSampleData(x: 'Aug', y: 78, secondSeriesYValue: 60, thirdSeriesYValue: 66),
|
||||
ChartSampleData(x: 'Sep', y: 72, secondSeriesYValue: 55, thirdSeriesYValue: 64),
|
||||
ChartSampleData(x: 'Oct', y: 65, secondSeriesYValue: 50, thirdSeriesYValue: 57),
|
||||
ChartSampleData(x: 'Nov', y: 58, secondSeriesYValue: 45, thirdSeriesYValue: 53),
|
||||
ChartSampleData(x: 'Dec', y: 50, secondSeriesYValue: 40, thirdSeriesYValue: 48)
|
||||
];
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void onSelectIntervalType(DateTimeIntervalType interval) {
|
||||
intervalType = interval;
|
||||
update();
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/model/chart_model.dart';
|
||||
import 'package:marco/model/product_order_modal.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class EcommerceController extends MyController {
|
||||
List<ChartSampleData>? salesAnalyticsData;
|
||||
List<ProductOrderModal> order = [];
|
||||
String selectedTimeByLocation = "Year";
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
ProductOrderModal.dummyList.then((value) {
|
||||
order = value.sublist(0, 5);
|
||||
update();
|
||||
});
|
||||
salesAnalyticsData = <ChartSampleData>[
|
||||
ChartSampleData(x: 'Jan', y: 43, secondSeriesYValue: 37, thirdSeriesYValue: 41),
|
||||
ChartSampleData(x: 'Feb', y: 45, secondSeriesYValue: 37, thirdSeriesYValue: 45),
|
||||
ChartSampleData(x: 'Mar', y: 50, secondSeriesYValue: 39, thirdSeriesYValue: 48),
|
||||
ChartSampleData(x: 'Apr', y: 55, secondSeriesYValue: 43, thirdSeriesYValue: 52),
|
||||
ChartSampleData(x: 'May', y: 63, secondSeriesYValue: 48, thirdSeriesYValue: 57),
|
||||
ChartSampleData(x: 'Jun', y: 68, secondSeriesYValue: 54, thirdSeriesYValue: 61),
|
||||
ChartSampleData(x: 'Jul', y: 72, secondSeriesYValue: 57, thirdSeriesYValue: 66),
|
||||
ChartSampleData(x: 'Aug', y: 70, secondSeriesYValue: 57, thirdSeriesYValue: 66),
|
||||
ChartSampleData(x: 'Sep', y: 66, secondSeriesYValue: 54, thirdSeriesYValue: 63),
|
||||
ChartSampleData(x: 'Oct', y: 57, secondSeriesYValue: 48, thirdSeriesYValue: 55),
|
||||
ChartSampleData(x: 'Nov', y: 50, secondSeriesYValue: 43, thirdSeriesYValue: 50),
|
||||
ChartSampleData(x: 'Dec', y: 45, secondSeriesYValue: 37, thirdSeriesYValue: 45)
|
||||
];
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
final List<ChartSampleData> chartData = [
|
||||
ChartSampleData(x: 'Jan', y: 10, yValue: 1000),
|
||||
ChartSampleData(x: 'Fab', y: 20, yValue: 2000),
|
||||
ChartSampleData(x: 'Mar', y: 15, yValue: 1500),
|
||||
ChartSampleData(x: 'Jun', y: 5, yValue: 500),
|
||||
ChartSampleData(x: 'Jul', y: 30, yValue: 3000),
|
||||
ChartSampleData(x: 'Aug', y: 20, yValue: 2000),
|
||||
ChartSampleData(x: 'Sep', y: 40, yValue: 4000),
|
||||
ChartSampleData(x: 'Oct', y: 60, yValue: 6000),
|
||||
ChartSampleData(x: 'Nov', y: 55, yValue: 5500),
|
||||
ChartSampleData(x: 'Dec', y: 38, yValue: 3000),
|
||||
];
|
||||
final TooltipBehavior chart = TooltipBehavior(
|
||||
enable: true,
|
||||
format: 'point.x : point.yValue1 : point.yValue2',
|
||||
);
|
||||
|
||||
final List<ChartSampleData> circleChart = [
|
||||
ChartSampleData(x: 'David', y: 25, pointColor: const Color.fromRGBO(9, 0, 136, 1)),
|
||||
ChartSampleData(x: 'Steve', y: 38, pointColor: const Color.fromRGBO(147, 0, 119, 1)),
|
||||
ChartSampleData(x: 'Jack', y: 34, pointColor: const Color.fromRGBO(228, 0, 124, 1)),
|
||||
ChartSampleData(x: 'Others', y: 52, pointColor: const Color.fromRGBO(255, 189, 57, 1))
|
||||
];
|
||||
|
||||
void onSelectedTimeByLocation(String time) {
|
||||
selectedTimeByLocation = time;
|
||||
update();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
salesAnalyticsData!.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
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 JobController extends MyController {
|
||||
int isSelectedListingPerformanceTime = 0;
|
||||
List<ChartSampleData>? chartData;
|
||||
TooltipBehavior? columnToolTip;
|
||||
List<JobRecentApplicationModel> recentApplication = [];
|
||||
List<String> dummyTexts = List.generate(12, (index) => MyTextUtils.getDummyText(60));
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
chartData = <ChartSampleData>[
|
||||
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();
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/model/chart_model.dart';
|
||||
import 'package:marco/model/project_summary_model.dart';
|
||||
import 'package:marco/model/task_list_model.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class ProjectController extends MyController {
|
||||
TooltipBehavior? tooltipBehavior;
|
||||
List<TaskListModel> task = [];
|
||||
List<ProjectSummaryModel> projectSummary = [];
|
||||
List<ChartSampleData>? chartData;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
TaskListModel.dummyList.then((value) {
|
||||
task = value;
|
||||
update();
|
||||
});
|
||||
ProjectSummaryModel.dummyList.then((value) {
|
||||
projectSummary = value.sublist(0, 5);
|
||||
update();
|
||||
});
|
||||
chartData = <ChartSampleData>[
|
||||
ChartSampleData(x: 'Jan', y: 10, secondSeriesYValue: 8, thirdSeriesYValue: 12),
|
||||
ChartSampleData(x: 'Feb', y: 5, secondSeriesYValue: 6, thirdSeriesYValue: 7),
|
||||
ChartSampleData(x: 'Mar', y: 11, secondSeriesYValue: 9, thirdSeriesYValue: 6),
|
||||
ChartSampleData(x: 'Apr', y: 14, secondSeriesYValue: 10, thirdSeriesYValue: 13),
|
||||
ChartSampleData(x: 'May', y: 9, secondSeriesYValue: 7, thirdSeriesYValue: 5),
|
||||
ChartSampleData(x: 'Jun', y: 8, secondSeriesYValue: 12, thirdSeriesYValue: 11),
|
||||
ChartSampleData(x: 'Jul', y: 12, secondSeriesYValue: 11, thirdSeriesYValue: 9),
|
||||
ChartSampleData(x: 'Aug', y: 7, secondSeriesYValue: 13, thirdSeriesYValue: 10),
|
||||
ChartSampleData(x: 'Sep', y: 6, secondSeriesYValue: 5, thirdSeriesYValue: 8),
|
||||
ChartSampleData(x: 'Oct', y: 4, secondSeriesYValue: 14, thirdSeriesYValue: 15),
|
||||
ChartSampleData(x: 'Nov', y: 13, secondSeriesYValue: 4, thirdSeriesYValue: 11),
|
||||
ChartSampleData(x: 'Dec', y: 15, secondSeriesYValue: 3, thirdSeriesYValue: 4)
|
||||
];
|
||||
|
||||
tooltipBehavior = TooltipBehavior(enable: true, format: 'point.x : point.ym');
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void onSelectTask(TaskListModel task) {
|
||||
task.isSelectTask = !task.isSelectTask;
|
||||
update();
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/model/chart_model.dart';
|
||||
import 'package:marco/model/recent_order_model.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class SalesController extends MyController {
|
||||
List<ChartData>? statisticsData;
|
||||
List<RecentOrderModel> recentOrder = [];
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
RecentOrderModel.dummyList.then((value) {
|
||||
recentOrder = value;
|
||||
update();
|
||||
});
|
||||
|
||||
statisticsData = <ChartData>[
|
||||
ChartData(2005, 15, 25),
|
||||
ChartData(2006, 40, 55),
|
||||
ChartData(2007, 50, 70),
|
||||
ChartData(2008, 55, 80),
|
||||
ChartData(2009, 65, 85),
|
||||
ChartData(2010, 70, 95),
|
||||
ChartData(2011, 90, 110)
|
||||
];
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
final List<ChartSampleData> visitorChartData = [
|
||||
ChartSampleData(x: 'Jan', y: 12, yValue: 1200),
|
||||
ChartSampleData(x: 'Feb', y: 18, yValue: 1800),
|
||||
ChartSampleData(x: 'Mar', y: 22, yValue: 2200),
|
||||
ChartSampleData(x: 'Apr', y: 10, yValue: 1000),
|
||||
ChartSampleData(x: 'May', y: 25, yValue: 2500),
|
||||
ChartSampleData(x: 'Jun', y: 35, yValue: 3500),
|
||||
ChartSampleData(x: 'Jul', y: 28, yValue: 2800),
|
||||
ChartSampleData(x: 'Aug', y: 45, yValue: 4500),
|
||||
ChartSampleData(x: 'Sep', y: 50, yValue: 5000),
|
||||
ChartSampleData(x: 'Oct', y: 60, yValue: 6000),
|
||||
ChartSampleData(x: 'Nov', y: 42, yValue: 4200),
|
||||
ChartSampleData(x: 'Dec', y: 55, yValue: 5500),
|
||||
];
|
||||
|
||||
final TooltipBehavior visitorChart = TooltipBehavior(
|
||||
enable: true,
|
||||
format: 'point.x : point.yValue1 : point.yValue2',
|
||||
);
|
||||
}
|
||||
|
||||
class ChartData {
|
||||
ChartData(this.x, this.y, this.y2);
|
||||
|
||||
final double x;
|
||||
final double y;
|
||||
final double y2;
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ChartSampleData {
|
||||
ChartSampleData(
|
||||
{this.x,
|
||||
this.y,
|
||||
this.xValue,
|
||||
this.yValue,
|
||||
this.secondSeriesYValue,
|
||||
this.thirdSeriesYValue,
|
||||
this.pointColor,
|
||||
this.size,
|
||||
this.text,
|
||||
this.open,
|
||||
this.close,
|
||||
this.low,
|
||||
this.high,
|
||||
this.volume});
|
||||
|
||||
final dynamic x;
|
||||
final num? y;
|
||||
final dynamic xValue;
|
||||
final num? yValue;
|
||||
final num? secondSeriesYValue;
|
||||
final num? thirdSeriesYValue;
|
||||
final Color? pointColor;
|
||||
final num? size;
|
||||
final String? text;
|
||||
final num? open;
|
||||
final num? close;
|
||||
final num? low;
|
||||
final num? high;
|
||||
final num? volume;
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:marco/helpers/services/json_decoder.dart';
|
||||
import 'package:marco/images.dart';
|
||||
import 'package:marco/model/identifier_model.dart';
|
||||
|
||||
class ChatModel extends IdentifierModel {
|
||||
final String firstName, avatar, email;
|
||||
|
||||
final List<ChatMessageModel> messages;
|
||||
|
||||
ChatModel(super.id, this.firstName, this.avatar, this.messages, this.email);
|
||||
|
||||
static ChatModel fromJSON(Map<String, dynamic> json) {
|
||||
JSONDecoder decoder = JSONDecoder(json);
|
||||
|
||||
String firstName = decoder.getString('first_name');
|
||||
String email = decoder.getString('email');
|
||||
String avatar = Images.randomImage(Images.avatars);
|
||||
|
||||
List<dynamic>? messagesList = decoder.getObjectListOrNull('messages');
|
||||
List<ChatMessageModel> messages = [];
|
||||
if (messagesList != null) {
|
||||
messages = ChatMessageModel.listFromJSON(messagesList);
|
||||
}
|
||||
|
||||
return ChatModel(decoder.getId, firstName, avatar, messages, email);
|
||||
}
|
||||
|
||||
static List<ChatModel> listFromJSON(List<dynamic> list) {
|
||||
return list.map((e) => ChatModel.fromJSON(e)).toList();
|
||||
}
|
||||
|
||||
static List<ChatModel>? _dummyList;
|
||||
|
||||
static Future<List<ChatModel>> get dummyList async {
|
||||
if (_dummyList == null) {
|
||||
dynamic data = json.decode(await getData());
|
||||
_dummyList = listFromJSON(data);
|
||||
}
|
||||
|
||||
return _dummyList!;
|
||||
}
|
||||
|
||||
static Future<String> getData() async {
|
||||
return await rootBundle.loadString('assets/data/chat.json');
|
||||
}
|
||||
}
|
||||
|
||||
class ChatMessageModel extends IdentifierModel {
|
||||
final String message, imageSent;
|
||||
final DateTime sendAt;
|
||||
final bool fromMe;
|
||||
|
||||
ChatMessageModel(super.id, this.message, this.sendAt, this.fromMe, this.imageSent);
|
||||
|
||||
static ChatMessageModel fromJSON(Map<String, dynamic> json) {
|
||||
JSONDecoder decoder = JSONDecoder(json);
|
||||
|
||||
String message = decoder.getString('message');
|
||||
String imageSent = Images.randomImage(Images.avatars);
|
||||
DateTime sendAt = decoder.getDateTime('send_at');
|
||||
bool fromMe = decoder.getBool('from_me');
|
||||
|
||||
return ChatMessageModel(decoder.getId, message, sendAt, fromMe, imageSent);
|
||||
}
|
||||
|
||||
static List<ChatMessageModel> listFromJSON(List<dynamic> list) {
|
||||
return list.map((e) => ChatMessageModel.fromJSON(e)).toList();
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:marco/helpers/services/json_decoder.dart';
|
||||
import 'package:marco/model/identifier_model.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class CoinGrowthModel extends IdentifierModel {
|
||||
final String asset, ipAddress, status;
|
||||
final int amount;
|
||||
final DateTime date;
|
||||
|
||||
CoinGrowthModel(
|
||||
super.id,
|
||||
this.asset,
|
||||
this.ipAddress,
|
||||
this.status,
|
||||
this.amount,
|
||||
this.date,
|
||||
);
|
||||
|
||||
static CoinGrowthModel fromJSON(Map<String, dynamic> json) {
|
||||
JSONDecoder decoder = JSONDecoder(json);
|
||||
|
||||
String asset = decoder.getString('asset');
|
||||
String ipAddress = decoder.getString('ip_address');
|
||||
String status = decoder.getString('status');
|
||||
int amount = decoder.getInt('amount');
|
||||
DateTime date = decoder.getDateTime('date');
|
||||
|
||||
return CoinGrowthModel(decoder.getId, asset, ipAddress, status, amount, date);
|
||||
}
|
||||
|
||||
static List<CoinGrowthModel> listFromJSON(List<dynamic> list) {
|
||||
return list.map((e) => CoinGrowthModel.fromJSON(e)).toList();
|
||||
}
|
||||
|
||||
static List<CoinGrowthModel>? _dummyList;
|
||||
|
||||
static Future<List<CoinGrowthModel>> get dummyList async {
|
||||
if (_dummyList == null) {
|
||||
dynamic data = json.decode(await getData());
|
||||
_dummyList = listFromJSON(data);
|
||||
}
|
||||
|
||||
return _dummyList!;
|
||||
}
|
||||
|
||||
static Future<String> getData() async {
|
||||
return await rootBundle.loadString('assets/data/coin_growth.json');
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:marco/helpers/services/json_decoder.dart';
|
||||
import 'package:marco/model/identifier_model.dart';
|
||||
|
||||
class Customer extends IdentifierModel {
|
||||
final String firstName, lastName, phoneNumber, projectName, balance;
|
||||
final double ordersCount;
|
||||
final DateTime lastOrder;
|
||||
|
||||
String get fullName => '$firstName $lastName $projectName';
|
||||
|
||||
Customer(
|
||||
super.id,
|
||||
this.firstName,
|
||||
this.lastName,
|
||||
this.phoneNumber,
|
||||
this.balance,
|
||||
this.ordersCount,
|
||||
this.lastOrder,
|
||||
this.projectName,
|
||||
);
|
||||
|
||||
static Customer fromJSON(Map<String, dynamic> json) {
|
||||
JSONDecoder decoder = JSONDecoder(json);
|
||||
|
||||
String firstName = decoder.getString('first_name');
|
||||
String lastName = decoder.getString('last_name');
|
||||
String phoneNumber = decoder.getString('phone_number');
|
||||
String balance = decoder.getString('balance');
|
||||
double ordersCount = decoder.getDouble('order_count');
|
||||
DateTime lastOrder = decoder.getDateTime('last_order');
|
||||
String projectName = decoder.getString('project_name');
|
||||
|
||||
return Customer(
|
||||
decoder.getId,
|
||||
firstName,
|
||||
lastName,
|
||||
phoneNumber,
|
||||
balance,
|
||||
ordersCount,
|
||||
lastOrder,
|
||||
projectName,
|
||||
);
|
||||
}
|
||||
|
||||
static List<Customer> listFromJSON(List<dynamic> list) {
|
||||
return list.map((e) => Customer.fromJSON(e)).toList();
|
||||
}
|
||||
|
||||
static List<Customer>? _dummyList;
|
||||
|
||||
static Future<List<Customer>> get dummyList async {
|
||||
if (_dummyList == null) {
|
||||
dynamic data = json.decode(await getData());
|
||||
_dummyList = listFromJSON(data);
|
||||
}
|
||||
|
||||
return _dummyList!.sublist(0, 10);
|
||||
}
|
||||
|
||||
static Future<String> getData() async {
|
||||
return await rootBundle.loadString('assets/data/customer.json');
|
||||
}
|
||||
}
|
@ -9,10 +9,6 @@ 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/dashboard_screen.dart';
|
||||
import 'package:marco/view/dashboard/add_employee_screen.dart';
|
||||
import 'package:marco/view/dashboard/daily_task_screen.dart';
|
||||
import 'package:marco/view/taskPlaning/report_task_screen.dart';
|
||||
import 'package:marco/view/taskPlaning/comment_task_screen.dart';
|
||||
import 'package:marco/view/dashboard/Attendence/attendance_screen.dart';
|
||||
import 'package:marco/view/taskPlaning/daily_task_planing.dart';
|
||||
import 'package:marco/view/taskPlaning/daily_progress.dart';
|
||||
@ -55,16 +51,7 @@ getPageRoute() {
|
||||
name: '/dashboard/employees',
|
||||
page: () => EmployeesScreen(),
|
||||
middlewares: [AuthMiddleware()]),
|
||||
// Employees Creation
|
||||
GetPage(
|
||||
name: '/employees/addEmployee',
|
||||
page: () => AddEmployeeScreen(),
|
||||
middlewares: [AuthMiddleware()]),
|
||||
// Daily Task Planning
|
||||
GetPage(
|
||||
name: '/dashboard/daily-task',
|
||||
page: () => DailyTaskScreen(),
|
||||
middlewares: [AuthMiddleware()]),
|
||||
GetPage(
|
||||
name: '/dashboard/daily-task-planing',
|
||||
page: () => DailyTaskPlaningScreen(),
|
||||
@ -73,14 +60,6 @@ getPageRoute() {
|
||||
name: '/dashboard/daily-task-progress',
|
||||
page: () => DailyProgressReportScreen(),
|
||||
middlewares: [AuthMiddleware()]),
|
||||
GetPage(
|
||||
name: '/daily-task/report-task',
|
||||
page: () => ReportTaskScreen(),
|
||||
middlewares: [AuthMiddleware()]),
|
||||
GetPage(
|
||||
name: '/daily-task/comment-task',
|
||||
page: () => CommentTaskScreen(),
|
||||
middlewares: [AuthMiddleware()]),
|
||||
// Authentication
|
||||
GetPage(name: '/auth/login', page: () => LoginScreen()),
|
||||
GetPage(name: '/auth/login-option', page: () => LoginOptionScreen()),
|
||||
|
@ -1,261 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/dashboard/add_employee_controller.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/widgets/my_breadcrumb.dart';
|
||||
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
|
||||
import 'package:marco/helpers/widgets/my_button.dart';
|
||||
import 'package:marco/helpers/widgets/my_card.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex_item.dart';
|
||||
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/layout.dart';
|
||||
|
||||
class AddEmployeeScreen extends StatefulWidget {
|
||||
const AddEmployeeScreen({super.key});
|
||||
|
||||
@override
|
||||
State<AddEmployeeScreen> createState() => _AddEmployeeScreenState();
|
||||
}
|
||||
|
||||
class _AddEmployeeScreenState extends State<AddEmployeeScreen> with UIMixin {
|
||||
final AddEmployeeController controller = Get.put(AddEmployeeController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: GetBuilder<AddEmployeeController>(
|
||||
init: controller,
|
||||
tag: 'add_employee_controller',
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium(
|
||||
"Add Employee",
|
||||
fontSize: 18,
|
||||
fontWeight: 600,
|
||||
),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Employee'),
|
||||
MyBreadcrumbItem(name: 'Add Employee'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(sizes: "lg-8 md-12", child: detail()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget detail() {
|
||||
return Form(
|
||||
key: controller.basicValidator.formKey,
|
||||
child: MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withOpacity(0.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(LucideIcons.server, size: 16),
|
||||
MySpacing.width(12),
|
||||
MyText.titleMedium("General", fontWeight: 600),
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.labelMedium("First Name"),
|
||||
MySpacing.height(8),
|
||||
TextFormField(
|
||||
validator: controller.basicValidator.getValidation('first_name'),
|
||||
controller: controller.basicValidator.getController('first_name'),
|
||||
keyboardType: TextInputType.name,
|
||||
decoration: InputDecoration(
|
||||
hintText: "eg: Jhon",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(16),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
MyText.labelMedium("Last Name"),
|
||||
MySpacing.height(8),
|
||||
TextFormField(
|
||||
validator: controller.basicValidator.getValidation('last_name'),
|
||||
controller: controller.basicValidator.getController('last_name'),
|
||||
keyboardType: TextInputType.name,
|
||||
decoration: InputDecoration(
|
||||
hintText: "eg: Doe",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(16),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
MyText.labelMedium("Phone Number"),
|
||||
MySpacing.height(8),
|
||||
TextFormField(
|
||||
validator: controller.basicValidator.getValidation('phone_number'),
|
||||
controller: controller.basicValidator.getController('phone_number'),
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: InputDecoration(
|
||||
hintText: "eg: +91 9876543210",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(16),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
MyFlex(contentPadding: false, children: [
|
||||
MyFlexItem(
|
||||
sizes: 'lg-6 md-12',
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.labelMedium("Select Gender"),
|
||||
MySpacing.height(8),
|
||||
DropdownButtonFormField<Gender>(
|
||||
value: controller.selectedGender,
|
||||
dropdownColor: contentTheme.background,
|
||||
menuMaxHeight: 200,
|
||||
isDense: true,
|
||||
items: Gender.values.map((gender) {
|
||||
return DropdownMenuItem<Gender>(
|
||||
value: gender,
|
||||
child: MyText.labelMedium(
|
||||
gender.name[0].toUpperCase() + gender.name.substring(1),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
icon: const Icon(Icons.expand_more, size: 20),
|
||||
decoration: InputDecoration(
|
||||
hintText: "Select Gender",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(14),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
onChanged: controller.onGenderSelected,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
]),
|
||||
MySpacing.height(24),
|
||||
MyFlex(contentPadding: false, children: [
|
||||
MyFlexItem(
|
||||
sizes: 'lg-6 md-12',
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.labelMedium("Select Role"),
|
||||
MySpacing.height(8),
|
||||
DropdownButtonFormField<String>(
|
||||
value: controller.selectedRoleId,
|
||||
dropdownColor: contentTheme.background,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Select Role",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(14),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
icon: const Icon(Icons.expand_more, size: 20),
|
||||
isDense: true,
|
||||
items: controller.roles.map((role) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: role['id'],
|
||||
child: Text(role['name']),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: controller.onRoleSelected,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
]),
|
||||
MySpacing.height(24),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
MyButton.text(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
padding: MySpacing.xy(20, 16),
|
||||
splashColor: contentTheme.secondary.withValues(alpha: 0.1),
|
||||
child: MyText.bodySmall('Cancel'),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
MyButton(
|
||||
onPressed: () async {
|
||||
if (controller.basicValidator.validateForm()) {
|
||||
await controller.createEmployees();
|
||||
}
|
||||
},
|
||||
elevation: 0,
|
||||
padding: MySpacing.xy(20, 16),
|
||||
backgroundColor: contentTheme.primary,
|
||||
borderRadiusAll: AppStyle.buttonRadius.medium,
|
||||
child: MyText.bodySmall(
|
||||
'Save',
|
||||
color: contentTheme.onPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,546 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/dashboard/analytics_controller.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_progress_bar.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';
|
||||
|
||||
class AnalyticsScreen extends StatefulWidget {
|
||||
const AnalyticsScreen({super.key});
|
||||
|
||||
@override
|
||||
State<AnalyticsScreen> createState() => _AnalyticsScreenState();
|
||||
}
|
||||
|
||||
class _AnalyticsScreenState extends State<AnalyticsScreen> with UIMixin {
|
||||
AnalyticsController controller = Get.put(AnalyticsController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: GetBuilder(
|
||||
init: controller,
|
||||
tag: 'analytics_controller',
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Analytics", fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Analytics', active: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(children: [
|
||||
MyFlexItem(sizes: 'lg-2.4 md-6 sm-6', child: stats("Pending", "1.245", "5.12%", LucideIcons.clock)),
|
||||
MyFlexItem(sizes: 'lg-2.4 md-6 sm-6', child: stats("Paid", "92.342", "67.89%", LucideIcons.circle_check)),
|
||||
MyFlexItem(sizes: 'lg-2.4 md-4 sm-4', child: stats("Rejected", "12.367", "3.56%", LucideIcons.circle_x)),
|
||||
MyFlexItem(sizes: 'lg-2.4 md-4 sm-4', child: stats("In Progress", "5.125", "10.78%", LucideIcons.hourglass)),
|
||||
MyFlexItem(sizes: 'lg-2.4 md-4 sm-4', child: stats("Canceled", "7.489", "4.45%", LucideIcons.trash)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: activityOnThePage()),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: audienceOverview()),
|
||||
MyFlexItem(sizes: 'lg-4 md-12', child: buildTrafficSources()),
|
||||
MyFlexItem(sizes: 'lg-4 md-6 sm-6', child: buildMostActiveUser()),
|
||||
MyFlexItem(sizes: 'lg-4 md-6 sm-6', child: buildVisitorsByCountry()),
|
||||
MyFlexItem(child: buildVisitorByChannel()),
|
||||
]),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget stats(String title, String subTitle, String percentage, IconData icon) {
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 0,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.all(24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodySmall(title, maxLines: 1),
|
||||
MySpacing.height(4),
|
||||
MyText.titleLarge(subTitle, maxLines: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyContainer(
|
||||
color: contentTheme.secondary.withValues(alpha:0.2),
|
||||
paddingAll: 12,
|
||||
child: Icon(icon, size: 16, color: contentTheme.onBackground),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
MyContainer(
|
||||
color: contentTheme.background,
|
||||
borderRadiusAll: 0,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(LucideIcons.arrow_up_right, size: 16),
|
||||
MySpacing.width(8),
|
||||
MyText.labelMedium(percentage),
|
||||
MySpacing.width(8),
|
||||
Expanded(child: MyText.labelMedium("Last Month", muted: true, maxLines: 1)),
|
||||
Expanded(child: InkWell(onTap: () {}, child: MyText.labelMedium("View More", fontWeight: 600, maxLines: 1))),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget activityOnThePage() {
|
||||
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(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: MyText.bodyMedium("Activity on the pages", fontWeight: 600, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
PopupMenuButton(
|
||||
onSelected: controller.onSelectedActivity,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
itemBuilder: (BuildContext context) {
|
||||
return ["Year", "Month", "Week", "Day", "Hours"].map((behavior) {
|
||||
return PopupMenuItem(
|
||||
value: behavior,
|
||||
height: 32,
|
||||
child: MyText.bodySmall(
|
||||
behavior.toString(),
|
||||
color: theme.colorScheme.onSurface,
|
||||
fontWeight: 600,
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
color: theme.cardTheme.color,
|
||||
child: MyContainer.bordered(
|
||||
padding: MySpacing.xy(8, 4),
|
||||
borderRadiusAll: 8,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
MyText.bodySmall(
|
||||
controller.selectActivity.toString(),
|
||||
fontWeight: 600,
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
MySpacing.width(4),
|
||||
Icon(
|
||||
LucideIcons.chevron_down,
|
||||
size: 20,
|
||||
color: theme.colorScheme.onSurface,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
SizedBox(
|
||||
height: 305,
|
||||
child: SfCartesianChart(
|
||||
plotAreaBorderWidth: 0,
|
||||
primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)),
|
||||
tooltipBehavior: controller.columnChartToolTip,
|
||||
legend: Legend(isVisible: true, position: LegendPosition.bottom),
|
||||
series: [
|
||||
ColumnSeries<ChartSampleData, int>(
|
||||
opacity: 0.9,
|
||||
width: 0.6,
|
||||
color: contentTheme.title,
|
||||
dataSource: controller.columnChart,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true)),
|
||||
ColumnSeries<ChartSampleData, int>(
|
||||
color: contentTheme.success,
|
||||
dataSource: controller.columnChart,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.yValue,
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget audienceOverview() {
|
||||
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("Audience Overview", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SizedBox(
|
||||
height: 318,
|
||||
child: SfCartesianChart(tooltipBehavior: controller.audienceOverview, series: <CartesianSeries>[
|
||||
BarSeries<ChartSampleData, dynamic>(
|
||||
color: Colors.blue,
|
||||
borderRadius: BorderRadius.horizontal(right: Radius.circular(8)),
|
||||
dataSource: controller.audienceOverviewChart,
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
width: 0.6,
|
||||
spacing: 0.3),
|
||||
BarSeries<ChartSampleData, dynamic>(
|
||||
borderRadius: BorderRadius.horizontal(right: Radius.circular(8)),
|
||||
dataSource: controller.audienceOverviewChart,
|
||||
color: Colors.teal,
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.yValue,
|
||||
width: 0.6,
|
||||
spacing: 0.3)
|
||||
]))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTrafficSources() {
|
||||
Widget buildData(String browser, session, double process) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(child: MyText.bodyMedium(browser, fontWeight: 600, overflow: TextOverflow.ellipsis)),
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
if (session >= 5000) Icon(LucideIcons.trending_up, size: 20, color: contentTheme.success),
|
||||
if (session < 5000) Icon(LucideIcons.trending_down, size: 20, color: contentTheme.danger),
|
||||
MySpacing.width(8),
|
||||
Expanded(
|
||||
child: MyText.bodyMedium("$session", fontWeight: 600, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: MyProgressBar(
|
||||
progress: process,
|
||||
height: 4,
|
||||
radius: 4,
|
||||
inactiveColor: theme.dividerColor,
|
||||
activeColor: contentTheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 0,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.only(left: 23, top: 19),
|
||||
child: MyText.titleMedium("Traffic Sources", fontWeight: 600),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
Divider(height: 0),
|
||||
MySpacing.height(24),
|
||||
Padding(
|
||||
padding: MySpacing.only(left: 23),
|
||||
child: Row(children: [
|
||||
Expanded(child: MyText.bodyMedium("Browser", fontWeight: 600)),
|
||||
Expanded(child: MyText.bodyMedium("Sessions", fontWeight: 600)),
|
||||
Expanded(child: MyText.bodyMedium("Traffic", fontWeight: 600)),
|
||||
]),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
Divider(height: 0),
|
||||
Padding(
|
||||
padding: MySpacing.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
buildData("Google Chrome", 12000, .30),
|
||||
MySpacing.height(24),
|
||||
buildData("Apple Safari", 7000, .25),
|
||||
MySpacing.height(24),
|
||||
buildData("Microsoft Edge", 4500, .15),
|
||||
MySpacing.height(24),
|
||||
buildData("Mozilla Firefox", 8000, .22),
|
||||
MySpacing.height(24),
|
||||
buildData("Opera Browser", 3000, .18),
|
||||
MySpacing.height(24),
|
||||
buildData("Brave Browser", 2000, .12),
|
||||
MySpacing.height(24),
|
||||
buildData("Vivaldi Browser", 1500, .08),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildMostActiveUser() {
|
||||
Widget buildData(String image, name, emailID) {
|
||||
return MyContainer.bordered(
|
||||
child: 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(name, fontWeight: 600),
|
||||
MySpacing.height(4),
|
||||
MyText.labelMedium(
|
||||
emailID,
|
||||
fontWeight: 600,
|
||||
xMuted: true,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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.titleMedium("Most Active user", fontWeight: 600),
|
||||
MySpacing.height(20),
|
||||
SizedBox(
|
||||
height: 372,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
buildData(Images.avatars[0], "John Doe", "john.doe@example.com"),
|
||||
MySpacing.height(24),
|
||||
buildData(Images.avatars[1], "Emily Smith", "emily.smith@example.com"),
|
||||
MySpacing.height(24),
|
||||
buildData(Images.avatars[2], "Michael Johnson", "michael.johnson@example.com"),
|
||||
MySpacing.height(24),
|
||||
buildData(Images.avatars[3], "Olivia Williams", "olivia.williams@example.com"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Widget buildVisitorsByCountry() {
|
||||
Widget buildData(String image, name, count) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
paddingAll: 0,
|
||||
height: 41,
|
||||
width: 41,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
child: Image.asset(
|
||||
image,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
Expanded(
|
||||
child: MyText.bodyMedium(name, fontWeight: 600, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
MyContainer(
|
||||
borderRadiusAll: 8,
|
||||
padding: MySpacing.xy(8, 8),
|
||||
color: Colors.brown.withAlpha(36),
|
||||
child: MyText.bodySmall(
|
||||
numberFormatter(count),
|
||||
fontWeight: 600,
|
||||
color: Colors.brown,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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.titleMedium("Visitor by country's", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
buildData('assets/country/united_states.png', "United State", "41560"),
|
||||
MySpacing.height(24),
|
||||
buildData('assets/country/argentina.png', "Argentina", "18400"),
|
||||
MySpacing.height(24),
|
||||
buildData('assets/country/germany.png', "Germany", "9000"),
|
||||
MySpacing.height(24),
|
||||
buildData('assets/country/mexico.png', "Mexico", "15325"),
|
||||
MySpacing.height(24),
|
||||
buildData('assets/country/russia.png', "Russia", "12222"),
|
||||
MySpacing.height(24),
|
||||
buildData('assets/country/canada.png', "Canada", "2040"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildVisitorByChannel() {
|
||||
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("Visitors By Channel", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
if (controller.visitorByChannel.isNotEmpty)
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: DataTable(
|
||||
sortAscending: true,
|
||||
columnSpacing: 105,
|
||||
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('Channel', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Session', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Bounce Rate', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Session Duration', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Target Reached', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Page Per Session', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Action', color: contentTheme.primary)),
|
||||
],
|
||||
rows: controller.visitorByChannel
|
||||
.mapIndexed((index, data) => DataRow(cells: [
|
||||
DataCell(MyText.bodyMedium('${data.id}')),
|
||||
DataCell(MyText.labelLarge(data.channel, overflow: TextOverflow.ellipsis, maxLines: 1)),
|
||||
DataCell(MyText.bodySmall('${data.session}', fontWeight: 600)),
|
||||
DataCell(MyText.bodySmall('${data.bounceRate}%', fontWeight: 600)),
|
||||
DataCell(MyText.bodySmall('${Utils.getDateTimeStringFromDateTime(data.sessionDuration)}', fontWeight: 600)),
|
||||
DataCell(
|
||||
MyContainer(
|
||||
borderRadiusAll: 4,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
padding: MySpacing.xy(8, 8),
|
||||
color: contentTheme.primary.withAlpha(32),
|
||||
child: MyText.bodySmall('${data.targetReached}', fontWeight: 600, color: contentTheme.primary),
|
||||
),
|
||||
),
|
||||
DataCell(MyText.bodyMedium('${data.pagePerSession}')),
|
||||
DataCell(SizedBox(
|
||||
width: 130,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyContainer(
|
||||
onTap: () => {},
|
||||
padding: MySpacing.xy(8, 8),
|
||||
color: contentTheme.primary.withAlpha(36),
|
||||
child: Icon(LucideIcons.pencil, size: 14, color: contentTheme.primary),
|
||||
),
|
||||
MyContainer(
|
||||
onTap: () => {},
|
||||
padding: MySpacing.xy(8, 8),
|
||||
color: contentTheme.success.withAlpha(36),
|
||||
child: Icon(LucideIcons.pencil, size: 14, color: contentTheme.success),
|
||||
),
|
||||
MyContainer(
|
||||
onTap: () => controller.removeData(index),
|
||||
padding: MySpacing.xy(8, 8),
|
||||
color: contentTheme.danger.withAlpha(36),
|
||||
child: Icon(LucideIcons.trash_2, size: 14, color: contentTheme.danger),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
]))
|
||||
.toList()),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,523 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/dashboard/crm_controller.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_progress_bar.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';
|
||||
|
||||
class CrmScreen extends StatefulWidget {
|
||||
const CrmScreen({super.key});
|
||||
|
||||
@override
|
||||
State<CrmScreen> createState() => _CrmScreenState();
|
||||
}
|
||||
|
||||
class _CrmScreenState extends State<CrmScreen> with UIMixin {
|
||||
CrmController controller = Get.put(CrmController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder(
|
||||
init: controller,
|
||||
tag: 'crm_dashboard_controller',
|
||||
builder: (controller) {
|
||||
return Layout(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Crm", fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Crm', active: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(
|
||||
sizes: "lg-3 md-6 sm-6",
|
||||
child:
|
||||
stats(LucideIcons.circle_dollar_sign, "Nominal Balance", "\$5,780", "Nominal Balance last month", "\$6,290", contentTheme.primary)),
|
||||
MyFlexItem(
|
||||
sizes: "lg-3 md-6 sm-6",
|
||||
child: stats(LucideIcons.package, "Total Stock Product", "5.264", "Total Stock product last month", "2.546", contentTheme.secondary)),
|
||||
MyFlexItem(
|
||||
sizes: "lg-3 md-6 sm-6",
|
||||
child: stats(LucideIcons.file_down, "Nominal Revenue", "5.264", "Total revenue last month", "2.546", contentTheme.success)),
|
||||
MyFlexItem(
|
||||
sizes: "lg-3 md-6 sm-6",
|
||||
child: stats(LucideIcons.file_up, "Nominal Expenses", "\$19,644", "Total expenses last month", "\$18,946", contentTheme.warning)),
|
||||
MyFlexItem(sizes: 'lg-9', child: revenueForecast()),
|
||||
MyFlexItem(sizes: 'lg-3', child: topDeals()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: dealSource()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: leadResponse()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: openDeals()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: leadSource()),
|
||||
MyFlexItem(child: leadReport()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget stats(IconData icon, String title, String subTitle, String statsMonthName, String statsMonthRevenue, 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: SizedBox(
|
||||
height: 100,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
MyContainer.bordered(paddingAll: 8, borderColor: color, child: Icon(icon, size: 16, color: color)),
|
||||
MySpacing.width(12),
|
||||
MyText.bodyMedium(title, fontWeight: 600),
|
||||
],
|
||||
),
|
||||
MyText.titleMedium(subTitle, fontWeight: 600),
|
||||
Row(
|
||||
children: [
|
||||
MyText.labelMedium(statsMonthName, fontWeight: 600, xMuted: true),
|
||||
MySpacing.width(8),
|
||||
Expanded(child: MyText.labelMedium(statsMonthRevenue, fontWeight: 600, maxLines: 1)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget revenueForecast() {
|
||||
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,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.bodyMedium("Revenue Forecast", fontWeight: 600),
|
||||
PopupMenuButton(
|
||||
offset: Offset(0, 20),
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
shape: OutlineInputBorder(borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none),
|
||||
itemBuilder: (BuildContext context) => [
|
||||
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Download", fontWeight: 600)),
|
||||
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Import", fontWeight: 600)),
|
||||
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Export", fontWeight: 600)),
|
||||
],
|
||||
child: Icon(LucideIcons.ellipsis_vertical, size: 20),
|
||||
)
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
SfCartesianChart(
|
||||
plotAreaBorderWidth: 0,
|
||||
primaryXAxis: const CategoryAxis(
|
||||
majorGridLines: MajorGridLines(width: 0),
|
||||
),
|
||||
margin: MySpacing.zero,
|
||||
primaryYAxis: const NumericAxis(maximum: 20, minimum: 0, interval: 4, axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(size: 0)),
|
||||
series: [
|
||||
ColumnSeries<ChartSampleData, String>(
|
||||
width: 0.8,
|
||||
spacing: 0.2,
|
||||
dataSource: controller.chartData,
|
||||
color: contentTheme.primary,
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.y,
|
||||
name: 'Sales Revenue'),
|
||||
ColumnSeries<ChartSampleData, String>(
|
||||
dataSource: controller.chartData,
|
||||
width: 0.8,
|
||||
spacing: 0.2,
|
||||
color: contentTheme.secondary,
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.secondSeriesYValue,
|
||||
name: 'Product Cost'),
|
||||
],
|
||||
legend: Legend(isVisible: true, position: LegendPosition.bottom),
|
||||
tooltipBehavior: controller.tooltipBehavior,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget topDeals() {
|
||||
Widget topDealsWidget(String image, String name, String email, String price) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
paddingAll: 0,
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: Image.asset(image, fit: BoxFit.cover),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(name, fontWeight: 600),
|
||||
MyText.labelMedium(email, fontWeight: 600, muted: true, maxLines: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyText.labelMedium(price, fontWeight: 600),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.bodyMedium("Top Deals", fontWeight: 600),
|
||||
PopupMenuButton(
|
||||
offset: Offset(0, 20),
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
shape: OutlineInputBorder(borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none),
|
||||
itemBuilder: (BuildContext context) => [
|
||||
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Week", fontWeight: 600)),
|
||||
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Month", fontWeight: 600)),
|
||||
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Year", fontWeight: 600)),
|
||||
],
|
||||
child: Icon(LucideIcons.ellipsis_vertical, size: 20),
|
||||
)
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
topDealsWidget(Images.avatars[0], "Christopher", "christopher123@gmail.com", "\$14,541"),
|
||||
MySpacing.height(24),
|
||||
topDealsWidget(Images.avatars[1], "Edward", "edward15@gmail.com", "\$21,548"),
|
||||
MySpacing.height(24),
|
||||
topDealsWidget(Images.avatars[2], "Michael", "michael@gmail.com", "\$13,645"),
|
||||
MySpacing.height(24),
|
||||
topDealsWidget(Images.avatars[3], "Sebastian", "sebastian@gmail.com", "\$51,254"),
|
||||
MySpacing.height(24),
|
||||
topDealsWidget(Images.avatars[4], "Nicholas", "nicholas@gmail.com", "\$15,487"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget dealSource() {
|
||||
Widget dealSourceWidget(String image, String title, String subtitle, String totalLeads) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
height: 32,
|
||||
width: 32,
|
||||
paddingAll: 0,
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyText.labelSmall('$totalLeads Leads', fontWeight: 600),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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("Deal Source", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/uxerflow_logo.png", "Website", "userflow.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/dribbble-logo.png", "Dribbble", "dribbble.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/facebook-logo.png", "Facebook", "facebook.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/instagram-logo.png", "Instagram", "instagram.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/LinkedIn-logo.png", "Linkedin", "linkedin.com", "50"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget leadResponse() {
|
||||
Widget leadData(String image, name, processRate, double progress) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
paddingAll: 0,
|
||||
height: 32,
|
||||
width: 32,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
child: Image.asset(image, fit: BoxFit.cover),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: MyText.labelLarge(name, fontWeight: 600, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
MyText.labelSmall(processRate, fontWeight: 600, overflow: TextOverflow.ellipsis),
|
||||
],
|
||||
),
|
||||
MySpacing.height(8),
|
||||
MyProgressBar(
|
||||
width: 300,
|
||||
height: 7,
|
||||
progress: progress,
|
||||
radius: 8,
|
||||
activeColor: contentTheme.primary,
|
||||
inactiveColor: contentTheme.primary.withAlpha(32),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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("Lead Response", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
leadData(Images.avatars[0], "Amelia Thomson", "1.3", .3),
|
||||
MySpacing.height(24),
|
||||
leadData(Images.avatars[1], "Ian Ferguson", "1.4", .4),
|
||||
MySpacing.height(24),
|
||||
leadData(Images.avatars[2], "Simon Ross", "2", .8),
|
||||
MySpacing.height(24),
|
||||
leadData(Images.avatars[3], "Heather", "1.5", .5),
|
||||
MySpacing.height(24),
|
||||
leadData(Images.avatars[4], "Madeleine Simpson", "1.9", .7),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget openDeals() {
|
||||
Widget dealsData(String image, dealsType, dealsDate, price) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
paddingAll: 0,
|
||||
height: 46,
|
||||
width: 46,
|
||||
borderRadiusAll: 8,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
child: Image.asset(image, fit: BoxFit.cover),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 32,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.bodyMedium(dealsType, fontWeight: 600, overflow: TextOverflow.ellipsis),
|
||||
MyText.labelSmall("Closing deal date ${dealsDate}", fontWeight: 600, overflow: TextOverflow.ellipsis)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
MyText.labelMedium("\$${numberFormatter(price)}", fontWeight: 600, color: contentTheme.primary),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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("Open Deals", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
dealsData(Images.avatars[1], "SASS app workflow", "26 Jan", "15478"),
|
||||
MySpacing.height(24),
|
||||
dealsData(Images.avatars[0], "Create new component", "8 Fab", "54791"),
|
||||
MySpacing.height(24),
|
||||
dealsData(Images.avatars[3], "New Email Design Template", "16 March", "54876"),
|
||||
MySpacing.height(24),
|
||||
dealsData(Images.avatars[4], "React Developer", "12 Fab", "1564"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget leadSource() {
|
||||
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("Lead Source", fontWeight: 600),
|
||||
SizedBox(
|
||||
height: 280,
|
||||
child: SfCircularChart(
|
||||
series: [
|
||||
PieSeries<ChartSampleData, String>(
|
||||
explode: true,
|
||||
explodeIndex: 0,
|
||||
dataSource: <ChartSampleData>[
|
||||
ChartSampleData(x: 'Prospecting', y: 13, text: 'Prospecting \n 13%'),
|
||||
ChartSampleData(x: 'Negotiation', y: 24, text: 'Negotiation \n 24%'),
|
||||
ChartSampleData(x: 'Proposal', y: 25, text: 'Proposal \n 25%'),
|
||||
ChartSampleData(x: 'Qualification', y: 38, text: 'Qualification \n 38%'),
|
||||
],
|
||||
xValueMapper: (ChartSampleData data, _) => data.x as String,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
dataLabelMapper: (ChartSampleData data, _) => data.text,
|
||||
dataLabelSettings: DataLabelSettings(isVisible: true)),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget leadReport() {
|
||||
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("Lead Report", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
if (controller.leadReport.isNotEmpty)
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: DataTable(
|
||||
sortAscending: true,
|
||||
columnSpacing: 80,
|
||||
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('Lead', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Company Name', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Phone Number', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Status', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Location', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Date', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Amount', color: contentTheme.primary)),
|
||||
],
|
||||
rows: controller.leadReport
|
||||
.mapIndexed((index, data) => DataRow(cells: [
|
||||
DataCell(MyText.bodyMedium("#${data.id}", fontWeight: 600)),
|
||||
DataCell(Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
MyContainer(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
child: Image.asset(Images.avatars[index % Images.avatars.length], fit: BoxFit.cover),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(data.firstName, fontWeight: 600),
|
||||
MyText.labelMedium(data.email),
|
||||
],
|
||||
)
|
||||
],
|
||||
)),
|
||||
DataCell(MyText.bodyMedium(data.companyName, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.phoneNumber, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.status, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.location, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium("${Utils.getDateStringFromDateTime(data.date)}", fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium("\$${data.amount}", fontWeight: 600)),
|
||||
]))
|
||||
.toList()),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
@ -1,533 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:marco/controller/dashboard/crypto_controller.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/model/chart_model.dart';
|
||||
import 'package:marco/view/layouts/layout.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class CryptoScreen extends StatefulWidget {
|
||||
const CryptoScreen({super.key});
|
||||
|
||||
@override
|
||||
State<CryptoScreen> createState() => _CryptoScreenState();
|
||||
}
|
||||
|
||||
class _CryptoScreenState extends State<CryptoScreen> with UIMixin {
|
||||
CryptoController controller = Get.put(CryptoController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: GetBuilder(
|
||||
init: controller,
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Crypto", fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Crypto', active: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats('assets/coin/ethereum.png', 'ETH', 'Ethereum', '3.754120', '4.2')),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats('assets/coin/bitcoin.png', 'BTC', 'Bitcoin', '12.125620', '-1.3')),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats('assets/coin/chainlink.png', 'LINK', 'Chainlink', '15.874562', '0.8')),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats('assets/coin/dogecoin.png', 'DOGE', 'Dogecoin', '8.674930', '5.0')),
|
||||
MyFlexItem(sizes: 'lg-6 md-6', child: marketOverview()),
|
||||
MyFlexItem(sizes: 'lg-6 md-6', child: cryptoStatistics()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: accountStats("Total Balance", "\$12000.50", LucideIcons.credit_card, contentTheme.success)),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: accountStats("Total Investment", "\$8000.75", LucideIcons.trending_up, contentTheme.info)),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: accountStats("Total Change", "\$500.25", LucideIcons.refresh_cw, contentTheme.warning)),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: accountStats("Day Change", "\$20.30", LucideIcons.circle_arrow_up, contentTheme.danger)),
|
||||
MyFlexItem(sizes: 'lg-4', child: recentActivity()),
|
||||
MyFlexItem(sizes: 'lg-4', child: topPerformers()),
|
||||
MyFlexItem(sizes: 'lg-4', child: transactionHistory()),
|
||||
MyFlexItem(child: activeOverallGrowth()),
|
||||
],
|
||||
)),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget stats(String coinImage, String coinShortName, String coinName, String count, String change) {
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha: .2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
height: 170,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
child: Image.asset(coinImage, fit: BoxFit.cover),
|
||||
),
|
||||
MySpacing.width(20),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodySmall(coinShortName, xMuted: true),
|
||||
MyText.bodySmall(coinName),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
MyText.titleLarge('$count $coinShortName'),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(change.startsWith("-") ? LucideIcons.trending_down : LucideIcons.trending_up,
|
||||
size: 16, color: change.startsWith("-") ? theme.colorScheme.error : theme.colorScheme.primary),
|
||||
MySpacing.width(8),
|
||||
MyText.bodySmall("${change.startsWith("-") ? '' : '+'}${change}%",
|
||||
color: change.startsWith("-") ? theme.colorScheme.error : theme.colorScheme.primary),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget marketOverview() {
|
||||
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(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.bodyMedium("Market Overview", fontWeight: 600),
|
||||
PopupMenuButton(
|
||||
onSelected: controller.onSelectIntervalType,
|
||||
itemBuilder: (BuildContext context) {
|
||||
return DateTimeIntervalType.values.map((behavior) {
|
||||
return PopupMenuItem(
|
||||
value: behavior,
|
||||
height: 32,
|
||||
child: MyText.bodySmall(
|
||||
behavior.toString().split('.').last.capitalize.toString(),
|
||||
color: theme.colorScheme.onSurface,
|
||||
fontWeight: 600,
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
color: theme.cardTheme.color,
|
||||
child: MyContainer.bordered(
|
||||
padding: MySpacing.xy(8, 4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
MyText.labelSmall(controller.intervalType.toString().split('.').last.capitalize.toString(), color: theme.colorScheme.onSurface),
|
||||
Icon(LucideIcons.chevron_down, size: 16, color: theme.colorScheme.onSurface)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
SfCartesianChart(
|
||||
plotAreaBorderWidth: 0,
|
||||
primaryXAxis: DateTimeAxis(
|
||||
autoScrollingMode: AutoScrollingMode.start,
|
||||
dateFormat: DateFormat.MMM(),
|
||||
intervalType: controller.intervalType,
|
||||
minimum: DateTime(2016),
|
||||
maximum: DateTime(2016, 10),
|
||||
majorGridLines: const MajorGridLines(width: 0)),
|
||||
primaryYAxis: const NumericAxis(minimum: 80, maximum: 120, labelFormat: r'${value}', axisLine: AxisLine(width: 0)),
|
||||
series: _getCandleSeries(),
|
||||
trackballBehavior: controller.trackballBehavior,
|
||||
tooltipBehavior: TooltipBehavior(),
|
||||
zoomPanBehavior: ZoomPanBehavior(enableMouseWheelZooming: true, enablePinching: true, enablePanning: true, enableDoubleTapZooming: true)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<CandleSeries<ChartSampleData, DateTime>> _getCandleSeries() {
|
||||
return <CandleSeries<ChartSampleData, DateTime>>[
|
||||
CandleSeries<ChartSampleData, DateTime>(
|
||||
enableSolidCandles: controller.enableSolidCandle,
|
||||
dataSource: <ChartSampleData>[
|
||||
ChartSampleData(x: DateTime(2016, 01, 11), open: 98.97, high: 101.19, low: 95.36, close: 97.13),
|
||||
ChartSampleData(x: DateTime(2016, 01, 18), open: 98.41, high: 101.46, low: 93.42, close: 101.42),
|
||||
ChartSampleData(x: DateTime(2016, 01, 25), open: 101.52, high: 101.53, low: 92.39, close: 97.34),
|
||||
ChartSampleData(x: DateTime(2016, 02), open: 96.47, high: 97.33, low: 93.69, close: 94.02),
|
||||
ChartSampleData(x: DateTime(2016, 02, 08), open: 93.13, high: 96.35, low: 92.59, close: 93.99),
|
||||
ChartSampleData(x: DateTime(2016, 02, 15), open: 95.02, high: 98.89, low: 94.61, close: 96.04),
|
||||
ChartSampleData(x: DateTime(2016, 02, 22), open: 96.31, high: 98.0237, low: 93.32, close: 96.91),
|
||||
ChartSampleData(x: DateTime(2016, 02, 29), open: 96.86, high: 103.75, low: 96.65, close: 103.01),
|
||||
ChartSampleData(x: DateTime(2016, 03, 07), open: 102.39, high: 102.83, low: 100.15, close: 102.26),
|
||||
ChartSampleData(x: DateTime(2016, 03, 14), open: 106.5, high: 106.5, low: 106.5, close: 106.5),
|
||||
ChartSampleData(x: DateTime(2016, 03, 21), open: 105.93, high: 107.65, low: 104.89, close: 105.67),
|
||||
ChartSampleData(x: DateTime(2016, 03, 28), open: 106, high: 110.42, low: 104.88, close: 109.99),
|
||||
ChartSampleData(x: DateTime(2016, 04, 04), open: 110.42, high: 112.19, low: 108.121, close: 108.66),
|
||||
ChartSampleData(x: DateTime(2016, 04, 11), open: 108.97, high: 112.39, low: 108.66, close: 109.85),
|
||||
ChartSampleData(x: DateTime(2016, 04, 18), open: 108.89, high: 108.95, low: 104.62, close: 105.68),
|
||||
ChartSampleData(x: DateTime(2016, 04, 25), open: 105, high: 105.65, low: 92.51, close: 93.74),
|
||||
ChartSampleData(x: DateTime(2016, 05, 02), open: 93.965, high: 95.9, low: 91.85, close: 92.72),
|
||||
ChartSampleData(x: DateTime(2016, 05, 09), open: 93, high: 93.77, low: 89.47, close: 90.52),
|
||||
ChartSampleData(x: DateTime(2016, 05, 16), open: 92.39, high: 95.43, low: 91.65, close: 95.22),
|
||||
ChartSampleData(x: DateTime(2016, 05, 23), open: 95.87, high: 100.73, low: 95.67, close: 100.35),
|
||||
ChartSampleData(x: DateTime(2016, 05, 30), open: 99.6, high: 100.4, low: 96.63, close: 97.92),
|
||||
ChartSampleData(x: DateTime(2016, 06, 06), open: 97.99, high: 101.89, low: 97.55, close: 98.83),
|
||||
ChartSampleData(x: DateTime(2016, 06, 13), open: 98.69, high: 99.12, low: 95.3, close: 95.33),
|
||||
ChartSampleData(x: DateTime(2016, 06, 20), open: 96, high: 96.89, low: 92.65, close: 93.4),
|
||||
ChartSampleData(x: DateTime(2016, 06, 27), open: 93, high: 96.465, low: 91.5, close: 95.89),
|
||||
ChartSampleData(x: DateTime(2016, 07, 04), open: 95.39, high: 96.89, low: 94.37, close: 96.68),
|
||||
ChartSampleData(x: DateTime(2016, 07, 11), open: 96.75, high: 99.3, low: 96.73, close: 98.78),
|
||||
ChartSampleData(x: DateTime(2016, 07, 18), open: 98.7, high: 101, low: 98.31, close: 98.66),
|
||||
ChartSampleData(x: DateTime(2016, 07, 25), open: 98.25, high: 104.55, low: 96.42, close: 104.21),
|
||||
ChartSampleData(x: DateTime(2016, 08), open: 104.41, high: 107.65, low: 104, close: 107.48),
|
||||
ChartSampleData(x: DateTime(2016, 08, 08), open: 107.52, high: 108.94, low: 107.16, close: 108.18),
|
||||
ChartSampleData(x: DateTime(2016, 08, 15), open: 108.14, high: 110.23, low: 108.08, close: 109.36),
|
||||
ChartSampleData(x: DateTime(2016, 08, 22), open: 108.86, high: 109.32, low: 106.31, close: 106.94),
|
||||
ChartSampleData(x: DateTime(2016, 08, 29), open: 109.74, high: 109.74, low: 109.74, close: 109.74),
|
||||
ChartSampleData(x: DateTime(2016, 09, 05), open: 107.9, high: 108.76, low: 103.13, close: 103.13),
|
||||
ChartSampleData(x: DateTime(2016, 09, 12), open: 102.65, high: 116.13, low: 102.53, close: 114.92),
|
||||
ChartSampleData(x: DateTime(2016, 09, 19), open: 115.19, high: 116.18, low: 111.55, close: 112.71),
|
||||
ChartSampleData(x: DateTime(2016, 09, 26), open: 111.64, high: 114.64, low: 111.55, close: 113.05),
|
||||
],
|
||||
showIndicationForSameValues: true,
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as DateTime,
|
||||
lowValueMapper: (ChartSampleData sales, _) => sales.low,
|
||||
highValueMapper: (ChartSampleData sales, _) => sales.high,
|
||||
openValueMapper: (ChartSampleData sales, _) => sales.open,
|
||||
closeValueMapper: (ChartSampleData sales, _) => sales.close,
|
||||
spacing: 0.2,
|
||||
width: 0.8,
|
||||
borderRadius: BorderRadius.all(Radius.circular(4)),
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
Widget cryptoStatistics() {
|
||||
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("Crypto Statistics", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SizedBox(
|
||||
height: 329,
|
||||
child: SfCartesianChart(
|
||||
margin: MySpacing.zero,
|
||||
plotAreaBorderWidth: 0,
|
||||
legend: Legend(isVisible: false, position: LegendPosition.bottom),
|
||||
primaryXAxis: const CategoryAxis(majorGridLines: MajorGridLines(width: 0), labelPlacement: LabelPlacement.onTicks),
|
||||
primaryYAxis: const NumericAxis(
|
||||
axisLine: AxisLine(width: 0), edgeLabelPlacement: EdgeLabelPlacement.shift, labelFormat: '{value}', majorTickLines: MajorTickLines(size: 0)),
|
||||
series: [
|
||||
SplineSeries<ChartSampleData, String>(
|
||||
dataSource: controller.chartData,
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.y,
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
color: contentTheme.success,
|
||||
name: 'High'),
|
||||
SplineSeries<ChartSampleData, String>(
|
||||
dataSource: controller.chartData,
|
||||
name: 'Low',
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.secondSeriesYValue,
|
||||
)
|
||||
],
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget accountStats(String title, String data, IconData icon, 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: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
color: color,
|
||||
child: Icon(icon, color: contentTheme.light),
|
||||
),
|
||||
MySpacing.width(20),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(title, fontWeight: 600, maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||
MySpacing.height(4),
|
||||
MyText.titleLarge(data, fontWeight: 600, maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget recentActivity() {
|
||||
Widget recentActivityWidget(String coinName, String transactionType, String price, String transactionUpDown, IconData icon) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyContainer.roundBordered(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
child: Icon(icon, size: 20),
|
||||
),
|
||||
MySpacing.width(20),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(coinName, fontWeight: 600),
|
||||
MySpacing.height(4),
|
||||
MyText.bodySmall(transactionType, fontWeight: 600, muted: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
MyText.bodyMedium(price, fontWeight: 600),
|
||||
MySpacing.height(4),
|
||||
MyText.bodySmall("${transactionUpDown.startsWith('-') ? '' : '+'}${transactionUpDown}",
|
||||
fontWeight: 600, muted: true, color: transactionUpDown.startsWith('-') ? contentTheme.danger : contentTheme.success),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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 Activity", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget("Bought Ethereum", "MasterCard ***8", "+0.215 BTC", "4320.22 USD", LucideIcons.circle_plus),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget("Sold Bitcoin", "PayPal Account", "-0.012 BTC", "-231.56 USD", LucideIcons.circle_minus),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget("Transferred Litecoin", "Visa Debit Card ***5", "-2.23 LTC", "-150.99 USD", LucideIcons.arrow_right),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget("Bought Cardano", "Bitcoin Wallet", "+500 ADA", "2,650.32 USD", LucideIcons.circle_plus),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget("Sold Dogecoin", "Bank Transfer", "-10,000 DOGE", "-756.11 USD", LucideIcons.circle_minus),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget topPerformers() {
|
||||
Widget topPerformersWidget(String coinName, String shortName, String price, String image) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
child: Image.asset(image),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(coinName, fontWeight: 600),
|
||||
MySpacing.height(4),
|
||||
MyText.bodySmall(shortName, fontWeight: 600, muted: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyText.bodyMedium(price, fontWeight: 600),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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("Top Performance", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
topPerformersWidget("Bitcoin", "BTC", "\$45,000", "assets/coin/bitcoin.png"),
|
||||
MySpacing.height(24),
|
||||
topPerformersWidget("Chainlink", "LINK", "\$25.50", "assets/coin/chainlink.png"),
|
||||
MySpacing.height(24),
|
||||
topPerformersWidget("Dogecoin", "DOGE", "\$0.25", "assets/coin/dogecoin.png"),
|
||||
MySpacing.height(24),
|
||||
topPerformersWidget("Ethereum", "ETH", "\$3,200", "assets/coin/ethereum.png"),
|
||||
MySpacing.height(24),
|
||||
topPerformersWidget("Polkadot", "DOT", "\$12.75", "assets/coin/polkadot.png"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget transactionHistory() {
|
||||
Widget transactionHistoryWidget(String coinName, String date, String buyPrice, IconData icon) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
color: contentTheme.primary.withValues(alpha: 0.2),
|
||||
child: Icon(icon, color: contentTheme.primary),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(coinName, fontWeight: 600),
|
||||
MySpacing.height(4),
|
||||
MyText.bodySmall(date, fontWeight: 600, muted: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyText.bodyMedium(buyPrice, fontWeight: 600),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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("Transaction History", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
transactionHistoryWidget("Sent BTC", "12 November 2024 2:15 PM", "0.045 BTC", LucideIcons.arrow_up),
|
||||
MySpacing.height(24),
|
||||
transactionHistoryWidget("Received ETH", "11 November 2024 9:30 AM", "2.5 ETH", LucideIcons.arrow_down),
|
||||
MySpacing.height(24),
|
||||
transactionHistoryWidget("Sent LTC", "10 November 2024 5:20 PM", "1.2 LTC", LucideIcons.arrow_up),
|
||||
MySpacing.height(24),
|
||||
transactionHistoryWidget("Received ADA", "9 November 2024 11:50 PM", "500 ADA", LucideIcons.arrow_down),
|
||||
MySpacing.height(24),
|
||||
transactionHistoryWidget("Sent DOGE", "8 November 2024 1:10 PM", "10,000 DOGE", LucideIcons.arrow_up),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget activeOverallGrowth() {
|
||||
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("Active Overall Growth", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: DataTable(
|
||||
sortAscending: true,
|
||||
columnSpacing: 170,
|
||||
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('Type', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Assets', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Date', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('IP Address', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Status', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Amount', color: contentTheme.primary)),
|
||||
],
|
||||
rows: controller.coinGrowth
|
||||
.mapIndexed((index, data) => DataRow(cells: [
|
||||
DataCell(MyText.labelMedium('Exchange')),
|
||||
DataCell(MyText.labelMedium('${data.asset}')),
|
||||
DataCell(MyText.labelMedium('${Utils.getDateTimeStringFromDateTime(data.date)}')),
|
||||
DataCell(MyText.labelMedium('${data.ipAddress}')),
|
||||
DataCell(MyContainer(
|
||||
paddingAll: 4,
|
||||
color: data.status == 'Success' ? contentTheme.success : contentTheme.danger,
|
||||
child: MyText.labelMedium('${data.status}', color: data.status == 'Success' ? contentTheme.onSuccess : contentTheme.onDanger))),
|
||||
DataCell(MyText.labelMedium('\$${data.amount}')),
|
||||
]))
|
||||
.toList()),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,437 +0,0 @@
|
||||
import 'package:flutter/material.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/widgets/my_breadcrumb.dart';
|
||||
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex_item.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/permission_controller.dart';
|
||||
import 'package:marco/helpers/widgets/my_loading_component.dart';
|
||||
import 'package:marco/helpers/widgets/my_refresh_wrapper.dart';
|
||||
import 'package:marco/model/my_paginated_table.dart';
|
||||
import 'package:marco/controller/dashboard/daily_task_controller.dart';
|
||||
import 'package:marco/helpers/widgets/avatar.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:marco/helpers/widgets/my_team_model_sheet.dart';
|
||||
class DailyTaskScreen extends StatefulWidget {
|
||||
const DailyTaskScreen({super.key});
|
||||
|
||||
@override
|
||||
State<DailyTaskScreen> createState() => _DailyTaskScreenState();
|
||||
}
|
||||
|
||||
class _DailyTaskScreenState extends State<DailyTaskScreen> with UIMixin {
|
||||
final DailyTaskController dailyTaskController =
|
||||
Get.put(DailyTaskController());
|
||||
final PermissionController permissionController =
|
||||
Get.put(PermissionController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: Obx(() {
|
||||
return LoadingComponent(
|
||||
isLoading: dailyTaskController.isLoading.value,
|
||||
loadingText: 'Loading Tasks...',
|
||||
child: GetBuilder<DailyTaskController>(
|
||||
init: dailyTaskController,
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(),
|
||||
MySpacing.height(flexSpacing),
|
||||
_buildBreadcrumb(),
|
||||
MySpacing.height(flexSpacing),
|
||||
_buildFilterSection(),
|
||||
MySpacing.height(flexSpacing),
|
||||
_buildTaskList(),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
return Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: MyText.titleMedium(
|
||||
"Daily Progress Report",
|
||||
fontSize: 18,
|
||||
fontWeight: 600,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBreadcrumb() {
|
||||
return Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Daily Progress Report', active: true),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFilterSection() {
|
||||
return Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildProjectFilter(),
|
||||
const SizedBox(width: 10),
|
||||
_buildDateRangeButton(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProjectFilter() {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.black, width: 1.5),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: PopupMenuButton<String>(
|
||||
onSelected: (String value) async {
|
||||
if (value.isNotEmpty) {
|
||||
dailyTaskController.selectedProjectId = value;
|
||||
await dailyTaskController.fetchTaskData(value);
|
||||
}
|
||||
dailyTaskController.update();
|
||||
},
|
||||
itemBuilder: (BuildContext context) {
|
||||
return dailyTaskController.projects
|
||||
.map<PopupMenuItem<String>>((project) {
|
||||
return PopupMenuItem<String>(
|
||||
value: project.id,
|
||||
child: MyText.bodySmall(project.name),
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
offset: const Offset(0, 40),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
dailyTaskController.selectedProjectId == null
|
||||
? dailyTaskController.projects.isNotEmpty
|
||||
? dailyTaskController.projects.first.name
|
||||
: 'No Tasks'
|
||||
: dailyTaskController.projects
|
||||
.firstWhere((project) =>
|
||||
project.id ==
|
||||
dailyTaskController.selectedProjectId)
|
||||
.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.arrow_drop_down),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Widget _buildDateRangeButton() {
|
||||
String dateRangeText;
|
||||
if (dailyTaskController.startDateTask != null &&
|
||||
dailyTaskController.endDateTask != null) {
|
||||
dateRangeText =
|
||||
'${DateFormat('dd-MM-yyyy').format(dailyTaskController.startDateTask!)}'
|
||||
' to '
|
||||
'${DateFormat('dd-MM-yyyy').format(dailyTaskController.endDateTask!)}';
|
||||
} else {
|
||||
dateRangeText = "Select Date Range";
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextButton.icon(
|
||||
icon: const Icon(Icons.date_range),
|
||||
label: Text(dateRangeText),
|
||||
onPressed: () => dailyTaskController.selectDateRangeForTaskData(
|
||||
context,
|
||||
dailyTaskController,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTaskList() {
|
||||
return Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(sizes: 'lg-6', child: employeeListTab()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget employeeListTab() {
|
||||
if (dailyTaskController.dailyTasks.isEmpty) {
|
||||
return Center(
|
||||
child: MyText.bodySmall("No Tasks Assigned to This Project",
|
||||
fontWeight: 600),
|
||||
);
|
||||
}
|
||||
Map<String, List<dynamic>> groupedTasks = {};
|
||||
for (var task in dailyTaskController.dailyTasks) {
|
||||
String dateKey =
|
||||
DateFormat('dd-MM-yyyy').format(task.assignmentDate);
|
||||
groupedTasks.putIfAbsent(dateKey, () => []).add(task);
|
||||
}
|
||||
|
||||
// Sort dates descending (latest first)
|
||||
final sortedEntries = groupedTasks.entries.toList()
|
||||
..sort((a, b) => DateFormat('dd-MM-yyyy')
|
||||
.parse(b.key)
|
||||
.compareTo(DateFormat('dd-MM-yyyy').parse(a.key)));
|
||||
|
||||
// Flatten grouped data into one list with optional visual separators
|
||||
List<DataRow> allRows = [];
|
||||
|
||||
for (var entry in sortedEntries) {
|
||||
allRows.add(
|
||||
DataRow(
|
||||
color: WidgetStateProperty.all(Colors.grey.shade200),
|
||||
cells: [
|
||||
DataCell(MyText.titleSmall('Date: ${entry.key}')),
|
||||
DataCell(MyText.titleSmall('')),
|
||||
DataCell(MyText.titleSmall('')),
|
||||
DataCell(MyText.titleSmall('')),
|
||||
DataCell(MyText.titleSmall('')),
|
||||
DataCell(MyText.titleSmall('')),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
allRows.addAll(entry.value.map((task) => _buildRow(task)));
|
||||
}
|
||||
|
||||
return MyRefreshableContent(
|
||||
onRefresh: () async {
|
||||
if (dailyTaskController.selectedProjectId != null) {
|
||||
await dailyTaskController
|
||||
.fetchTaskData(dailyTaskController.selectedProjectId!);
|
||||
}
|
||||
},
|
||||
child: MyPaginatedTable(
|
||||
columns: _buildColumns(),
|
||||
rows: allRows,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<DataColumn> _buildColumns() {
|
||||
return [
|
||||
DataColumn(
|
||||
label: MyText.labelLarge('Activity', color: contentTheme.primary)),
|
||||
DataColumn(
|
||||
label: MyText.labelLarge('Assigned', color: contentTheme.primary)),
|
||||
DataColumn(
|
||||
label: MyText.labelLarge('Completed', color: contentTheme.primary)),
|
||||
DataColumn(
|
||||
label: MyText.labelLarge('Assigned On', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Team', color: contentTheme.primary)),
|
||||
DataColumn(
|
||||
label: MyText.labelLarge('Actions', color: contentTheme.primary)),
|
||||
];
|
||||
}
|
||||
|
||||
DataRow _buildRow(dynamic task) {
|
||||
final workItem = task.workItem;
|
||||
final location = [
|
||||
workItem?.workArea?.floor?.building?.name,
|
||||
workItem?.workArea?.floor?.floorName,
|
||||
workItem?.workArea?.areaName
|
||||
].where((e) => e != null && e.isNotEmpty).join(' > ');
|
||||
|
||||
return DataRow(cells: [
|
||||
DataCell(
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
MyText.bodyMedium(workItem?.activityMaster?.activityName ?? 'N/A',
|
||||
fontWeight: 600),
|
||||
SizedBox(height: 2),
|
||||
MyText.bodySmall(location, color: Colors.grey),
|
||||
],
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
MyText.bodyMedium(
|
||||
'${task.plannedTask ?? "NA"} / '
|
||||
'${(workItem?.plannedWork != null && workItem?.completedWork != null) ? (workItem!.plannedWork! - workItem.completedWork!) : "NA"}',
|
||||
),
|
||||
),
|
||||
DataCell(MyText.bodyMedium(task.completedTask.toString())),
|
||||
DataCell(MyText.bodyMedium(DateFormat('dd-MM-yyyy')
|
||||
.format(DateTime.parse(task.assignmentDate)))),
|
||||
DataCell(_buildTeamCell(task)),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
final activityName =
|
||||
task.workItem?.activityMaster?.activityName ?? 'N/A';
|
||||
final assigned = '${task.plannedTask ?? "NA"} / '
|
||||
'${(task.workItem?.plannedWork != null && task.workItem?.completedWork != null) ? (task.workItem!.plannedWork! - task.workItem.completedWork!) : "NA"}';
|
||||
final assignedBy =
|
||||
"${task.assignedBy.firstName} ${task.assignedBy.lastName ?? ''}";
|
||||
final completed = task.completedTask.toString();
|
||||
final assignedOn = DateFormat('dd-MM-yyyy')
|
||||
.format(DateTime.parse(task.assignmentDate));
|
||||
final taskId = task.id;
|
||||
final location = [
|
||||
task.workItem?.workArea?.floor?.building?.name,
|
||||
task.workItem?.workArea?.floor?.floorName,
|
||||
task.workItem?.workArea?.areaName
|
||||
].where((e) => e != null && e.isNotEmpty).join(' > ');
|
||||
|
||||
final teamMembers =
|
||||
task.teamMembers.map((member) => member.firstName).toList();
|
||||
|
||||
// Navigate with detailed values
|
||||
Get.toNamed(
|
||||
'/daily-task/report-task',
|
||||
arguments: {
|
||||
'activity': activityName,
|
||||
'assigned': assigned,
|
||||
'taskId': taskId,
|
||||
'assignedBy': assignedBy,
|
||||
'completed': completed,
|
||||
'assignedOn': assignedOn,
|
||||
'location': location,
|
||||
'teamSize': task.teamMembers.length,
|
||||
'teamMembers': teamMembers,
|
||||
},
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||
minimumSize: const Size(60, 20),
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
),
|
||||
child: const Text("Report"),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
final activityName =
|
||||
task.workItem?.activityMaster?.activityName ?? 'N/A';
|
||||
final assigned = '${task.plannedTask ?? "NA"} / '
|
||||
'${(task.workItem?.plannedWork != null && task.workItem?.completedWork != null) ? (task.workItem!.plannedWork! - task.workItem.completedWork!) : "NA"}';
|
||||
final plannedWork = '${(task.plannedTask.toString())}';
|
||||
final assignedBy =
|
||||
"${task.assignedBy.firstName} ${task.assignedBy.lastName ?? ''}";
|
||||
final completedWork = '${(task.completedTask.toString())}';
|
||||
final assignedOn = DateFormat('dd-MM-yyyy')
|
||||
.format(DateTime.parse(task.assignmentDate));
|
||||
final taskId = task.id;
|
||||
final location = [
|
||||
task.workItem?.workArea?.floor?.building?.name,
|
||||
task.workItem?.workArea?.floor?.floorName,
|
||||
task.workItem?.workArea?.areaName
|
||||
].where((e) => e != null && e.isNotEmpty).join(' > ');
|
||||
|
||||
final teamMembers =
|
||||
task.teamMembers.map((member) => member.firstName).toList();
|
||||
final taskComments = task.comments
|
||||
.map((comment) => comment.comment ?? 'No Content')
|
||||
.toList();
|
||||
Get.toNamed(
|
||||
'/daily-task/comment-task',
|
||||
arguments: {
|
||||
'activity': activityName,
|
||||
'assigned': assigned,
|
||||
'taskId': taskId,
|
||||
'assignedBy': assignedBy,
|
||||
'completedWork': completedWork,
|
||||
'plannedWork': plannedWork,
|
||||
'assignedOn': assignedOn,
|
||||
'location': location,
|
||||
'teamSize': task.teamMembers.length,
|
||||
'teamMembers': teamMembers,
|
||||
'taskComments': taskComments
|
||||
},
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
|
||||
minimumSize: const Size(60, 20),
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
),
|
||||
child: const Text("Comment"),
|
||||
),
|
||||
],
|
||||
)),
|
||||
]);
|
||||
}
|
||||
|
||||
Widget _buildTeamCell(dynamic task) {
|
||||
return GestureDetector(
|
||||
onTap: () => TeamBottomSheet.show(
|
||||
context: context,
|
||||
teamMembers: task.teamMembers,
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 32,
|
||||
width: 100,
|
||||
child: Stack(
|
||||
children: [
|
||||
for (int i = 0; i < task.teamMembers.length.clamp(0, 3); i++)
|
||||
_buildAvatar(task.teamMembers[i], i * 24.0),
|
||||
if (task.teamMembers.length > 3)
|
||||
_buildExtraMembersIndicator(task.teamMembers.length - 3, 48.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAvatar(dynamic member, double leftPosition) {
|
||||
return Positioned(
|
||||
left: leftPosition,
|
||||
child: Tooltip(
|
||||
message: member.firstName,
|
||||
child: Avatar(firstName: member.firstName, lastName: '', size: 32),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildExtraMembersIndicator(int extraMembers, double leftPosition) {
|
||||
return Positioned(
|
||||
left: leftPosition,
|
||||
child: CircleAvatar(
|
||||
radius: 16,
|
||||
backgroundColor: Colors.grey.shade300,
|
||||
child: MyText.bodyMedium('+$extraMembers',
|
||||
style: const TextStyle(fontSize: 12, color: Colors.black87)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,528 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:marco/controller/dashboard/ecommerce_controller.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';
|
||||
|
||||
class EcommerceScreen extends StatefulWidget {
|
||||
const EcommerceScreen({super.key});
|
||||
|
||||
@override
|
||||
State<EcommerceScreen> createState() => _EcommerceScreenState();
|
||||
}
|
||||
|
||||
class _EcommerceScreenState extends State<EcommerceScreen> with UIMixin {
|
||||
EcommerceController controller = Get.put(EcommerceController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: GetBuilder(
|
||||
init: controller,
|
||||
tag: 'ecommerce_dashboard_controller',
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Ecommerce", fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Ecommerce', active: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(sizes: 'lg-6 ', child: stats()),
|
||||
MyFlexItem(sizes: "lg-6", child: responseTimeByLocation()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6', child: topCustomer()),
|
||||
MyFlexItem(sizes: "lg-4 md-6", child: costBreakDown()),
|
||||
MyFlexItem(sizes: 'lg-5', child: salesAnalytics()),
|
||||
MyFlexItem(child: productOrder()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget stats() {
|
||||
Widget statsWidget(IconData icon, String title, String count, String change, 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,
|
||||
height: 140,
|
||||
child: Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
paddingAll: 24,
|
||||
color: color.withValues(alpha:0.2),
|
||||
child: MyContainer(paddingAll: 8, color: color, child: Icon(icon, size: 16, color: contentTheme.light)),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 80,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.labelSmall(title, maxLines: 1),
|
||||
MyText.bodyMedium(count, fontWeight: 600, maxLines: 1),
|
||||
Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
padding: MySpacing.xy(6, 4),
|
||||
color: change[0] == '+' ? Colors.green.withValues(alpha:.2) : theme.colorScheme.error.withValues(alpha:.2),
|
||||
child: MyText.labelSmall(change, color: change[0] == '+' ? Colors.green : theme.colorScheme.error),
|
||||
),
|
||||
MySpacing.width(8),
|
||||
Expanded(child: MyText.labelSmall("This Month", overflow: TextOverflow.ellipsis))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return MyFlex(contentPadding: false, children: [
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget(LucideIcons.shopping_bag, "Total Sales", "12,254", "+4.2%", contentTheme.primary)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget(LucideIcons.receipt_text, "Total Expenses", "\$28,346.00", "-4.2%", contentTheme.secondary)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget(LucideIcons.user, "Total Visitors", "1,29,368", "-3.54%", contentTheme.success)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget(LucideIcons.shopping_basket, "Total Orders", "35,367", "+5.18%", contentTheme.info)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget(LucideIcons.chart_column, "Average Order Value", "\$120", "+4.48%", contentTheme.dark)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget(LucideIcons.users, "Total Customer", "36,835", "-1.15%", contentTheme.warning)),
|
||||
]);
|
||||
}
|
||||
|
||||
Widget salesAnalytics() {
|
||||
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("Sales Analytics", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SizedBox(height: 384, child: salesAnalyticsChart()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
SfCartesianChart salesAnalyticsChart() {
|
||||
return SfCartesianChart(
|
||||
plotAreaBorderWidth: 0,
|
||||
margin: MySpacing.zero,
|
||||
primaryXAxis: const CategoryAxis(majorGridLines: MajorGridLines(width: 0), labelPlacement: LabelPlacement.onTicks),
|
||||
primaryYAxis: const NumericAxis(
|
||||
minimum: 30,
|
||||
maximum: 80,
|
||||
axisLine: AxisLine(width: 0),
|
||||
edgeLabelPlacement: EdgeLabelPlacement.shift,
|
||||
labelFormat: '{value}',
|
||||
majorTickLines: MajorTickLines(size: 0)),
|
||||
series: [
|
||||
SplineSeries<ChartSampleData, String>(
|
||||
dataSource: controller.salesAnalyticsData,
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.y,
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
name: 'Pending',
|
||||
),
|
||||
SplineSeries<ChartSampleData, String>(
|
||||
dataSource: controller.salesAnalyticsData,
|
||||
name: 'Complete',
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.secondSeriesYValue,
|
||||
)
|
||||
],
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
);
|
||||
}
|
||||
|
||||
Widget topCustomer() {
|
||||
Widget topCustomerData(String name, String cardNumber, int orders, String image) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
borderRadiusAll: 4,
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
child: Image.asset(image),
|
||||
),
|
||||
MySpacing.width(20),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(name, fontWeight: 600, maxLines: 1),
|
||||
MyText.labelSmall(cardNumber, maxLines: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyText.labelSmall("Orders : $orders"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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("Top Customer", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
topCustomerData("John Doe", "1234 5678 9012 3456", 21, Images.avatars[0]),
|
||||
MySpacing.height(24),
|
||||
topCustomerData("Jane Smith", "2345 6789 0123 4567", 22, Images.avatars[1]),
|
||||
MySpacing.height(24),
|
||||
topCustomerData("Michael Johnson", "3456 7890 1234 5678", 23, Images.avatars[2]),
|
||||
MySpacing.height(24),
|
||||
topCustomerData("Emily Davis", "4567 8901 2345 6789", 24, Images.avatars[3]),
|
||||
MySpacing.height(24),
|
||||
topCustomerData("Chris Brown", "5678 9012 3456 7890", 25, Images.avatars[4]),
|
||||
MySpacing.height(24),
|
||||
topCustomerData("Olivia Wilson", "6789 0123 4567 8901", 26, Images.avatars[5]),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Widget costBreakDown() {
|
||||
Widget buildCircleChartData(Color color, String name, String price) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
paddingAll: 4,
|
||||
color: color,
|
||||
),
|
||||
MySpacing.width(8),
|
||||
MyText.labelMedium(name)
|
||||
],
|
||||
),
|
||||
MyText.labelSmall(price),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
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(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.bodyMedium("Cost BreakDown", overflow: TextOverflow.ellipsis, fontWeight: 600),
|
||||
InkWell(onTap: () {}, child: Icon(LucideIcons.move_right, size: 16)),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 293,
|
||||
child: SfCircularChart(
|
||||
margin: MySpacing.zero,
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
series: <CircularSeries>[
|
||||
DoughnutSeries<ChartSampleData, String>(
|
||||
radius: '80%',
|
||||
explode: true,
|
||||
explodeOffset: '10%',
|
||||
dataSource: controller.circleChart,
|
||||
pointColorMapper: (ChartSampleData data, _) => data.pointColor,
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
dataLabelSettings: const DataLabelSettings(isVisible: true)),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [MyText.titleMedium("Top Channel"), MyText.titleMedium("Value")],
|
||||
),
|
||||
MySpacing.height(12),
|
||||
buildCircleChartData(const Color.fromRGBO(9, 0, 136, 1), "Salary", "\$54,847"),
|
||||
MySpacing.height(8),
|
||||
buildCircleChartData(const Color.fromRGBO(147, 0, 119, 1), "Bill", "\$58,188"),
|
||||
MySpacing.height(8),
|
||||
buildCircleChartData(const Color.fromRGBO(228, 0, 124, 1), "Marketing", "\$24,618"),
|
||||
MySpacing.height(8),
|
||||
buildCircleChartData(const Color.fromRGBO(255, 189, 57, 1), "Other", "\$15,651")
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget responseTimeByLocation() {
|
||||
Widget buildResponseTimeByLocationData(String currentTime, String price, IconData icon, Color iconColor) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(LucideIcons.circle_dot_dashed, size: 16),
|
||||
MySpacing.width(8),
|
||||
MyText.bodyMedium(currentTime),
|
||||
],
|
||||
),
|
||||
MySpacing.height(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
MyText.bodyLarge(price, fontSize: 20, fontWeight: 600, muted: true),
|
||||
MySpacing.width(8),
|
||||
Icon(icon, size: 16, color: iconColor),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 0,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.all(16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: MyText.titleMedium(
|
||||
"Response time by location",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
fontWeight: 600,
|
||||
),
|
||||
),
|
||||
PopupMenuButton(
|
||||
onSelected: controller.onSelectedTimeByLocation,
|
||||
itemBuilder: (BuildContext context) {
|
||||
return ["Year", "Month", "Week", "Day", "Hours"].map((behavior) {
|
||||
return PopupMenuItem(
|
||||
value: behavior,
|
||||
height: 32,
|
||||
child: MyText.bodySmall(
|
||||
behavior.toString(),
|
||||
color: theme.colorScheme.onSurface,
|
||||
fontWeight: 600,
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
color: theme.cardTheme.color,
|
||||
child: MyContainer.bordered(
|
||||
padding: MySpacing.xy(8, 4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
MyText.labelSmall(controller.selectedTimeByLocation.toString(), color: theme.colorScheme.onSurface),
|
||||
Icon(LucideIcons.chevron_down, size: 16, color: theme.colorScheme.onSurface)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
MySpacing.height(12),
|
||||
MyFlex(
|
||||
wrapCrossAlignment: WrapCrossAlignment.center,
|
||||
runAlignment: WrapAlignment.center,
|
||||
wrapAlignment: WrapAlignment.center,
|
||||
children: [
|
||||
MyFlexItem(
|
||||
sizes: "lg-4 md-4 sm-6",
|
||||
child: buildResponseTimeByLocationData("Current Week", "\$1886.52", LucideIcons.corner_right_up, contentTheme.success),
|
||||
),
|
||||
MyFlexItem(
|
||||
sizes: "lg-4 md-4 sm-6",
|
||||
child: buildResponseTimeByLocationData("Conversation", "5.68%", LucideIcons.corner_right_up, contentTheme.success),
|
||||
),
|
||||
MyFlexItem(
|
||||
sizes: "lg-4 md-4 sm-6",
|
||||
child: buildResponseTimeByLocationData("Customers", "59K", LucideIcons.corner_right_up, contentTheme.red),
|
||||
),
|
||||
],
|
||||
),
|
||||
MySpacing.height(12),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: MySpacing.all(16),
|
||||
child: SizedBox(
|
||||
height: 267,
|
||||
child: SfCartesianChart(
|
||||
primaryXAxis: CategoryAxis(),
|
||||
tooltipBehavior: controller.chart,
|
||||
axes: <ChartAxis>[
|
||||
NumericAxis(
|
||||
numberFormat: NumberFormat.compact(),
|
||||
majorGridLines: const MajorGridLines(width: 0),
|
||||
opposedPosition: true,
|
||||
name: 'yAxis1',
|
||||
interval: 1000,
|
||||
minimum: 0,
|
||||
maximum: 7000)
|
||||
],
|
||||
series: [
|
||||
ColumnSeries<ChartSampleData, String>(
|
||||
animationDuration: 2000,
|
||||
width: 0.5,
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(4), topRight: Radius.circular(4)),
|
||||
color: contentTheme.primary,
|
||||
dataSource: controller.chartData,
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
name: 'Unit Sold'),
|
||||
LineSeries<ChartSampleData, String>(
|
||||
animationDuration: 4500,
|
||||
animationDelay: 2000,
|
||||
dataSource: controller.chartData,
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.yValue,
|
||||
yAxisName: 'yAxis1',
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
name: 'Total Transaction')
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget productOrder() {
|
||||
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.titleMedium("Product Order", fontWeight: 600),
|
||||
MySpacing.height(20),
|
||||
if (controller.order.isNotEmpty)
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: DataTable(
|
||||
sortAscending: true,
|
||||
columnSpacing: 98,
|
||||
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('Order Id', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Customer Name', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Location', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Order Date', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Payments', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Quantity', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Price', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Total Amount', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Status', color: contentTheme.primary)),
|
||||
],
|
||||
rows: controller.order
|
||||
.mapIndexed((index, data) => DataRow(cells: [
|
||||
DataCell(MyText.bodyMedium("#${data.orderId}", fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.customerName, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.location, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium("${Utils.getDateStringFromDateTime(data.orderDate)}", fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.payment, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium("${data.quantity}", fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium("\$${data.price}", fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium("\$${data.quantity * data.price}", fontWeight: 600)),
|
||||
DataCell(MyContainer(
|
||||
padding: MySpacing.xy(8, 4),
|
||||
color: getStatusColor(data.status)?.withAlpha(32),
|
||||
child: MyText.bodySmall(
|
||||
data.status,
|
||||
fontWeight: 600,
|
||||
color: getStatusColor(data.status),
|
||||
),
|
||||
)),
|
||||
]))
|
||||
.toList()),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color? getStatusColor(String? status) {
|
||||
switch (status) {
|
||||
case "Delivered":
|
||||
return contentTheme.primary;
|
||||
case "Shopping":
|
||||
return contentTheme.success;
|
||||
case "New":
|
||||
return contentTheme.warning;
|
||||
case "Pending":
|
||||
return contentTheme.danger;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,436 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/dashboard/job_controller.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';
|
||||
|
||||
class JobScreen extends StatefulWidget {
|
||||
const JobScreen({super.key});
|
||||
|
||||
@override
|
||||
State<JobScreen> createState() => _JobScreenState();
|
||||
}
|
||||
|
||||
class _JobScreenState extends State<JobScreen> with UIMixin {
|
||||
JobController controller = Get.put(JobController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: GetBuilder(
|
||||
init: controller,
|
||||
tag: 'job_dashboard_controller',
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Job", fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Job', 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<ChartSampleData, String>(
|
||||
explode: true,
|
||||
dataSource: <ChartSampleData>[
|
||||
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<ChartSampleData, String>(
|
||||
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<ChartSampleData, String>(
|
||||
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()),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,435 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/dashboard/project_controller.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/model/task_list_model.dart';
|
||||
import 'package:marco/view/layouts/layout.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
class ProjectScreen extends StatefulWidget {
|
||||
const ProjectScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ProjectScreen> createState() => _ProjectScreenState();
|
||||
}
|
||||
|
||||
class _ProjectScreenState extends State<ProjectScreen> with UIMixin {
|
||||
ProjectController controller = Get.put(ProjectController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: GetBuilder(
|
||||
init: controller,
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Project", fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Project', active: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(children: [
|
||||
MyFlexItem(sizes: 'lg-6', child: stats()),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: taskPerformance()),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: incomeAnalytics()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: taskList()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: recentTransaction()),
|
||||
MyFlexItem(sizes: 'lg-3 md-6', child: taskSummary()),
|
||||
MyFlexItem(sizes: 'lg-9 md-6', child: projectSummary()),
|
||||
]),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget stats() {
|
||||
Widget statsWidget(String title, String subTitle, IconData icon, 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: [
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.bodyMedium(title, maxLines: 1),
|
||||
MyText.titleMedium(subTitle, fontWeight: 600),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
MyContainer(
|
||||
color: color,
|
||||
child: Icon(icon, color: contentTheme.light),
|
||||
)
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
return MyFlex(
|
||||
contentPadding: false,
|
||||
children: [
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget("Projects Completed", "120", LucideIcons.briefcase, contentTheme.primary)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget("Tasks In Progress", "75", LucideIcons.circle_check, contentTheme.secondary)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget("Total Hours Worked", "540", LucideIcons.clock, contentTheme.info)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget("Current Budgets", "\$12,500", LucideIcons.dollar_sign, contentTheme.success)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget("Completed Tasks", "58", LucideIcons.check, contentTheme.warning)),
|
||||
MyFlexItem(sizes: 'lg-6 md-6 sm-6', child: statsWidget("Team Members", "15", LucideIcons.user, contentTheme.danger)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget taskPerformance() {
|
||||
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("Task Performance", fontWeight: 600),
|
||||
SizedBox(
|
||||
height: 299,
|
||||
child: Theme(
|
||||
data: ThemeData(),
|
||||
child: SfCircularChart(
|
||||
margin: MySpacing.zero,
|
||||
series: [
|
||||
RadialBarSeries<ChartSampleData, String>(
|
||||
dataLabelSettings: const DataLabelSettings(isVisible: true, textStyle: TextStyle(fontSize: 10.0)),
|
||||
dataSource: <ChartSampleData>[
|
||||
ChartSampleData(x: 'Complete', y: 7, text: '100%', pointColor: contentTheme.primary),
|
||||
ChartSampleData(x: 'Active', y: 5, text: '100%', pointColor: contentTheme.success),
|
||||
ChartSampleData(x: 'Assigned', y: 8, text: '100%', pointColor: contentTheme.info),
|
||||
],
|
||||
trackColor: contentTheme.background,
|
||||
cornerStyle: CornerStyle.bothCurve,
|
||||
gap: '10%',
|
||||
radius: '90%',
|
||||
xValueMapper: (ChartSampleData data, _) => data.x as String,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
pointRadiusMapper: (ChartSampleData data, _) => data.text,
|
||||
pointColorMapper: (ChartSampleData data, _) => data.pointColor,
|
||||
dataLabelMapper: (ChartSampleData data, _) => data.x as String)
|
||||
],
|
||||
tooltipBehavior: controller.tooltipBehavior,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget incomeAnalytics() {
|
||||
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("Income Analytics", fontWeight: 600),
|
||||
SfCircularChart(
|
||||
margin: MySpacing.zero,
|
||||
legend: Legend(isVisible: true, overflowMode: LegendItemOverflowMode.wrap),
|
||||
series: [
|
||||
PieSeries<ChartSampleData, String>(
|
||||
dataSource: <ChartSampleData>[
|
||||
ChartSampleData(x: 'USA', y: 700000, text: '60%'),
|
||||
ChartSampleData(x: 'Germany', y: 450000, text: '50%'),
|
||||
ChartSampleData(x: 'China', y: 600000, text: '65%'),
|
||||
ChartSampleData(x: 'India', y: 400000, text: '55%'),
|
||||
ChartSampleData(x: 'Brazil', y: 350000, text: '40%'),
|
||||
ChartSampleData(x: 'Russia', y: 300000, text: '35%'),
|
||||
ChartSampleData(x: 'South Africa', y: 250000, text: '30%')
|
||||
],
|
||||
xValueMapper: (ChartSampleData data, _) => data.x as String,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
dataLabelMapper: (ChartSampleData data, _) => data.x as String,
|
||||
startAngle: 100,
|
||||
endAngle: 100,
|
||||
pointRadiusMapper: (ChartSampleData data, _) => data.text,
|
||||
dataLabelSettings: const DataLabelSettings(isVisible: true, labelPosition: ChartDataLabelPosition.outside),
|
||||
),
|
||||
],
|
||||
tooltipBehavior: TooltipBehavior(enable: true, tooltipPosition: TooltipPosition.auto, duration: 2 * 1000),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget taskList() {
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 0,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.all(24),
|
||||
child: MyText.bodyMedium("Task List", fontWeight: 600),
|
||||
),
|
||||
SizedBox(
|
||||
height: 300,
|
||||
child: ListView.separated(
|
||||
itemCount: controller.task.length,
|
||||
shrinkWrap: true,
|
||||
padding: MySpacing.x(24),
|
||||
itemBuilder: (context, index) {
|
||||
TaskListModel task = controller.task[index];
|
||||
return Row(
|
||||
children: [
|
||||
Theme(
|
||||
data: ThemeData(visualDensity: getCompactDensity),
|
||||
child: Checkbox(
|
||||
value: task.isSelectTask,
|
||||
onChanged: (value) => controller.onSelectTask(task),
|
||||
visualDensity: getCompactDensity,
|
||||
),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
MyContainer.rounded(
|
||||
height: 32,
|
||||
width: 32,
|
||||
paddingAll: 0,
|
||||
child: Image.asset(Images.avatars[index % Images.avatars.length], fit: BoxFit.cover),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
Expanded(child: MyText.bodyMedium(task.title, maxLines: 1)),
|
||||
MyText.labelMedium(task.status,
|
||||
color: task.status == 'Pending'
|
||||
? contentTheme.primary
|
||||
: task.status == 'Completed'
|
||||
? contentTheme.success
|
||||
: null),
|
||||
],
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return MySpacing.height(24);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget recentTransaction() {
|
||||
Widget recentTransaction(String title, String subTitle, String price) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
MyContainer.roundBordered(
|
||||
paddingAll: 12,
|
||||
child: MyText(title[0].capitalize.toString()),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(title),
|
||||
MySpacing.height(4),
|
||||
MyText.bodySmall(subTitle),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyText.bodySmall(price),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 0,
|
||||
height: 367,
|
||||
child: ListView(
|
||||
padding: MySpacing.all(24),
|
||||
children: [
|
||||
MyText.bodyMedium("Recent Transaction", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
recentTransaction("Charles", "Feb 28,2023 - 12:54PM", "price"),
|
||||
MySpacing.height(24),
|
||||
recentTransaction("David", "Feb 28,2023 - 12:54PM", "price"),
|
||||
MySpacing.height(24),
|
||||
recentTransaction("Leonard", "Feb 28,2023 - 12:54PM", "price"),
|
||||
MySpacing.height(24),
|
||||
recentTransaction("Steven", "Feb 28,2023 - 12:54PM", "price"),
|
||||
MySpacing.height(24),
|
||||
recentTransaction("Steven", "Feb 28,2023 - 12:54PM", "price"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget taskSummary() {
|
||||
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(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium("Task Summary", fontWeight: 600),
|
||||
MyContainer(
|
||||
onTap: () {},
|
||||
paddingAll: 8,
|
||||
color: contentTheme.light,
|
||||
child: MyText.labelSmall("View All", fontWeight: 600),
|
||||
)
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
SizedBox(
|
||||
height: 344,
|
||||
child: SfCartesianChart(
|
||||
plotAreaBorderWidth: 0,
|
||||
margin: MySpacing.zero,
|
||||
legend: Legend(isVisible: true, position: LegendPosition.bottom),
|
||||
primaryXAxis: const CategoryAxis(majorGridLines: MajorGridLines(width: 0), labelPlacement: LabelPlacement.onTicks),
|
||||
primaryYAxis: const NumericAxis(
|
||||
axisLine: AxisLine(width: 0), edgeLabelPlacement: EdgeLabelPlacement.shift, labelFormat: '{value}', majorTickLines: MajorTickLines(size: 0)),
|
||||
series: [
|
||||
SplineSeries<ChartSampleData, String>(
|
||||
dataSource: controller.chartData,
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.y,
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
name: 'This Week'),
|
||||
SplineSeries<ChartSampleData, String>(
|
||||
dataSource: controller.chartData,
|
||||
name: 'Last Week',
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
|
||||
yValueMapper: (ChartSampleData sales, _) => sales.secondSeriesYValue,
|
||||
)
|
||||
],
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget projectSummary() {
|
||||
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("Project Summary", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: DataTable(
|
||||
sortAscending: true,
|
||||
columnSpacing: 84,
|
||||
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('Title', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Assign to', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Due Date', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Priority', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Status', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Action', color: contentTheme.primary)),
|
||||
],
|
||||
rows: controller.projectSummary
|
||||
.mapIndexed((index, data) => DataRow(cells: [
|
||||
DataCell(MyText.bodyMedium("#${data.id}", fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.title, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.assignTo, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(Utils.getDateStringFromDateTime(data.date), fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.priority, fontWeight: 600)),
|
||||
DataCell(MyText.bodyMedium(data.status, 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()),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,506 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:marco/controller/dashboard/sales_controller.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';
|
||||
|
||||
class SalesScreen extends StatefulWidget {
|
||||
const SalesScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SalesScreen> createState() => _SalesScreenState();
|
||||
}
|
||||
|
||||
class _SalesScreenState extends State<SalesScreen> with UIMixin {
|
||||
SalesController controller = Get.put(SalesController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Layout(
|
||||
child: GetBuilder(
|
||||
init: controller,
|
||||
tag: 'sales_dashboard_controller',
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Crypto", fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Dashboard'),
|
||||
MyBreadcrumbItem(name: 'Crypto', active: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats("Total Income", "\$3,50,000", "15.00%")),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats("Profit", "\$1,20,000", "10.00%")),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats("Total Views", "15000", "5.00%")),
|
||||
MyFlexItem(sizes: 'lg-3 md-6 sm-6', child: stats("Conversion Rate", "18.75%", "3.50%")),
|
||||
MyFlexItem(sizes: 'lg-6 md-6', child: visitorsReport()),
|
||||
MyFlexItem(sizes: 'lg-6 md-6', child: otherStatistics()),
|
||||
MyFlexItem(sizes: 'lg-3.5 md-6', child: recentTransaction()),
|
||||
MyFlexItem(sizes: 'lg-3.5 md-6', child: recentActivity()),
|
||||
MyFlexItem(sizes: 'lg-2.5 md-6', child: countryWiseSale()),
|
||||
MyFlexItem(sizes: 'lg-2.5 md-6', child: dealSource()),
|
||||
MyFlexItem(child: recentOrder()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget stats(String title, String changes, String percentage) {
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
height: 144,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(title),
|
||||
MyText.titleLarge(changes, fontWeight: 600),
|
||||
Row(
|
||||
children: [
|
||||
MyContainer(
|
||||
paddingAll: 4,
|
||||
color: contentTheme.success.withValues(alpha:0.2),
|
||||
child: MyText.labelSmall(percentage, color: contentTheme.success),
|
||||
),
|
||||
MySpacing.width(8),
|
||||
Expanded(child: MyText.labelSmall("Compare to last month")),
|
||||
],
|
||||
)
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Widget visitorsReport() {
|
||||
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("Visitors Report", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SfCartesianChart(
|
||||
margin: MySpacing.zero,
|
||||
primaryXAxis: CategoryAxis(),
|
||||
tooltipBehavior: controller.visitorChart,
|
||||
axes: <ChartAxis>[
|
||||
NumericAxis(
|
||||
numberFormat: NumberFormat.compact(),
|
||||
majorGridLines: const MajorGridLines(width: 0),
|
||||
opposedPosition: true,
|
||||
name: 'yAxis1',
|
||||
interval: 1000,
|
||||
minimum: 0,
|
||||
maximum: 7000)
|
||||
],
|
||||
series: [
|
||||
ColumnSeries<ChartSampleData, String>(
|
||||
animationDuration: 2000,
|
||||
width: 0.5,
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(4), topRight: Radius.circular(4)),
|
||||
color: contentTheme.success,
|
||||
dataSource: controller.visitorChartData,
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.y,
|
||||
name: 'Unit Sold'),
|
||||
LineSeries<ChartSampleData, String>(
|
||||
animationDuration: 4500,
|
||||
animationDelay: 2000,
|
||||
dataSource: controller.visitorChartData,
|
||||
xValueMapper: (ChartSampleData data, _) => data.x,
|
||||
yValueMapper: (ChartSampleData data, _) => data.yValue,
|
||||
yAxisName: 'yAxis1',
|
||||
markerSettings: const MarkerSettings(isVisible: true),
|
||||
name: 'Total Transaction')
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget otherStatistics() {
|
||||
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("Other Statistics", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SfCartesianChart(
|
||||
plotAreaBorderWidth: 0,
|
||||
margin: MySpacing.zero,
|
||||
legend: Legend(isVisible: true, overflowMode: LegendItemOverflowMode.wrap, position: LegendPosition.bottom),
|
||||
primaryXAxis: const NumericAxis(edgeLabelPlacement: EdgeLabelPlacement.shift, majorGridLines: MajorGridLines(width: 0)),
|
||||
primaryYAxis: const NumericAxis(labelFormat: '{value}', axisLine: AxisLine(width: 0), majorTickLines: MajorTickLines(color: Colors.transparent)),
|
||||
series: [
|
||||
LineSeries<ChartData, num>(
|
||||
dataSource: controller.statisticsData,
|
||||
xValueMapper: (ChartData sales, _) => sales.x,
|
||||
yValueMapper: (ChartData sales, _) => sales.y,
|
||||
name: 'Pending',
|
||||
color: contentTheme.secondary,
|
||||
markerSettings: const MarkerSettings(isVisible: true)),
|
||||
LineSeries<ChartData, num>(
|
||||
dataSource: controller.statisticsData,
|
||||
name: 'Delivered',
|
||||
color: contentTheme.primary,
|
||||
xValueMapper: (ChartData sales, _) => sales.x,
|
||||
yValueMapper: (ChartData sales, _) => sales.y2,
|
||||
markerSettings: const MarkerSettings(isVisible: true))
|
||||
],
|
||||
tooltipBehavior: TooltipBehavior(enable: true),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget recentTransaction() {
|
||||
Widget recentTransactionWidget(String transactionMethod, String transactionType, String price, String date, IconData? icon, Color color) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
color: color.withValues(alpha:0.2),
|
||||
child: Icon(icon, color: color),
|
||||
),
|
||||
MySpacing.width(24),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(transactionMethod, fontWeight: 600, maxLines: 1),
|
||||
MySpacing.height(4),
|
||||
MyText.bodySmall(transactionType, fontWeight: 600, muted: true, maxLines: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
MyText.bodyMedium(price, fontWeight: 600),
|
||||
MyText.bodySmall(date, fontWeight: 600, muted: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
height: 475,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: MyText.bodyMedium("Recent Transaction", fontWeight: 600)),
|
||||
InkWell(onTap: () {}, child: MyText.labelSmall("View All", fontWeight: 600)),
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
recentTransactionWidget("Digital Wallet", "Online Transaction", "\$350.00", "Nov 23, 2023", LucideIcons.gift, contentTheme.primary),
|
||||
MySpacing.height(24),
|
||||
recentTransactionWidget("Bank Account", "Purchase", "\$150.00", "Nov 23, 2023", LucideIcons.coins, contentTheme.success),
|
||||
MySpacing.height(24),
|
||||
recentTransactionWidget("PayPal", "Transfer", "\$500.00", "Nov 22, 2023", LucideIcons.shopping_cart, contentTheme.purple),
|
||||
MySpacing.height(24),
|
||||
recentTransactionWidget("Digital Wallet", "Bill Payment", "\$120.00", "Nov 21, 2023", LucideIcons.wallet, contentTheme.warning),
|
||||
MySpacing.height(24),
|
||||
recentTransactionWidget("Credit Card", "Subscription", "\$20.00", "Nov 20, 2023", LucideIcons.id_card, contentTheme.danger),
|
||||
MySpacing.height(24),
|
||||
recentTransactionWidget("Digital Wallet", "Refund", "\$100.00", "Nov 19, 2023", LucideIcons.circle_arrow_up, contentTheme.info),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget countryWiseSale() {
|
||||
Widget countryWiseSaleWidget(String image, name, count) {
|
||||
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: MyText.bodyMedium(name, fontWeight: 600, overflow: TextOverflow.ellipsis)),
|
||||
MyContainer(
|
||||
borderRadiusAll: 8,
|
||||
padding: MySpacing.xy(8, 8),
|
||||
color: contentTheme.success.withAlpha(36),
|
||||
child: MyText.bodySmall(numberFormatter(count), fontWeight: 600, color: contentTheme.success),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
height: 475,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium("Country wise sale", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
countryWiseSaleWidget('assets/country/united_states.png', "France", "25000"),
|
||||
MySpacing.height(24),
|
||||
countryWiseSaleWidget('assets/country/argentina.png', "Brazil", "17500"),
|
||||
MySpacing.height(24),
|
||||
countryWiseSaleWidget('assets/country/germany.png', "India", "12500"),
|
||||
MySpacing.height(24),
|
||||
countryWiseSaleWidget('assets/country/mexico.png', "Japan", "22000"),
|
||||
MySpacing.height(24),
|
||||
countryWiseSaleWidget('assets/country/russia.png', "United Kingdom", "30000"),
|
||||
MySpacing.height(24),
|
||||
countryWiseSaleWidget('assets/country/canada.png', "Australia", "18000"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget recentActivity() {
|
||||
Widget recentActivityWidget(String title) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyContainer.rounded(paddingAll: 4, child: MyContainer.rounded(paddingAll: 4, color: contentTheme.primary, child: MyContainer.rounded(paddingAll: 4))),
|
||||
MySpacing.width(12),
|
||||
Expanded(child: MyText.bodyMedium(title, fontWeight: 600, maxLines: 2))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
height: 475,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium("Recent Activity", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget(
|
||||
"Ava Thompson placed an order for 3 units of Wireless Earbuds, 2 units of Bluetooth Speakers, and 1 unit of Smart Home Thermostat"),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget(
|
||||
"Noah Jackson upgraded his subscription to the Gold service plan, gaining access to premium features, priority support, and 20GB cloud storage for his team of 15 employees."),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget(
|
||||
"Emma Harris added 5 new items to the shopping cart, including a designer handbag, a set of luxury skincare products, a Bluetooth speaker, a fitness tracker, and a pair of leather boots"),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget(
|
||||
"Liam Davis purchased 1 unit of Electric Scooter, along with an additional helmet and charging station for enhanced convenience. Delivery expected in 5-7 business days."),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget(
|
||||
"Mason Martinez returned 2 units of Smartphone, citing dissatisfaction with the camera quality. The items will be processed for a full refund once inspected."),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget(
|
||||
"Isabella Robinson upgraded to the Platinum Plan with 5 users, unlocking advanced analytics tools, exclusive discounts, and premium customer support for her growing e-commerce team."),
|
||||
MySpacing.height(24),
|
||||
recentActivityWidget(
|
||||
"Elijah Walker completed a purchase of 6 ergonomic office chairs, 3 sit-stand desks, and a set of new monitor arms for the team, improving the comfort and productivity of the workspace."),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget dealSource() {
|
||||
Widget dealSourceWidget(String image, String title, String subtitle, String totalLeads) {
|
||||
return Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
height: 44,
|
||||
width: 44,
|
||||
paddingAll: 0,
|
||||
child: Image.asset(image, fit: BoxFit.cover),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium(title, fontWeight: 600, maxLines: 1),
|
||||
MyText.bodySmall(subtitle, maxLines: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
MyText.bodyMedium('\$$totalLeads', fontWeight: 600),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
height: 475,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium("Deal Source", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/uxerflow_logo.png", "Website", "userflow.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/dribbble-logo.png", "Dribbble", "dribbble.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/facebook-logo.png", "Facebook", "facebook.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/instagram-logo.png", "Instagram", "instagram.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/LinkedIn-logo.png", "Linkedin", "linkedin.com", "50"),
|
||||
MySpacing.height(24),
|
||||
dealSourceWidget("assets/social/twitter-logo.png", "Twitter", "twitter.com", "50"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget recentOrder() {
|
||||
return MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withValues(alpha:0.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.bodyMedium("Recent Order", fontWeight: 600),
|
||||
MySpacing.height(24),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: DataTable(
|
||||
sortAscending: true,
|
||||
columnSpacing: 150,
|
||||
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('Product', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Quantity', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Customer', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Status', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Price', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Date', color: contentTheme.primary)),
|
||||
DataColumn(label: MyText.labelLarge('Action', color: contentTheme.primary)),
|
||||
],
|
||||
rows: controller.recentOrder
|
||||
.mapIndexed((index, data) => DataRow(cells: [
|
||||
DataCell(MyText.labelMedium(data.productName)),
|
||||
DataCell(MyText.labelMedium('${data.quantity}')),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
height: 32,
|
||||
width: 32,
|
||||
paddingAll: 0,
|
||||
child: Image.asset(Images.avatars[index % Images.avatars.length]),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
MyText.labelMedium('${data.customer}'),
|
||||
],
|
||||
)),
|
||||
DataCell(
|
||||
MyContainer(
|
||||
paddingAll: 4,
|
||||
color: data.status == 'Shipped'
|
||||
? contentTheme.success
|
||||
: data.status == 'Delivery'
|
||||
? contentTheme.info
|
||||
: contentTheme.danger,
|
||||
child: MyText.labelMedium(
|
||||
'${data.status}',
|
||||
color: data.status == 'Success' ? contentTheme.onSuccess : contentTheme.onDanger,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(MyText.labelMedium('\$${data.price}')),
|
||||
DataCell(MyText.labelMedium('${Utils.getDateTimeStringFromDateTime(data.orderDate)}')),
|
||||
DataCell(Row(
|
||||
children: [
|
||||
MyContainer.rounded(
|
||||
onTap: () {},
|
||||
paddingAll: 8,
|
||||
color: contentTheme.primary,
|
||||
child: Icon(LucideIcons.eye, size: 16, color: contentTheme.onPrimary),
|
||||
),
|
||||
MySpacing.width(20),
|
||||
MyContainer.rounded(
|
||||
onTap: () {},
|
||||
paddingAll: 8,
|
||||
color: contentTheme.secondary,
|
||||
child: Icon(LucideIcons.pencil, size: 16, color: contentTheme.onSecondary),
|
||||
),
|
||||
],
|
||||
)),
|
||||
]))
|
||||
.toList()),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,303 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/task_planing/report_task_controller.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/widgets/my_breadcrumb.dart';
|
||||
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
|
||||
import 'package:marco/helpers/widgets/my_button.dart';
|
||||
import 'package:marco/helpers/widgets/my_card.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex_item.dart';
|
||||
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/layout.dart';
|
||||
import 'package:marco/helpers/widgets/avatar.dart';
|
||||
import 'package:marco/helpers/widgets/my_team_model_sheet.dart';
|
||||
|
||||
class CommentTaskScreen extends StatefulWidget {
|
||||
const CommentTaskScreen({super.key});
|
||||
|
||||
@override
|
||||
State<CommentTaskScreen> createState() => _CommentTaskScreenState();
|
||||
}
|
||||
class _Member {
|
||||
final String firstName;
|
||||
_Member(this.firstName);
|
||||
}
|
||||
|
||||
class _CommentTaskScreenState extends State<CommentTaskScreen> with UIMixin {
|
||||
final ReportTaskController controller = Get.put(ReportTaskController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final taskData = Get.arguments as Map<String, dynamic>;
|
||||
print("Task Data: $taskData");
|
||||
controller.basicValidator.getController('assigned_date')?.text =
|
||||
taskData['assignedOn'] ?? '';
|
||||
controller.basicValidator.getController('assigned_by')?.text =
|
||||
taskData['assignedBy'] ?? '';
|
||||
controller.basicValidator.getController('work_area')?.text =
|
||||
taskData['location'] ?? '';
|
||||
controller.basicValidator.getController('activity')?.text =
|
||||
taskData['activity'] ?? '';
|
||||
controller.basicValidator.getController('planned_work')?.text =
|
||||
taskData['plannedWork'] ?? '';
|
||||
controller.basicValidator.getController('completed_work')?.text =
|
||||
taskData['completedWork'] ?? '';
|
||||
controller.basicValidator.getController('team_members')?.text =
|
||||
(taskData['teamMembers'] as List<dynamic>).join(', ');
|
||||
controller.basicValidator.getController('assigned')?.text =
|
||||
taskData['assigned'] ?? '';
|
||||
controller.basicValidator.getController('task_id')?.text =
|
||||
taskData['taskId'] ?? '';
|
||||
|
||||
return Layout(
|
||||
child: GetBuilder<ReportTaskController>(
|
||||
init: controller,
|
||||
tag: 'comment_task_controller',
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Comment Task",
|
||||
fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Daily Progress Report'),
|
||||
MyBreadcrumbItem(name: 'Comment Task'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(sizes: "lg-8 md-12", child: detail()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget detail() {
|
||||
return Form(
|
||||
key: controller.basicValidator.formKey,
|
||||
child: MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withOpacity(0.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(LucideIcons.server, size: 16),
|
||||
MySpacing.width(12),
|
||||
MyText.titleMedium("Activity Summary", fontWeight: 600),
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
// Static fields
|
||||
buildRow(
|
||||
"Assigned By",
|
||||
controller.basicValidator
|
||||
.getController('assigned_by')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Work Area",
|
||||
controller.basicValidator
|
||||
.getController('work_area')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Activity",
|
||||
controller.basicValidator
|
||||
.getController('activity')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Planned Work",
|
||||
controller.basicValidator
|
||||
.getController('planned_work')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Completed Work",
|
||||
controller.basicValidator
|
||||
.getController('completed_work')
|
||||
?.text
|
||||
.trim()),
|
||||
buildTeamMembers(),
|
||||
|
||||
MyText.labelMedium("Comment"),
|
||||
MySpacing.height(8),
|
||||
TextFormField(
|
||||
validator: controller.basicValidator.getValidation('comment'),
|
||||
controller: controller.basicValidator.getController('comment'),
|
||||
keyboardType: TextInputType.text,
|
||||
decoration: InputDecoration(
|
||||
hintText: "eg: Work done successfully",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(16),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
|
||||
// Buttons
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
MyButton.text(
|
||||
onPressed: () => Get.back(),
|
||||
padding: MySpacing.xy(20, 16),
|
||||
splashColor: contentTheme.secondary.withValues(alpha: 0.1),
|
||||
child: MyText.bodySmall('Cancel'),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
MyButton(
|
||||
onPressed: () async {
|
||||
if (controller.basicValidator.validateForm()) {
|
||||
await controller.reportTask(
|
||||
projectId: controller.basicValidator
|
||||
.getController('task_id')
|
||||
?.text ??
|
||||
'', // Replace with actual ID
|
||||
comment: controller.basicValidator
|
||||
.getController('comment')
|
||||
?.text ??
|
||||
'',
|
||||
completedTask: int.tryParse(controller.basicValidator
|
||||
.getController('completed_work')
|
||||
?.text ??
|
||||
'') ??
|
||||
0,
|
||||
checklist: [],
|
||||
reportedDate: DateTime.now(),
|
||||
);
|
||||
}
|
||||
},
|
||||
elevation: 0,
|
||||
padding: MySpacing.xy(20, 16),
|
||||
backgroundColor: contentTheme.primary,
|
||||
borderRadiusAll: AppStyle.buttonRadius.medium,
|
||||
child: MyText.bodySmall(
|
||||
'Comment',
|
||||
color: contentTheme.onPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Loading spinner
|
||||
Obx(() {
|
||||
return controller.isLoading.value
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: SizedBox.shrink();
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Widget buildTeamMembers() {
|
||||
final teamMembersText =
|
||||
controller.basicValidator.getController('team_members')?.text ?? '';
|
||||
final members = teamMembersText
|
||||
.split(',')
|
||||
.map((e) => e.trim())
|
||||
.where((e) => e.isNotEmpty)
|
||||
.toList();
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
MyText.labelMedium("Team Members:"),
|
||||
MySpacing.width(12),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
TeamBottomSheet.show(
|
||||
context: context,
|
||||
teamMembers: members.map((name) => _Member(name)).toList(),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 32,
|
||||
width: 100,
|
||||
child: Stack(
|
||||
children: [
|
||||
for (int i = 0; i < members.length.clamp(0, 3); i++)
|
||||
Positioned(
|
||||
left: i * 24.0,
|
||||
child: Tooltip(
|
||||
message: members[i],
|
||||
child: Avatar(
|
||||
firstName: members[i],
|
||||
lastName: '',
|
||||
size: 32,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (members.length > 3)
|
||||
Positioned(
|
||||
left: 2 * 24.0,
|
||||
child: CircleAvatar(
|
||||
radius: 16,
|
||||
backgroundColor: Colors.grey.shade300,
|
||||
child: MyText.bodyMedium(
|
||||
'+${members.length - 3}',
|
||||
style: const TextStyle(
|
||||
fontSize: 12, color: Colors.black87),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildRow(String label, String? value) {
|
||||
print("Label: $label, Value: $value");
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.labelMedium("$label:"),
|
||||
MySpacing.width(12),
|
||||
Expanded(
|
||||
child: MyText.bodyMedium(value?.isNotEmpty == true ? value! : "-"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,269 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:marco/controller/task_planing/report_task_controller.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/widgets/my_breadcrumb.dart';
|
||||
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
|
||||
import 'package:marco/helpers/widgets/my_button.dart';
|
||||
import 'package:marco/helpers/widgets/my_card.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex.dart';
|
||||
import 'package:marco/helpers/widgets/my_flex_item.dart';
|
||||
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/layout.dart';
|
||||
|
||||
class ReportTaskScreen extends StatefulWidget {
|
||||
const ReportTaskScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ReportTaskScreen> createState() => _ReportTaskScreenState();
|
||||
}
|
||||
|
||||
class _ReportTaskScreenState extends State<ReportTaskScreen> with UIMixin {
|
||||
final ReportTaskController controller = Get.put(ReportTaskController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final taskData = Get.arguments as Map<String, dynamic>;
|
||||
print("Task Data: $taskData");
|
||||
controller.basicValidator.getController('assigned_date')?.text =
|
||||
taskData['assignedOn'] ?? '';
|
||||
controller.basicValidator.getController('assigned_by')?.text =
|
||||
taskData['assignedBy'] ?? '';
|
||||
controller.basicValidator.getController('work_area')?.text =
|
||||
taskData['location'] ?? '';
|
||||
controller.basicValidator.getController('activity')?.text =
|
||||
taskData['activity'] ?? '';
|
||||
controller.basicValidator.getController('team_size')?.text =
|
||||
taskData['teamSize'].toString();
|
||||
controller.basicValidator.getController('assigned')?.text =
|
||||
taskData['assigned'] ?? '';
|
||||
controller.basicValidator.getController('task_id')?.text =
|
||||
taskData['taskId'] ?? '';
|
||||
|
||||
return Layout(
|
||||
child: GetBuilder<ReportTaskController>(
|
||||
init: controller,
|
||||
tag: 'report_task_controller',
|
||||
builder: (controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
MyText.titleMedium("Report Task",
|
||||
fontSize: 18, fontWeight: 600),
|
||||
MyBreadcrumb(
|
||||
children: [
|
||||
MyBreadcrumbItem(name: 'Daily Progress Report'),
|
||||
MyBreadcrumbItem(name: 'Report Task'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
MySpacing.height(flexSpacing),
|
||||
Padding(
|
||||
padding: MySpacing.x(flexSpacing / 2),
|
||||
child: MyFlex(
|
||||
children: [
|
||||
MyFlexItem(sizes: "lg-8 md-12", child: detail()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget detail() {
|
||||
return Form(
|
||||
key: controller.basicValidator.formKey,
|
||||
child: MyCard.bordered(
|
||||
borderRadiusAll: 4,
|
||||
border: Border.all(color: Colors.grey.withOpacity(0.2)),
|
||||
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
|
||||
paddingAll: 24,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(LucideIcons.server, size: 16),
|
||||
MySpacing.width(12),
|
||||
MyText.titleMedium("General", fontWeight: 600),
|
||||
],
|
||||
),
|
||||
MySpacing.height(24),
|
||||
|
||||
// Static fields
|
||||
buildRow(
|
||||
"Assigned Date",
|
||||
controller.basicValidator
|
||||
.getController('assigned_date')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Assigned By",
|
||||
controller.basicValidator
|
||||
.getController('assigned_by')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Work Area",
|
||||
controller.basicValidator
|
||||
.getController('work_area')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Activity",
|
||||
controller.basicValidator
|
||||
.getController('activity')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Team Size",
|
||||
controller.basicValidator
|
||||
.getController('team_size')
|
||||
?.text
|
||||
.trim()),
|
||||
buildRow(
|
||||
"Assigned",
|
||||
controller.basicValidator
|
||||
.getController('assigned')
|
||||
?.text
|
||||
.trim()),
|
||||
|
||||
// Input fields
|
||||
MyText.labelMedium("Completed Work"),
|
||||
MySpacing.height(8),
|
||||
TextFormField(
|
||||
validator:
|
||||
controller.basicValidator.getValidation('completed_work'),
|
||||
controller:
|
||||
controller.basicValidator.getController('completed_work'),
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
hintText: "eg: 10",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(16),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
MyText.labelMedium("Comment"),
|
||||
MySpacing.height(8),
|
||||
TextFormField(
|
||||
validator: controller.basicValidator.getValidation('comment'),
|
||||
controller: controller.basicValidator.getController('comment'),
|
||||
keyboardType: TextInputType.text,
|
||||
decoration: InputDecoration(
|
||||
hintText: "eg: Work done successfully",
|
||||
hintStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: outlineInputBorder,
|
||||
enabledBorder: outlineInputBorder,
|
||||
focusedBorder: focusedInputBorder,
|
||||
contentPadding: MySpacing.all(16),
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
),
|
||||
MySpacing.height(24),
|
||||
|
||||
// Buttons
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
MyButton.text(
|
||||
onPressed: () => Get.back(),
|
||||
padding: MySpacing.xy(20, 16),
|
||||
splashColor: contentTheme.secondary.withValues(alpha: 0.1),
|
||||
child: MyText.bodySmall('Cancel'),
|
||||
),
|
||||
MySpacing.width(12),
|
||||
MyButton(
|
||||
onPressed: controller.reportStatus.value == ApiStatus.loading
|
||||
? null
|
||||
: () async {
|
||||
if (controller.basicValidator.validateForm()) {
|
||||
await controller.reportTask(
|
||||
projectId: controller.basicValidator
|
||||
.getController('task_id')
|
||||
?.text ??
|
||||
'',
|
||||
comment: controller.basicValidator
|
||||
.getController('comment')
|
||||
?.text ??
|
||||
'',
|
||||
completedTask: int.tryParse(controller
|
||||
.basicValidator
|
||||
.getController('completed_work')
|
||||
?.text ??
|
||||
'') ??
|
||||
0,
|
||||
checklist: [],
|
||||
reportedDate: DateTime.now(),
|
||||
);
|
||||
}
|
||||
},
|
||||
elevation: 0,
|
||||
padding: MySpacing.xy(20, 16),
|
||||
backgroundColor: contentTheme.primary,
|
||||
borderRadiusAll: AppStyle.buttonRadius.medium,
|
||||
child: Obx(() {
|
||||
if (controller.reportStatus.value == ApiStatus.loading) {
|
||||
return SizedBox(
|
||||
height: 16,
|
||||
width: 16,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
contentTheme.onPrimary),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return MyText.bodySmall(
|
||||
'Save',
|
||||
color: contentTheme.onPrimary,
|
||||
);
|
||||
}
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildRow(String label, String? value) {
|
||||
print("Label: $label, Value: $value");
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.labelMedium("$label:"),
|
||||
MySpacing.width(12),
|
||||
Expanded(
|
||||
child: MyText.bodyMedium(value?.isNotEmpty == true ? value! : "-"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -100,8 +100,6 @@ flutter:
|
||||
- assets/country/
|
||||
- assets/data/
|
||||
- assets/dummy/
|
||||
- assets/dummy/ecommerce/
|
||||
- assets/dummy/single_product/
|
||||
- assets/lang/
|
||||
- assets/logo/
|
||||
- assets/logo/loading_logo.png
|
||||
|