From f166e8179b8b291ad356fb4c9e11095d13140948 Mon Sep 17 00:00:00 2001
From: ciraganenicole <ciraganenicole@gmail.com>
Date: Wed, 4 Oct 2023 08:56:29 +0200
Subject: [PATCH 1/2] Port ballot to the dashboard

---
 main/app/DataTransferObjects/BallotData.php   |   4 +-
 main/app/Enums/ModelStatusEnum.php            |  16 +-
 .../Dashboard/BallotController.php            |  45 ++++-
 .../Dashboard/DashboardController.php         |   6 +-
 .../Dashboard/SnapshotController.php          |   5 +-
 main/app/Models/Ballot.php                    |  19 +-
 .../js/Pages/Dashboard/Ballots/Create.vue     | 152 +---------------
 .../js/Pages/Dashboard/Ballots/Edit.vue       |  48 +----
 .../js/Pages/Dashboard/Ballots/Index.vue      |  79 --------
 .../Dashboard/Ballots/Partials/BallotCard.vue |  88 +++++++++
 .../Dashboard/Ballots/Partials/BallotForm.vue | 133 ++++++++++++++
 .../Dashboard/Ballots/Partials/BallotList.vue | 161 ++++++++++++++++
 .../Ballots/Partials/BallotStatusBadge.vue    |  28 +++
 .../Dashboard/Ballots/Partials/Step1.vue      | 172 ++++++++++++++++++
 .../Ballots/{ => Partials}/Step2.vue          |   9 +-
 .../Ballots/{ => Partials}/Step3.vue          |  12 +-
 .../Dashboard/Ballots/Partials/Step4.vue      |  14 ++
 .../Ballots/Services/admin-ballot-service.ts  |   7 +
 .../js/Pages/Dashboard/Ballots/Step1.vue      |  38 ----
 .../js/Pages/Dashboard/Ballots/Step4.vue      |  20 --
 .../js/Pages/Dashboard/Ballots/View.vue       |  32 ++++
 main/resources/js/Pages/Dashboard/Home.vue    |  20 ++
 .../js/Pages/Dashboard/Snapshot/Create.vue    |   2 +-
 main/resources/js/models/alert.ts             |   6 +
 .../js/shared/Services/admin-service.ts       |   8 +
 main/resources/js/shared/Services/alert.ts    |  12 ++
 main/resources/js/stores/ballot-store.ts      | 118 ++++++------
 .../resources/js/stores/global-alert-store.ts |  25 +++
 main/resources/js/types/generated.d.ts        |   1 +
 main/resources/js/utils/alert.ts              |  11 ++
 main/routes/web.php                           |  15 +-
 31 files changed, 883 insertions(+), 423 deletions(-)
 delete mode 100644 main/resources/js/Pages/Dashboard/Ballots/Index.vue
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/Partials/BallotCard.vue
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/Partials/BallotForm.vue
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/Partials/BallotList.vue
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/Partials/BallotStatusBadge.vue
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue
 rename main/resources/js/Pages/Dashboard/Ballots/{ => Partials}/Step2.vue (62%)
 rename main/resources/js/Pages/Dashboard/Ballots/{ => Partials}/Step3.vue (62%)
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/Partials/Step4.vue
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/Services/admin-ballot-service.ts
 delete mode 100644 main/resources/js/Pages/Dashboard/Ballots/Step1.vue
 delete mode 100644 main/resources/js/Pages/Dashboard/Ballots/Step4.vue
 create mode 100644 main/resources/js/Pages/Dashboard/Ballots/View.vue
 create mode 100644 main/resources/js/models/alert.ts
 create mode 100644 main/resources/js/shared/Services/admin-service.ts
 create mode 100644 main/resources/js/shared/Services/alert.ts
 create mode 100644 main/resources/js/stores/global-alert-store.ts
 create mode 100644 main/resources/js/utils/alert.ts

diff --git a/main/app/DataTransferObjects/BallotData.php b/main/app/DataTransferObjects/BallotData.php
index b3e8037..201b05f 100644
--- a/main/app/DataTransferObjects/BallotData.php
+++ b/main/app/DataTransferObjects/BallotData.php
@@ -9,10 +9,12 @@
 class BallotData extends Data
 {
     public function __construct(
+        public int $id,
         public int $user_id,
         public string $title,
         public string $description,
-        public string $status,
+        public  $status,
+        public ?string $isPublished,
         public string $started_at,
         public string $ended_at,
     ) {
diff --git a/main/app/Enums/ModelStatusEnum.php b/main/app/Enums/ModelStatusEnum.php
index 686a9ad..2a4b539 100644
--- a/main/app/Enums/ModelStatusEnum.php
+++ b/main/app/Enums/ModelStatusEnum.php
@@ -2,16 +2,14 @@
 
 namespace App\Enums;
 
-enum ModelStatusEnum: String
+enum ModelStatusEnum: string
 {
-    public static function getValues()
-    {
-        $possibleStatuses = [
-            'draft',
-            'pending',
-            'published',
-        ];
+    case DRAFT = 'draft';
+    case PENDING = 'pending';
+    case PUBLISHED = 'published';
 
-        return $possibleStatuses;
+    public static function values(): array
+    {
+        return array_column(self::cases(), 'value');
     }
 }
diff --git a/main/app/Http/Controllers/Dashboard/BallotController.php b/main/app/Http/Controllers/Dashboard/BallotController.php
index 6500908..5f4eab2 100644
--- a/main/app/Http/Controllers/Dashboard/BallotController.php
+++ b/main/app/Http/Controllers/Dashboard/BallotController.php
@@ -7,6 +7,9 @@
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
 use Inertia\Inertia;
+use App\DataTransferObjects\BallotData;
+use Illuminate\Support\Facades\Redirect;
+use Illuminate\Support\Facades\Gate;
 
 
 class BallotController extends Controller
@@ -26,7 +29,7 @@ public function index(Request $request)
     public function create()
     {
         return Inertia::render(
-            'Dashboard/Ballots/Create'
+            'Dashboard/Ballots/Create', []
         );
     }
 
@@ -36,27 +39,51 @@ public function store(Request $request)
         $validatedData = $request->validate([
             'title' => 'required|string|min:3|max:255',
             'description' => 'required|string|min:10',
+            'started_at' => 'required',
+            'ended_at' => 'required',
+            'status' => 'required',
         ]);
 
         $ballot = Ballot::create([
             'user_id' => $user->id,
             'title' => $validatedData['title'],
             'description' => $validatedData['description'],
+            'started_at' => $validatedData['started_at'],
+            'ended_at' => $validatedData['ended_at'],
+            'status' => $validatedData['status'],
         ]);
 
         $ballot->save();
 
-        return to_route('dashboard.ballots.index');
+        //return to_route('dashboard.home');
     }
 
-    public function edit(Request $request)
+    public function view(Request $request, Ballot $ballot)
+    {
+        $user = Auth::user();
+        
+        return Inertia::render(
+            'Dashboard/Ballots/View', [
+                'ballot' => BallotData::from([
+                    'id' => $ballot->id,
+                    'user_id' => $user->id,
+                    'title' => $ballot->title, 
+                    'description' => $ballot->description, 
+                    'status' => $ballot->status, 
+                    'started_at' => $ballot->started_at,
+                    'ended_at' => $ballot->ended_at 
+                ]),
+            ]
+        );
+    }
+
+    public function edit(Request $request, Ballot $ballot)
     {
-        $ballot = Ballot::find($request->input('id'));
 
         return Inertia::render(
             'Dashboard/Ballots/Edit',
             [
-                'ballot' => $ballot,
+                'ballot' => BallotData::from($ballot),
             ]
         );
     }
@@ -67,18 +94,20 @@ public function update(Request $request, Ballot $ballot)
         $validatedData = $request->validate([
             'title' => 'required|string|min:3|max:255',
             'description' => 'required|string|min:10',
+            'started_at' => 'required',
+            'ended_at' => 'required',
+            'status' => 'required',
         ]);
 
         $ballot->update($validatedData);
 
-        // return response()->json(['message' => 'Ballot updated successfully', 'ballot' => BallotData::from( $ballot)], 201);
-        return to_route('dashboard.ballots.index');
+        return to_route('dashboard.ballots.view', $ballot);
     }
 
     public function delete(Ballot $ballot)
     {
         $ballot->delete();
 
-        return to_route('dashboard.ballots.index');
+        return to_route('dashboard.home');
     }
 }
diff --git a/main/app/Http/Controllers/Dashboard/DashboardController.php b/main/app/Http/Controllers/Dashboard/DashboardController.php
index 8c34a11..511b117 100644
--- a/main/app/Http/Controllers/Dashboard/DashboardController.php
+++ b/main/app/Http/Controllers/Dashboard/DashboardController.php
@@ -3,7 +3,6 @@
 namespace App\Http\Controllers\Dashboard;
 
 use App\DataTransferObjects\BallotData;
-use App\DataTransferObjects\SnapshotData;
 use App\Http\Controllers\Controller;
 use App\Models\Ballot;
 use App\Models\Snapshot;
@@ -15,13 +14,14 @@
 
 class DashboardController extends Controller
 {
-    public function index(Request $request): Response
+    public function index(Request $request, Ballot $ballot ): Response
     {
         $snapshots = Snapshot::all();
-
+        $ballots = BallotData::collection(Ballot::all());
         return Inertia::render('Dashboard/Home')
             ->with([
                 'snapshots' => $snapshots,
+                'ballots' => $ballots,
             ]);
     }
 }
diff --git a/main/app/Http/Controllers/Dashboard/SnapshotController.php b/main/app/Http/Controllers/Dashboard/SnapshotController.php
index 5d42351..2c397bc 100644
--- a/main/app/Http/Controllers/Dashboard/SnapshotController.php
+++ b/main/app/Http/Controllers/Dashboard/SnapshotController.php
@@ -39,11 +39,14 @@ public function store(Request $request)
             'user_id' => $user->id,
             'title' => $validatedData['title'],
             'description' => $validatedData['description'],
+            'policy_id' => 23,
+            'status' => 'draft',
+            'type' => 'file',
         ]);
 
         $snapshot->save();
 
-        return to_route('dashboard.snapshot.index');
+        return to_route('dashboard.snapshots.index');
     }
 
     public function read(Request $request)
diff --git a/main/app/Models/Ballot.php b/main/app/Models/Ballot.php
index 0d062c2..6ba8e6a 100644
--- a/main/app/Models/Ballot.php
+++ b/main/app/Models/Ballot.php
@@ -4,8 +4,11 @@
 
 use App\Models\Traits\HasModel;
 use App\Models\Traits\HasOwner;
+use Illuminate\Database\Eloquent\Casts\Attribute;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
+use App\Enums\ModelStatusEnum;
+use App\Enums\BallotTypeEnum;
 
 class Ballot extends Model
 {
@@ -17,6 +20,20 @@ class Ballot extends Model
         'description',
         'status',
         'policy_id',
-        'type',
+        'isPublished',
+        'started_at',
+        'ended_at',
     ];
+
+    protected $casts = [
+        'status' => ModelStatusEnum::class,
+        'started_at' => 'datetime:Y-m-d H:i:s',
+        'ended_at' => 'datetime:Y-m-d H:i:s',
+    ];
+
+    public function isPublished(): Attribute
+    {
+        return Attribute::make(get: fn () => $this->status == 'published' ? true : false);
+    }
 }
+
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Create.vue b/main/resources/js/Pages/Dashboard/Ballots/Create.vue
index 329ec69..f3f052a 100644
--- a/main/resources/js/Pages/Dashboard/Ballots/Create.vue
+++ b/main/resources/js/Pages/Dashboard/Ballots/Create.vue
@@ -1,149 +1,7 @@
-<template>
-    <AppLayout title="Dashboard">
-        <div class="py-12">
-            <div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
-                <div class="flex flex-col w-[100%] bg-white">
-                    <div class="bg-gray-50 px-20 py-10">
-                        <div class="flex items-center justify-center">
-                            <div
-                                v-for="(stepName, stepNumber) in stepNames"
-                                :key="stepNumber"
-                                class="flex-col items-center"
-                            >
-                                <div class="relative flex items-center mb-4">
-          <span
-              class="rounded-tl-full rounded-bl-full p-2 bg-primary-950 text-white w-8 h-8 flex items-center justify-center mr-[-4px]"
-              :class="{ 'bg-opacity-50': step !== stepName.id }"
-          >{{ stepName.id }}</span>
-                                    <span
-                                        class="rounded-full p-2 bg-primary-950 text-white w-20 h-16 flex items-center justify-center"
-                                        :class="{ 'bg-opacity-50': step !== stepName.id }"
-                                    >
-            <i
-                v-if="stepName.id === 1"
-                class="fas fa-user"
-            ></i>
-            <i
-                v-else-if="stepName.id === 2"
-                class="fas fa-question"
-            ></i>
-            <i
-                v-else-if="stepName.id === 3"
-                class="fas fa-shield-alt"
-            ></i>
-            <i
-                v-else
-                class="fas fa-check"
-            ></i>
-          </span>
-                                    <svg
-                                        v-if="stepNumber < 3"
-                                        class="h-[2px] w-[100%] bg-primary-950"
-                                        :class="{ 'bg-opacity-50': step !== stepName.id }"
-                                        :style="{ left: `${((stepName.id - 1) / 3) * 100}%` }"
-                                    ></svg>
-                                </div>
-                                <span
-                                    class="text-xl text-slate-600 ml-4"
-                                    :class="{ 'text-primary-950': step === stepNumber }"
-                                >
-            {{ stepName.name }}
-          </span>
-                            </div>
-                        </div>
-                    </div>
-                    <div class="flex items-center px-20 py-10">
-                        <div class="w-[40%] border-[1px] border-primary-950 rounded-lg p-8">
-                            <h1 class="mb-12 text-2xl font-semibold text-slate-600">
-                                Create new ballot
-                            </h1>
-                            <component :is="currentStepComponent"/>
-                        </div>
-                        <div class="w-[30%] p-20">Sidebar</div>
-                    </div>
-                    <hr/>
-                    <div class="flex flex-row items-center justify-between px-20 py-4">
-                        <button
-                            v-if="step !== 1"
-                            class="text-primary-950 border-primary-950 border-[1px] py-4 px-8 text-lg mt-10 rounded-[10px] flex items-center justify-between w-[140px]"
-                            @click="prevStep"
-                            :disabled="step === 1"
-                        >
-                            <i class="fas fa-arrow-left"></i>
-                            <p>Back</p>
-                        </button>
-                        <button
-                            v-if="step !== 4"
-                            class="bg-primary-950 text-white p-4 text-lg mt-10 rounded-[10px] flex items-center justify-between w-[140px]"
-                            @click="nextStep"
-                            :disabled="step === 4"
-                        >
-                            <p>Next step</p>
-                            <i class="fas fa-arrow-right"></i>
-                        </button>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </AppLayout>
-</template>
-
 <script setup lang="ts">
-import {useForm} from '@inertiajs/vue3';
-import {useFormDataStore} from '@/stores/ballot-store';
-import {computed} from 'vue';
-
-import Step1 from './Step1.vue';
-import Step2 from './Step2.vue';
-import Step3 from './Step3.vue';
-import Step4 from './Step4.vue';
-import AppLayout from "@/Layouts/AppLayout.vue";
-
-const formDataStore = useFormDataStore();
-const step = computed(() => formDataStore.step);
-
-const stepNames = computed(() => [
-    {id: 1, name: 'Intro'},
-    {id: 2, name: 'Questions'},
-    {id: 3, name: 'Policy'},
-    {id: 4, name: 'Publish'},
-
-]);
-
-const nextStep = () => {
-    formDataStore.nextStep();
-};
-
-const prevStep = () => {
-    formDataStore.prevStep();
-};
-
-const currentStepComponent = computed(() => {
-    switch (step.value) {
-        case 1:
-            return Step1;
-        case 2:
-            return Step2;
-        case 3:
-            return Step3;
-        case 4:
-            return Step4;
-        default:
-            return null;
-    }
-});
-
-const form = useForm({
-    title: formDataStore.formData.title || '',
-    description: formDataStore.formData.description || '',
-    question: formDataStore.formData.question || '',
-    policy: formDataStore.formData.policy || '',
-    publish: formDataStore.formData.publish || false
-});
-
-const submit = () => {
-    form.post(route('dashboard.ballots.store'), {});
-
-}
-
+import BallotForm from './Partials/BallotForm.vue';
 </script>
+
+<template>
+    <BallotForm class="w-full" />
+</template>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Edit.vue b/main/resources/js/Pages/Dashboard/Ballots/Edit.vue
index 57fccbc..0facf95 100644
--- a/main/resources/js/Pages/Dashboard/Ballots/Edit.vue
+++ b/main/resources/js/Pages/Dashboard/Ballots/Edit.vue
@@ -1,50 +1,16 @@
 <script setup lang="ts">
-import { useForm } from '@inertiajs/inertia-vue3';
+import BallotForm from './Partials/BallotForm.vue';
+import BallotData = App.DataTransferObjects.BallotData;
 
-
-const props = withDefaults(
-    defineProps<{
-        ballot?: {'id': number, 'title': string, 'description': string};
-    }>(),
-    {}
-);
-
-const form = useForm({
-  id: props.ballot.id,
-  title: props.ballot.title,
-  description: props.ballot.description
-});
-
-const submit = () => {
-  form.put(route('dashboard.ballots.update', {'ballot': props.ballot.id}))};
+const props = defineProps<{
+    ballot: BallotData;
+}>();
 
 </script>
 
 <template>
-    <div class="flex items-center justify-center h-screen">
+    <BallotForm :ballot="props.ballot" class="w-full" />
+</template>
 
- <form @submit.prevent="submit" class="border-2 border-slate-400 rounded-[15px] w-[40%] p-16">
-     <h1 class="mb-12 text-2xl font-semibold text-slate-600">Edit ballot</h1>
-     <div class="flex flex-col">
-         <label for="title" class="mb-4 text-lg text-slate-600">Title</label>
-         <input
-         v-model="form.title"
-           type="text"
-           name="title"
-           id="title"
-           required
-           class="rounded-[10px] border-slate-400 p-4 w-[100%]"
-         />
-     </div>
-     <div class="flex flex-col">
-         <label for="description" class="my-4 text-lg text-slate-600">Description </label>
-         <textarea v-model="form.description" id="description" required class="rounded-[10px] border-slate-400 p-4 w-[100%] h-[200px]"></textarea>
-     </div>
-     <div>
-         <button type="submit" class="bg-blue-600 text-white p-4 text-lg mt-10 rounded-[10px] w-[30%]">Submit</button>
-     </div>
- </form>
-    </div>
- </template>
 
 
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Index.vue b/main/resources/js/Pages/Dashboard/Ballots/Index.vue
deleted file mode 100644
index c4e2109..0000000
--- a/main/resources/js/Pages/Dashboard/Ballots/Index.vue
+++ /dev/null
@@ -1,79 +0,0 @@
-<script setup lang="ts">
-import { Inertia } from "@inertiajs/inertia";
-import { Head, Link } from "@inertiajs/vue3";
-
-defineProps({ ballots: Array });
-
-function destroy(id) {
-    if (confirm("Are you sure you want to Delete")) {
-    Inertia.delete(route('dashboard.ballots.delete', id));
-    }
-}
-
-function updateStatus(id) {
-    if (confirm("Are you sure you want to publish")) {
-    Inertia.post(route('dashboard.ballots.store', id));
-    }
-}
-</script>
-
-<template>
-    <Head title="Ballots" />
-
-    <div class="p-16">
-        <div class="mb-16">
-            <a
-                :href="route('dashboard.ballots.create.view')"
-                class="text-xl text-white font-semibold bg-primary-950 p-4 rounded-[15px]"
-                >Create new ballot</a
-            >
-        </div>
-
-        <section class="grid grid-cols-3 gap-20">
-            <div v-for="ballot in ballots" :key="ballot.id">
-                <div
-                    class="w-full bg-white border border-slate-200 rounded-[15px] shadow-lg"
-                >
-                    <ul
-                        class="flex flex-row items-center justify-between text-sm font-medium text-center text-gray-500 border-b border-slate-200 rounded-t-[15px] p-4"
-                    >
-                        <li class="flex flex-row items-center">
-                            <div
-                                class="mr-6 bg-orange-50 text-orange-900 px-3 rounded-[30px] published:bg-green-50 published:text-green-900"
-                            >
-                              {{ ballot.status }}
-                            </div>
-                        </li>
-                        <li class="flex flex-row items-center gap-4">
-                            <Link
-                                :href="route('dashboard.ballots.edit', {'id': ballot.id})"
-                                class="px-6 py-1 bg-yellow-50 text-yellow-900 rounded-lg"
-                                >Edit</Link
-                            >
-                            <button
-                                class="bg-red-100 text-red-900 px-3 py-1 rounded-lg"
-                                @click="destroy(ballot.id)"
-                            >
-                                Delete
-                            </button>
-                        </li>
-                    </ul>
-                    <div
-                        class="p-6 bg-white rounded-[15px] dark:bg-gray-800 h-[250px]"
-                    >
-                        <h2
-                            class="mb-6 text-xl font-extrabold tracking-tight text-slate-600 dark:text-white"
-                        >
-                            {{ ballot.title }}
-                        </h2>
-                        <p
-                            class="mb-2 text-gray-500 dark:text-gray-400 text-sm overflow-wrap"
-                        >
-                            {{ ballot.description }}
-                        </p>
-                    </div>
-                </div>
-            </div>
-        </section>
-    </div>
-</template>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotCard.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotCard.vue
new file mode 100644
index 0000000..82a0067
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotCard.vue
@@ -0,0 +1,88 @@
+<script setup lang="ts">
+import BallotData = App.DataTransferObjects.BallotData;
+import { Link } from '@inertiajs/vue3';
+
+defineProps<{
+    ballot: BallotData;
+}>();
+
+</script>
+
+
+<template>
+    <section>
+        <div class="relative">
+            <div
+                class="overflow-hidden border border-primary-950 rounded-lg shadow-sm dark:border-gray-700 focus-within:border-indigo-500 dark:focus-within:border-indigo-600 focus-within:ring-1 focus-within:ring-indigo-500 dark:focus-within:ring-indigo-500">
+                <header
+                    class="block w-full p-4 text-gray-900 border-0 resize-none dark:text-gray-100 xl:p-4 sm:text-sm sm:leading-6 bg-primary-50/20 dark:bg-gray-900">
+                    <div class="flex flex-wrap items-center justify-start gap-2 sm:flex-nowrap">
+                        <h2 class="text-xl font-bold mb-4">
+                            {{ ballot.title }}
+                        </h2>
+                        <!-- <BallotStatusBadge :ballot="ballot"></BallotStatusBadge> -->
+                    </div>
+                    <p class="h-20 text-lg">
+                        {{ ballot.description }}
+                    </p>
+                </header>
+
+                <div class="flex items-center gap-8 px-2 py-4 xl:px-3">
+                    <div class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300 w-44">
+                        Ballot Start
+                    </div>
+                    <p class="relative block w-full flex flex-1 border-0 p-2.5 sm:text-sm sm:leading-6 capitalize font-medium text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:ring-0 bg-primary-50/20 dark:bg-gray-900 rounded-lg">
+                        {{ ballot.started_at }}
+                    </p>
+                </div>
+
+                <div class="flex items-center gap-8 px-2 py-4 xl:px-3">
+                    <div class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300 w-44">
+                        Ballot End
+                    </div>
+                    <p class="relative block w-full flex flex-1 border-0 p-2.5 sm:text-sm sm:leading-6 capitalize font-medium text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:ring-0 bg-primary-50/20 dark:bg-gray-900 rounded-lg">
+                        {{ ballot.ended_at }}
+                    </p>
+                </div>
+
+                <div class="flex items-center gap-8 px-2 py-4 xl:px-3">
+                    <div class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300 w-44">
+                        Ballot Status
+                    </div>
+                    <p class="relative block w-full flex flex-1 border-0 p-2.5 sm:text-sm sm:leading-6 capitalize font-medium text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:ring-0 bg-primary-50/20 dark:bg-gray-900 rounded-lg">
+                        {{ ballot.status }}
+                    </p>
+                </div>
+
+
+                <div aria-hidden="true">
+                    <div class="py-3">
+                        <div class="h-10"/>
+                    </div>
+                    <div class="h-px"/>
+                    <div class="py-3">
+                        <div class="py-px">
+                            <div class="h-10"/>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <div v-if="ballot.title" class="absolute bottom-0 inset-x-px">
+                <div
+                    class="flex items-center justify-between px-2 py-3 space-x-3 border-t border-gray-200 dark:border-gray-700 sm:px-3">
+                    <div class="flex">
+
+                    </div>
+                    <div class="flex-shrink-0">
+                        <Link as="button"
+                              :href="route( 'dashboard.ballots.edit', { ballot: ballot.id})"
+                              class="inline-flex items-center px-6 py-2 text-sm font-semibold text-white bg-primary-950 rounded-md shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
+                            <span>Edit</span>
+                        </Link>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </section>
+</template>
\ No newline at end of file
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotForm.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotForm.vue
new file mode 100644
index 0000000..b7b3046
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotForm.vue
@@ -0,0 +1,133 @@
+<template>
+    <AppLayout title="Dashboard">
+        <div class="py-12">
+            <div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
+                <div class="flex flex-col w-[100%] bg-white">
+                    <div class="bg-gray-50 px-10 py-4">
+                        <div class="flex items-center justify-center">
+                            <div
+                                v-for="(stepName, stepNumber) in stepNames"
+                                :key="stepNumber"
+                                class="flex-col items-center"
+                            >
+                                <div class="relative flex items-center mb-2">
+                                    <span
+                                        class="rounded-tl-full rounded-bl-full p-2 bg-primary-950 text-white w-8 h-8 flex items-center justify-center mr-[-4px]"
+                                        :class="{
+                                            'bg-opacity-50':
+                                                step !== stepName.id,
+                                        }"
+                                        
+                                        >{{ stepName.id }}</span
+                                    >
+                                    <span
+                                        class="rounded-full p-2 bg-primary-950 text-white w-20 h-16 flex items-center justify-center"
+                                        :class="{
+                                            'bg-opacity-50':
+                                                step !== stepName.id,
+                                        }"
+                                        @click="changeStep()"
+                                       
+                                    >
+                                    <UserIcon class="w-6 h-6" v-if="stepName.id === 1"/>
+                                    <QuestionMarkCircleIcon class="w-6 h-6" v-else-if="stepName.id === 2"/>
+                                    <DocumentIcon class="w-6 h-6" v-else-if="stepName.id === 3"/>
+                                    <CheckCircleIcon class="w-6 h-6" v-else />
+                                    </span>
+                                    <svg
+                                        v-if="stepNumber < 3"
+                                        class="h-[2px] w-[100%] bg-primary-950"
+                                        :class="{
+                                            'bg-opacity-50':
+                                                step !== stepName.id,
+                                        }"
+                                        :style="{
+                                            left: `${
+                                                ((stepName.id - 1) / 3) * 100
+                                            }%`,
+                                        }"
+                                    ></svg>
+                                </div>
+                                <span
+                                    class="text-xl text-slate-600 ml-4"
+                                    :class="{
+                                        'text-primary-950': step === stepNumber,
+                                    }"
+                                >
+                                    {{ stepName.name }}
+                                </span>
+                            </div>
+                        </div>
+                    </div>
+                    <h1  class="text-xl font-semibold text-slate-600 p-8">
+                        {{ ballot ? 'Edit Ballot' : 'Create new ballot' }}
+                            </h1>
+                    <div class="flex items-center px-8 mb-4 gap-16">
+                        <div
+                            class="w-[60%] border-[1px] border-primary-950 rounded-lg"
+                        >
+                            <!-- <component :is="currentStepComponent" /> -->
+                            <div v-if="step == 1">
+                                <Step1 :ballot="ballot"></Step1>
+                            </div>
+                            <div v-else-if="step == 2">
+                                <Step2></Step2>
+                            </div>
+                            <div v-else-if="step == 3">
+                                <Step3></Step3>
+                            </div>
+                            <div v-else-if="step == 4">
+                                <Step4></Step4>
+                            </div>
+                        </div>
+                        <div class="w-[35%] p-20 bg-primary-50/30 h-[560px] rounded-lg">Sidebar</div>
+                    </div>
+                    <hr />
+                </div>
+            </div>
+        </div>
+    </AppLayout>
+</template>
+
+<script setup lang="ts">
+import { useBallotStore } from "@/stores/ballot-store";
+import {storeToRefs} from 'pinia';
+import { computed, ref } from "vue";
+import { UserIcon, QuestionMarkCircleIcon, CheckCircleIcon, DocumentIcon } from '@heroicons/vue/24/solid';
+
+import Step1 from "./Step1.vue";
+import Step2 from "./Step2.vue";
+import Step3 from "./Step3.vue";
+import Step4 from "./Step4.vue";
+import AppLayout from "@/Layouts/AppLayout.vue";
+import BallotData=App.DataTransferObjects.BallotData
+
+const props = defineProps<{
+    ballot?: BallotData;
+}>();
+
+let propBallot = ref(props.ballot);
+const { nextStep, previousStep } = useBallotStore();
+
+const formD = useBallotStore();
+formD.uploadBallotData(propBallot.value);
+formD.setStep();
+const { step, ballot } = storeToRefs(formD);
+
+
+const stepNames = computed(() => [
+    { id: 1, name: "Create ballot" },
+    { id: 2, name: "Add questions" },
+    { id: 3, name: "Add policy" },
+    { id: 4, name: "Publish" },
+]);
+
+const changeStep = () => {
+    if (step.value < 4) {
+        nextStep();
+    } else if (step.value > 1){
+        previousStep();
+    }
+    }
+</script>
+ 
\ No newline at end of file
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotList.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotList.vue
new file mode 100644
index 0000000..23fbe3f
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotList.vue
@@ -0,0 +1,161 @@
+<template>
+    <div class="overflow-x-auto">
+        <ul
+            role="list"
+            class="grid grid-cols-1 gap-x-6 gap-y-8 lg:grid-cols-3 xl:gap-x-8"
+            style="width: max-content; min-width: 100%"
+        >
+            <li v-for="ballot in ballots" :key="ballot.id">
+                <div
+                    class="w-full bg-white border border-slate-200 rounded-[15px] shadow-lg"
+                >
+                    <ul
+                        class="flex flex-row items-center justify-between text-sm font-medium text-center text-gray-500 border-b border-slate-200 rounded-t-[15px] p-4 bg-primary-50/10"
+                    >
+                        <li class="text-slate-900 text-xl font-bold">
+                            {{ ballot.title }}
+                        </li>
+
+                        <li class="flex flex-row items-center">
+                            <div class="flex flex-row items-center gap-2">
+                                <div
+                                    class="bg-orange-400 text-orange-900 rounded-full p-[4px]"
+                                >
+                                    <div
+                                        class="bg-orange-900 text-orange-900 rounded-full w-[6px] h-[6px]"
+                                    />
+                                </div>
+                                <p class="text-lg text-orange-900">Pending</p>
+                            </div>
+
+                            <div class="hidden sm:flex sm:items-center sm:ml-6">
+                                <div class="relative">
+                                    <Dropdown align="right" width="60">
+                                        <template #trigger>
+                                            <button type="button">
+                                                <svg
+                                                    class="ml-2 -mr-0.5 h-4 w-4"
+                                                    xmlns="http://www.w3.org/2000/svg"
+                                                    fill="none"
+                                                    viewBox="0 0 24 24"
+                                                    stroke-width="1.5"
+                                                    stroke="currentColor"
+                                                >
+                                                    <path
+                                                        stroke-linecap="round"
+                                                        stroke-linejoin="round"
+                                                        stroke-width="2"
+                                                        d="M16 12a2 2 0 11-4 0 2 2 0 014 0zm-8 0a2 2 0 11-4 0 2 2 0 014 0zm16 0a2 2 0 11-4 0 2 2 0 014 0z"
+                                                    />
+                                                </svg>
+                                            </button>
+                                        </template>
+
+                                        <template #content>
+                                            <div
+                                                class="flex flex-col items-start gap-4 p-4 w-40 right-0"
+                                            >
+                                                <DropdownLink
+                                                    :href="view(ballot.id)"
+                                                >
+                                                    View
+                                                </DropdownLink>
+
+                                                <DropdownLink
+                                                    :href="
+                                                        route(
+                                                            'dashboard.ballots.edit',
+                                                            { id: ballot.id }
+                                                        )
+                                                    "
+                                                >
+                                                    Edit
+                                                </DropdownLink>
+
+                                                <button
+                                                    @click="destroy(ballot.id)"
+                                                    class="text-red-600 dark:text-red-400 hover:bg-red-100 hover:text-red-800 ml-4"
+                                                >
+                                                    Delete
+                                                </button>
+                                            </div>
+                                        </template>
+                                    </Dropdown>
+                                </div>
+                            </div>
+                        </li>
+                    </ul>
+                    <div
+                        class="p-6 bg-white rounded-[15px] dark:bg-gray-800 h-[250px]"
+                    >
+                        <ul>
+                            <li>
+                                <div
+                                    class="flex flex-row items-center justify-between py-4"
+                                >
+                                    <h3>Ballot opens</h3>
+                                    <p>{{ ballot.started_at }}</p>
+                                </div>
+                                <hr class="h-4" />
+                            </li>
+                            <li>
+                                <div
+                                    class="flex flex-row items-center justify-between py-4"
+                                >
+                                    <h3>Ballot ends</h3>
+                                    <p>{{ ballot.ended_at }}</p>
+                                </div>
+                                <hr class="h-4" />
+                            </li>
+                            <li>
+                                <div
+                                    class="flex flex-row items-center justify-between py-2"
+                                >
+                                    <h3>Total votes</h3>
+                                    <p>0</p>
+                                </div>
+                            </li>
+                        </ul>
+                    </div>
+                </div>
+            </li>
+
+            <li
+                class="py-16 overflow-hidden border border-gray-400 border-dashed rounded-xl dark:border-gray-700 hover:border-indigo-600"
+            >
+                <Link
+                    as="button"
+                    :href="route('dashboard.ballots.create.view')"
+                    class="flex flex-col items-center justify-center w-full h-full gap-2 px-6 py-4 leading-6 text-gray-500 text-md xl:text-xl dark:text-gray-400"
+                >
+                    <PlusIcon class="w-6 h-6" />
+                    <span>Create ballot</span>
+                </Link>
+            </li>
+        </ul>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { Link } from "@inertiajs/vue3";
+import { Inertia } from "@inertiajs/inertia";
+import { PlusIcon } from "@heroicons/vue/24/solid";
+import Dropdown from "@/Components/Dropdown.vue";
+import DropdownLink from "@/Components/DropdownLink.vue";
+import BallotData = App.DataTransferObjects.BallotData;
+
+defineProps<{
+    ballots: BallotData[];
+}>();
+
+function destroy(id) {
+    if (confirm("Are you sure you want to Delete")) {
+        Inertia.delete(route("dashboard.ballots.delete", id));
+    }
+}
+
+function view(id) {
+    let link = route("dashboard.ballots.view", { ballot: id });
+    return link;
+}
+</script>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotStatusBadge.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotStatusBadge.vue
new file mode 100644
index 0000000..7d52e2d
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/BallotStatusBadge.vue
@@ -0,0 +1,28 @@
+<script lang="ts" setup>
+import BallotData = App.DataTransferObjects.BallotData;
+import {computed} from "vue";
+
+const props = defineProps<{
+    ballot: BallotData;
+}>();
+
+let status = computed(() => {
+    switch (props.ballot.status) {
+        case 'published':
+            return props.ballot?.status ? 'Pending' : 'Published';
+        default:
+            return props.ballot.status;
+    }
+});
+
+</script>
+<template>
+    <span class="flex items-center gap-x-1.5">
+        <span class="flex-none rounded-full p-1">
+            <div class="h-1.5 w-1.5 rounded-full" />
+        </span>
+        <span class="text-xs leading-5 text-gray-300 capitalize">
+            {{ status }}
+        </span>
+    </span>
+</template>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue
new file mode 100644
index 0000000..826b31a
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue
@@ -0,0 +1,172 @@
+<template>
+    <form @submit.prevent="submitForm">
+        <div class="flex flex-col bg-primary-100/10">
+        <input
+            v-model="form.title"
+            type="text"
+            name="title"
+            id="title"
+            placeholder="Title"
+            required
+            class="block w-full border-0 py-3 px-6 text-lg font-medium text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:ring-0 bg-primary-50/10 dark:bg-gray-900"
+        />
+        <textarea
+            v-model="form.description"
+            id="description"
+            placeholder="Write a description"
+            required
+            class="block w-full h-[100px] py-3 px-6 text-gray-900 bg-primary-50/10 border-0 rounded-md resize-none text-md xl:text-lg dark:text-gray-100 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6 dark:bg-gray-900"
+        ></textarea>
+    </div>
+
+    <div class="flex flex-col p-4">
+        <div>
+            <div class="flex items-center gap-8 px-2 py-4 xl:px-3">
+         <label for="title" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300 w-44">Start Date & Time</label>
+         <input 
+           v-model="form.started_at"
+           type="datetime-local" 
+           name="version" 
+           id="version" 
+           placeholder="Datetime" 
+           class="relative w-full flex flex-1 border-0 sm:text-sm sm:leading-6 font-medium text-gray-900 dark:text-gray-100 placeholder:text-gray-400 bg-primary-50/10 dark:bg-gray-900 ring-1 ring-gray-300 dark:ring-gray-700 focus:ring-2 focus:ring-indigo-600 dark:focus:ring-indigo-700 rounded-lg">
+     </div>
+     <div class="flex items-center gap-8 px-2 py-4 xl:px-3">
+         <label for="title" class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300 w-44">End Date & Time</label>
+         <input 
+           v-model="form.ended_at"
+           type="datetime-local" 
+           name="version" 
+           id="version" 
+           placeholder="Datetime" 
+           class="relative w-full flex flex-1 border-0 sm:text-sm sm:leading-6 font-medium text-gray-900 dark:text-gray-100 placeholder:text-gray-400 bg-primary-50/10 dark:bg-gray-900 ring-1 ring-gray-300 dark:ring-gray-700 focus:ring-2 focus:ring-indigo-600 dark:focus:ring-indigo-700 rounded-lg">
+     </div>
+
+     <Listbox as="div" @update:modelValue="value => form.status = value"
+                             class="flex items-center gap-8 px-2 py-2 border-t border-gray-200 xl:px-3 dark:border-gray-700">
+                        <ListboxLabel class="block text-sm font-medium leading-6 text-gray-900 dark:text-gray-300 w-44">
+                            Ballot Status
+                        </ListboxLabel>
+                        <div class="relative flex flex-1 mt-2">
+                            <ListboxButton
+                                class="relative w-full cursor-default rounded-md bg-primary-50/10 dark:bg-gray-900 py-1.5 pl-3 pr-10 text-left text-gray-900 dark:text-gray-100 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-600 dark:focus:ring-indigo-700 sm:text-sm sm:leading-6">
+                                <span class="block capitalize truncate">{{ form.status }}</span>
+                                <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
+                                  <ChevronUpDownIcon class="w-5 h-5 text-gray-400" aria-hidden="true"/>
+                                </span>
+                            </ListboxButton>
+
+                            <transition leave-active-class="transition duration-100 ease-in"
+                                        leave-from-class="opacity-100" leave-to-class="opacity-0">
+                                <ListboxOptions
+                                    class="absolute z-10 w-full py-1 mt-1 overflow-auto text-base bg-primary-50 rounded-md shadow-lg max-h-60 dark:bg-gray-700 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
+                                    <ListboxOption as="template" v-for="status in Object.values(ballotStatuses)" :key="status"
+                                                   :value="status" v-slot="{ active, selected }">
+                                        <li :class="[active ? 'bg-primary-950 text-white' : 'text-gray-900', 'relative cursor-default select-none py-2 pl-3 pr-9']">
+                                            <span class="capitalize"
+                                                  :class="[selected ? 'font-semibold' : 'font-normal', 'block truncate']">
+                                                {{status }}
+                                            </span>
+
+                                            <span v-if="selected"
+                                                  :class="[active ? 'text-white' : 'text-indigo-600', 'absolute inset-y-0 right-0 flex items-center pr-4']">
+                                                <CheckIcon class="w-5 h-5" aria-hidden="true"/>
+                                          </span>
+                                        </li>
+                                    </ListboxOption>
+                                </ListboxOptions>
+                            </transition>
+                        </div>
+                    </Listbox>
+                    </div>
+
+        <div class="flex justify-end px-2 py-2 space-x-2 border-t border-gray-200 flex-nowrap sm:px-3 dark:border-gray-700">
+            <div class="flex-shrink-0" data-headlessui-state="">
+                <label id="headlessui-listbox-label-30" data-headlessui-state="" class="sr-only">Assign</label>
+                <div class="relative">
+                    <button id="headlessui-listbox-button-31" type="button" aria-haspopup="listbox" aria-expanded="false" data-headlessui-state="" class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 rounded-full whitespace-nowrap bg-gray-50 dark:bg-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-900 sm:px-3" aria-labelledby="headlessui-listbox-label-30 headlessui-listbox-button-31">
+                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="flex-shrink-0 w-5 h-5 text-gray-300 dark:text-gray-100 sm:-ml-1">
+                            <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-5.5-2.5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zM10 12a5.99 5.99 0 00-4.793 2.39A6.483 6.483 0 0010 16.5a6.483 6.483 0 004.793-2.11A5.99 5.99 0 0010 12z" clip-rule="evenodd"></path>
+                        </svg>
+                        <span class="hidden truncate sm:ml-2 sm:block">Assign</span>
+                    </button>
+                </div>
+            </div>
+        </div>
+        <div class="flex items-center justify-between px-2 py-2 space-x-3 border-t border-gray-200 dark:border-gray-700 sm:px-3">
+            <div class="flex"></div>
+            <div class="flex-shrink-0">
+                <button 
+                type="submit" 
+                class="inline-flex items-center px-3 py-2 text-sm font-semibold text-white bg-primary-950 rounded-md shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
+                {{ ballot ? 'Edit' : 'Create' }}
+            </button>
+            </div>
+        </div>
+    </div>
+</form>
+</template>
+
+<script setup lang="ts">
+import { useForm } from "@inertiajs/vue3";
+import AlertService from "@/shared/Services/alert"
+import {Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions} from '@headlessui/vue'
+import BallotData = App.DataTransferObjects.BallotData;
+import { ChevronUpDownIcon } from '@heroicons/vue/20/solid'
+import { useBallotStore } from "@/stores/ballot-store";
+import { ref } from "vue";
+import AdminBallotService from "../Services/admin-ballot-service"
+
+
+const props = defineProps<{
+    status?: String;
+    ballot?: BallotData;
+}>();
+
+const ballotStatuses = ref({});
+AdminBallotService.getBallotStatuses().then((statuses) => {
+    ballotStatuses.value = statuses;
+});
+
+const form = useForm({
+    title: props?.ballot?.title ?? '',
+    description: props?.ballot?.description ?? '',
+    status: props?.ballot?.status ?? 'Select Status',
+    type: props?.ballot?.type ?? 'Select Type',
+    started_at: props?.ballot?.started_at,
+    ended_at: props?.ballot?.ended_at,
+});
+
+const { nextStep } = useBallotStore();
+
+const submitForm = () => {
+    if (!props.ballot?.id) {
+        form.post(route('dashboard.ballots.store'), {
+            onSuccess: () => {
+                AlertService.show(['Ballot created successfully'], 'success');
+                nextStep();
+            },
+            onError: (errors) => {
+                AlertService.show(
+                    Object
+                    .entries(errors)
+                    .map(([key, value]) => value)
+                );
+            },
+        });
+    } else {
+        form.put(route('dashboard.ballots.update', {ballot: props.ballot?.id}), {
+            onSuccess: () => {
+                AlertService.show(['Ballot updated successfully'], 'success');
+            },
+            onError: (errors) => {
+                AlertService.show(
+                    Object
+                    .entries(errors)
+                    .map(([key, value]) => value)
+                );
+            },
+        });
+    }
+}
+</script>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Step2.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step2.vue
similarity index 62%
rename from main/resources/js/Pages/Dashboard/Ballots/Step2.vue
rename to main/resources/js/Pages/Dashboard/Ballots/Partials/Step2.vue
index 00a4e28..3337c70 100644
--- a/main/resources/js/Pages/Dashboard/Ballots/Step2.vue
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step2.vue
@@ -4,7 +4,7 @@
         >Question
         </label>
         <textarea
-            v-model="formDataStore.formData.question"
+            v-model="form.question"
             id="description"
             required
             class="rounded-[10px] border-slate-400 p-4 w-[100%] h-[150px]"
@@ -13,12 +13,11 @@
 </template>
 
 <script setup lang="ts">
-import {useFormDataStore} from '@/stores/ballot-store';
+import { useForm } from '@inertiajs/vue3';
 
-const formDataStore = useFormDataStore();
 
-formDataStore.updateFormData({
-    question: formDataStore.formData.question
+const form = useForm({
+    question: '' 
 });
 
 </script>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Step3.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step3.vue
similarity index 62%
rename from main/resources/js/Pages/Dashboard/Ballots/Step3.vue
rename to main/resources/js/Pages/Dashboard/Ballots/Partials/Step3.vue
index 2f994d6..0f20975 100644
--- a/main/resources/js/Pages/Dashboard/Ballots/Step3.vue
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step3.vue
@@ -4,7 +4,7 @@
         >Policy
         </label>
         <textarea
-            v-model="formDataStore.formData.policy"
+            v-model="form.policy"
             id="description"
             required
             class="rounded-[10px] border-slate-400 p-4 w-[100%] h-[150px]"
@@ -13,13 +13,9 @@
 </template>
 
 <script setup lang="ts">
-import {useFormDataStore} from '@/stores/ballot-store';
+import { useForm } from '@inertiajs/vue3';
 
-
-const formDataStore = useFormDataStore();
-
-formDataStore.updateFormData({
-    policy: formDataStore.formData.policy
+const form = useForm({
+    policy: '' 
 });
-
 </script>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Partials/Step4.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step4.vue
new file mode 100644
index 0000000..2f67a0c
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step4.vue
@@ -0,0 +1,14 @@
+<template>
+    <button @click="submit" class="text-xl text-white font-semibold bg-primary-950 p-4 rounded-[15px]">Publish</button>
+</template>
+
+<script setup lang="ts">
+
+let publish = false
+
+const submit = () => {
+    publish = true
+}
+
+
+</script>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Services/admin-ballot-service.ts b/main/resources/js/Pages/Dashboard/Ballots/Services/admin-ballot-service.ts
new file mode 100644
index 0000000..db9e7fe
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/Services/admin-ballot-service.ts
@@ -0,0 +1,7 @@
+import AdminService from "@/shared/Services/admin-service";
+
+export default class AdminBallotService {
+    public static async getBallotStatuses(): Promise<string[]> {
+        return AdminService.getEnums('model-status');
+    }
+}
\ No newline at end of file
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Step1.vue b/main/resources/js/Pages/Dashboard/Ballots/Step1.vue
deleted file mode 100644
index eaeedca..0000000
--- a/main/resources/js/Pages/Dashboard/Ballots/Step1.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-<template>
-    <div class="flex flex-col">
-        <label for="title" class="mb-4 text-lg text-slate-600"
-        >Title</label
-        >
-        <input
-            v-model="formDataStore.formData.title"
-            type="text"
-            name="title"
-            id="title"
-            required
-            class="rounded-[10px] border-slate-400 p-4 w-[100%]"
-        />
-    </div>
-    <div class="flex flex-col">
-        <label for="description" class="my-4 text-lg text-slate-600"
-        >Description
-        </label>
-        <textarea
-            v-model="formDataStore.formData.description"
-            id="description"
-            required
-            class="rounded-[10px] border-slate-400 p-4 w-[100%] h-[150px]"
-        ></textarea>
-    </div>
-</template>
-
-<script setup lang="ts">
-import {useFormDataStore} from '@/stores/ballot-store';
-
-
-const formDataStore = useFormDataStore();
-
-formDataStore.updateFormData({
-    title: formDataStore.formData.title,
-    description: formDataStore.formData.description,
-});
-</script>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/Step4.vue b/main/resources/js/Pages/Dashboard/Ballots/Step4.vue
deleted file mode 100644
index bcd3a15..0000000
--- a/main/resources/js/Pages/Dashboard/Ballots/Step4.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-<template>
-    <button @click="submit" class="text-xl text-white font-semibold bg-primary-950 p-4 rounded-[15px]">Publish</button>
-</template>
-
-<script setup lang="ts">
-import {useFormDataStore} from '@/stores/ballot-store';
-
-
-const formDataStore = useFormDataStore();
-
-formDataStore.updateFormData({
-    publish: formDataStore.formData.publish
-});
-
-const submit = () => {
-    formDataStore.formData.publish = true
-}
-
-
-</script>
diff --git a/main/resources/js/Pages/Dashboard/Ballots/View.vue b/main/resources/js/Pages/Dashboard/Ballots/View.vue
new file mode 100644
index 0000000..37addc0
--- /dev/null
+++ b/main/resources/js/Pages/Dashboard/Ballots/View.vue
@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import AppLayout from '@/Layouts/AppLayout.vue';
+import BallotCard from "@/Pages/Dashboard/Ballots/Partials/BallotCard.vue";
+import BallotData = App.DataTransferObjects.BallotData;
+
+defineProps<{
+    ballot: BallotData;
+}>();
+</script>
+
+<template>
+
+    <AppLayout title="Dashboard">
+        <template #header>
+            <div class="flex flex-row justify-between">
+                <h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">Viewing
+                    <b>{{ ballot.title }}</b> 
+                    Ballot</h2>
+            </div>
+        </template>
+
+        <div class="py-12">
+            <div class="mx-auto space-y-6 max-w-7xl sm:px-6 lg:px-8">
+                <div class="flex gap-8 p-4 bg-white shadow sm:p-8 dark:bg-gray-800 sm:rounded-lg">
+                    <BallotCard :ballot="ballot" class="w-2/3 max-w-xl" />
+                </div>
+
+               
+            </div>
+        </div>
+    </AppLayout>
+</template>
diff --git a/main/resources/js/Pages/Dashboard/Home.vue b/main/resources/js/Pages/Dashboard/Home.vue
index 79f0c06..34b3321 100644
--- a/main/resources/js/Pages/Dashboard/Home.vue
+++ b/main/resources/js/Pages/Dashboard/Home.vue
@@ -1,6 +1,24 @@
 <template>
     <AppLayout title="Dashboard">
         <div class="py-12">
+
+            <div class="mx-auto max-w-7xl sm:px-6 lg:px-8 mb-8">
+                <div class="overflow-hidden bg-white shadow-xl dark:bg-gray-800 sm:rounded-lg">
+
+                    <div class="py-12">
+                        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
+                            <div class="sm:rounded-lg">
+                                <h2 class="font-semibold text-lg xl:text-xl text-gray-800 dark:text-gray-200 leading-tight mb-4">
+                                    Ballots
+                                </h2>
+                                <BallotList :ballots=props.ballots />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+
             <div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
                 <div class="overflow-hidden bg-white shadow-xl dark:bg-gray-800 sm:rounded-lg">
 
@@ -22,9 +40,11 @@
 <script setup lang="ts">
 import AppLayout from '@/Layouts/AppLayout.vue';
 import SnapshotList from "@/Pages/Dashboard/Snapshot/Partials/SnapshotList.vue";
+import BallotList from "@/Pages/Dashboard/Ballots/Partials/BallotList.vue"
 
 const props = defineProps<{
     snapshots: any;
+    ballots: any;
 }>();
 </script>
 
diff --git a/main/resources/js/Pages/Dashboard/Snapshot/Create.vue b/main/resources/js/Pages/Dashboard/Snapshot/Create.vue
index f148bd9..a63c9ca 100644
--- a/main/resources/js/Pages/Dashboard/Snapshot/Create.vue
+++ b/main/resources/js/Pages/Dashboard/Snapshot/Create.vue
@@ -37,7 +37,7 @@
  });
 
  const submit = () => {
-    form.post(route('dashboard.snapshot.store'), {
+    form.post(route('dashboard.snapshots.store'), {
     });
 
 }
diff --git a/main/resources/js/models/alert.ts b/main/resources/js/models/alert.ts
new file mode 100644
index 0000000..2befd38
--- /dev/null
+++ b/main/resources/js/models/alert.ts
@@ -0,0 +1,6 @@
+export default interface Alert{
+    message:string,
+    type :string,
+    show : boolean,
+    showTime?:number
+}
\ No newline at end of file
diff --git a/main/resources/js/shared/Services/admin-service.ts b/main/resources/js/shared/Services/admin-service.ts
new file mode 100644
index 0000000..1007204
--- /dev/null
+++ b/main/resources/js/shared/Services/admin-service.ts
@@ -0,0 +1,8 @@
+import axios from "axios";
+export default class AdminService {
+    public static async getEnums(collection: string): Promise<string[]> {
+        const response = await axios.get(route('dashboard.enums', { collection }));
+        return response.data;
+    }
+
+}
\ No newline at end of file
diff --git a/main/resources/js/shared/Services/alert.ts b/main/resources/js/shared/Services/alert.ts
new file mode 100644
index 0000000..ed001ff
--- /dev/null
+++ b/main/resources/js/shared/Services/alert.ts
@@ -0,0 +1,12 @@
+import { useGlobalAlert } from "@/stores/global-alert-store";
+import setAlert from "@/utils/alert";
+import axios from "axios";
+
+export default class AlertService {
+    static show(alerts: string [], type: string = 'info') {
+        const alertStore = useGlobalAlert();
+        for (const message of alerts) {
+            alertStore.showAlert(setAlert(message, type));
+        }
+    }
+}
diff --git a/main/resources/js/stores/ballot-store.ts b/main/resources/js/stores/ballot-store.ts
index 2b79f0a..d72dfb1 100644
--- a/main/resources/js/stores/ballot-store.ts
+++ b/main/resources/js/stores/ballot-store.ts
@@ -1,65 +1,67 @@
-import { defineStore } from 'pinia';
+import {defineStore} from 'pinia';
+import { ref, computed, watch} from 'vue';
 import {useStorage} from "@vueuse/core";
 
-type StepData = {
-  title?: string;
-  description?: string;
-  question?: string;
-  policy?: string;
-  publish?: boolean;
-};
+export const useBallotStore = defineStore('ballot-store', () => {
 
-export const useFormDataStore = defineStore('form',{
-  state: () => ({
-    step: 1,
-    formData: useStorage('form-data', {
-      title: '',
-      description: '',
-      question: '',
-      policy: '',
-      publish: false,
-    }),
-  }),
-  getters: {
-    currentStepData(state) {
-      const { step, formData } = state;
-      switch (step) {
-        case 1:
-          return {
-            title: formData.title,
-            description: formData.description ,
-          }
-        case 2:
-          return {
-            question: formData.question,
-          }
-        case 3:
-          return {
-            policy: formData.policy,
-          }
-        case 4:
-          return {
-            publish: formData.publish ,
-          }
-        default:
-          return {}
-      }
-    },
-  },
+  interface BallotData {
+      title?: string;
+      description?: string;
+      started_at?: string,
+      ended_at?: string,
+      status?: any,
+      question?: string;
+      policy?: string;
+      publish?: boolean;
+      hasQuestion?: boolean;
+      hasPolicy?: boolean;
+      isPublished?: boolean;
+    };
 
-  actions: {
-    updateFormData(data: Partial<StepData>) {
-      this.formData = { ...this.formData, ...data };
-    },
-    nextStep() {
-      this.step++;
-    },
-    prevStep() {
-      this.step--;
-    },
-  },
-}
-);
+  let formData = ref<object|null>(null);
+  let ballot = ref<BallotData|null>(null);
+  let step = ref<number>(1);
+
+  function uploadFormData(form: any)
+  {
+    formData.value = form;
+  }
+
+  function uploadBallotData(form: any)
+  {
+    ballot.value = form;
+  }
+
+  function setStep() {
+
+    if (ballot.value?.question && !ballot.value?.policy) {
+      step.value = 2;
+    } else if (ballot.value?.policy && !ballot.value?.publish){
+      step.value = 3;
+    }
+  }
+
+  // Next Step method
+  function nextStep() {
+      step.value++;
+  }
+
+  // Previous Step method
+  function previousStep() {
+      step.value--;
+  }
+
+  return {
+      formData,
+      ballot,
+      step,
+      setStep,
+      uploadFormData,
+      uploadBallotData,
+      nextStep,
+      previousStep,
+  }
+});
 
 
 
diff --git a/main/resources/js/stores/global-alert-store.ts b/main/resources/js/stores/global-alert-store.ts
new file mode 100644
index 0000000..f52e73e
--- /dev/null
+++ b/main/resources/js/stores/global-alert-store.ts
@@ -0,0 +1,25 @@
+import {defineStore} from 'pinia';
+import {computed, ref, Ref} from 'vue';
+import Alert from '@/models/alert';
+
+export const useGlobalAlert = defineStore('global-alert', () => {
+    let alerts: Ref<Alert[]> = ref([]);
+
+    function showAlert(alertModel: Alert) {
+        alerts.value = [...alerts.value,{...alertModel}];
+        setTimeout(() => {
+            alerts.value = [];
+        }, 5000);
+    }
+
+    function closeAlert(index:number) {
+        alerts.value.length==1 ? alerts.value = [] : alerts.value.splice(index, 1);
+    }
+
+    return {
+        showAlert,
+        closeAlert,
+        alerts
+    }
+});
+
diff --git a/main/resources/js/types/generated.d.ts b/main/resources/js/types/generated.d.ts
index 319bf8a..144d7cb 100644
--- a/main/resources/js/types/generated.d.ts
+++ b/main/resources/js/types/generated.d.ts
@@ -4,6 +4,7 @@ user_id: number;
 title: string;
 description: string;
 status: string;
+type: string;
 started_at: string;
 ended_at: string;
 };
diff --git a/main/resources/js/utils/alert.ts b/main/resources/js/utils/alert.ts
new file mode 100644
index 0000000..19d1bee
--- /dev/null
+++ b/main/resources/js/utils/alert.ts
@@ -0,0 +1,11 @@
+import Alert from "@/models/alert"
+
+function setAlert(message: string, type: string) {
+    let notification = {} as Alert
+    notification.message = message;
+    notification.type = type;
+    notification.show = true;
+    return notification;
+}
+
+export default setAlert;
diff --git a/main/routes/web.php b/main/routes/web.php
index 4abf509..e8c729f 100644
--- a/main/routes/web.php
+++ b/main/routes/web.php
@@ -8,7 +8,7 @@
 use Illuminate\Foundation\Application;
 use Illuminate\Support\Facades\Route;
 use Inertia\Inertia;
-
+use Illuminate\Support\Str;
 /*
 |--------------------------------------------------------------------------
 | Web Routes
@@ -55,7 +55,9 @@
 
         Route::post('/store', [BallotController::class, 'store'])->name('store');
 
-        Route::get('/edit', [BallotController::class, 'edit'])->name('edit');
+        Route::get('/view/{ballot}', [BallotController::class, 'view'])->name('view');
+
+        Route::get('/edit/{ballot}', [BallotController::class, 'edit'])->name('edit');
 
         Route::put('/update/{ballot}', [BallotController::class, 'update'])->name('update');
 
@@ -69,10 +71,17 @@
 
         Route::post('/store', [SnapshotController::class, 'store'])->name('store');
 
-        Route::get('/edit', [SnapshotCotroller::class, 'edit'])->name('edit');
+        Route::get('/edit', [SnapshotController::class, 'edit'])->name('edit');
 
         Route::put('/update/{snapshot}', [SnapshotController::class, 'update'])->name('');
 
         Route::delete('/delete/{snapshot}', [SnapshotController::class, 'delete'])->name('');
     });
+
+    Route::get('/enums/{collection}', function () {
+        $collection = request()->route('collection');
+        $collection = 'App\\Enums\\' . Str::studly($collection). 'Enum';
+
+        return array_column($collection::cases(), 'value', 'name');
+    })->name('enums');
 });
-- 
GitLab


From aee0f92742cd18d872233c1a36970c6c44300028 Mon Sep 17 00:00:00 2001
From: ciraganenicole <ciraganenicole@gmail.com>
Date: Wed, 4 Oct 2023 09:02:50 +0200
Subject: [PATCH 2/2] Update the button colors

---
 main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue
index 826b31a..945ee53 100644
--- a/main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue
+++ b/main/resources/js/Pages/Dashboard/Ballots/Partials/Step1.vue
@@ -98,7 +98,7 @@
             <div class="flex-shrink-0">
                 <button 
                 type="submit" 
-                class="inline-flex items-center px-3 py-2 text-sm font-semibold text-white bg-primary-950 rounded-md shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
+                class="inline-flex items-center px-3 py-2 text-sm font-semibold text-white bg-primary-950 rounded-md shadow-sm hover:bg-primary-50 hover:text-black focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
                 {{ ballot ? 'Edit' : 'Create' }}
             </button>
             </div>
-- 
GitLab