Skip to content

Commit

Permalink
feat: adding import/export capability
Browse files Browse the repository at this point in the history
  • Loading branch information
moebiusmania committed May 12, 2024
1 parent b440a53 commit 1f863a2
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 23 deletions.
60 changes: 60 additions & 0 deletions src/components/Backup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script setup lang="ts">
import { useMainStore } from "./../store";
import { save } from "./../libs/storage";
const app = useMainStore();
const i18n = app.i18n.backup;
const btns = "btn btn-neutral w-full md:w-1/2 lg:w-1/3";
const exportData = (): void => {
const data = app.getState.data;
const json = JSON.stringify(data);
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.id = "download";
a.href = url;
a.download = "subscriptions.json";
a.click();
URL.revokeObjectURL(url);
document.getElementById("download")?.remove();
};
const importData = (): void => {
const input = document.createElement("input");
input.id = "upload";
input.type = "file";
input.accept = ".json";
input.onchange = (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const content = e.target?.result;
if (typeof content === "string") {
const data = JSON.parse(content);
app.importSubs(data);
save(app.getState);
}
};
reader.readAsText(file);
}
};
input.click();
document.getElementById("upload")?.remove();
};
</script>

<template>
<section class="mt-8 flex flex-col md:flex-row justify-between gap-4">
<button :class="btns" @click="exportData">↓ {{ i18n.export }}</button>

<button :class="btns" @click="importData">↑ {{ i18n.import }}</button>
</section>
</template>
6 changes: 3 additions & 3 deletions src/components/Empty.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ const useMock = (): void => {
</p>
<div class="mt-10 md:flex md:justify-center">
<router-link to="/add" class="btn btn-accent w-full md:w-1/2 lg:w-1/3">
Let's track some subscriptions!
Let's track some subscriptions!
</router-link>
<div class="divider">OR</div>
<button class="btn w-full md:w-1/2 lg:w-1/3" @click="useMock">
Use the example data
<button class="btn btn-neutral w-full md:w-1/2 lg:w-1/3" @click="useMock">
✏️ Use the example data
</button>
</div>
</Container>
Expand Down
59 changes: 48 additions & 11 deletions src/components/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,78 @@ const onSubmit = (event: Event): void => {
<template>
<form @submit="onSubmit">
<label for="name" class="label">Service name:</label>
<input type="text" placeholder="ex: Netflix, Prime, etc.." class="input w-full input-bordered" name="name"
v-model="data.name" required />
<input
type="text"
placeholder="ex: Netflix, Prime, etc.."
class="input w-full input-bordered"
name="name"
v-model="data.name"
required
/>

<label for="price" class="label">How much does it costs?</label>
<input type="number" placeholder="10.00" class="input w-full input-bordered" min="0.1" step="0.1"
:value="data.price.toString()" @input="updatePrice" name="price" required />
<input
type="number"
placeholder="10.00"
class="input w-full input-bordered"
min="0.1"
step="0.1"
:value="data.price.toString()"
@input="updatePrice"
name="price"
required
/>

<label for="currency" class="label">Currency:</label>
<select class="select select-bordered w-full" required name="currency" v-model="data.currency" disabled>
<select
class="select select-bordered w-full"
required
name="currency"
v-model="data.currency"
disabled
>
<option value="">€ Euro</option>
<option value="$">$ Dollar</option>
</select>

<label class="label cursor-pointer" for="isactive">
<span>Is active?</span>
<input type="checkbox" class="toggle" name="isactive" v-model="data.isActive" />
<input
type="checkbox"
class="toggle"
name="isactive"
v-model="data.isActive"
/>
</label>

<label for="expiration" class="label">Date of expiration:</label>
<input type="date" class="input w-full input-bordered" required name="expiration"
:value="formatDate(data.expiration)" @input="updateExpiration" />
<input
type="date"
class="input w-full input-bordered"
required
name="expiration"
:value="formatDate(data.expiration)"
@input="updateExpiration"
/>

<label for="recurrence" class="label">Recurs:</label>
<select class="select select-bordered w-full" required name="recurrence" v-model="data.recurrence">
<select
class="select select-bordered w-full"
required
name="recurrence"
v-model="data.recurrence"
>
<option value="monthly">Monthly</option>
<option value="yearly">Yearly</option>
</select>

<div class="mt-7 flex flex-col gap-5 md:flex-row md: justify-between">
<button class="btn btn-accent w-full md:w-1/2 lg:w-1/3">
Add this subscription
Add this subscription
</button>

<router-link to="/" class="btn w-full md:w-1/2 lg:w-1/3">
Go back to the main screen
Go back to the main screen
</router-link>
</div>
</form>
Expand Down
20 changes: 15 additions & 5 deletions src/components/List.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@ import { useMainStore } from "./../store";
import { save } from "./../libs/storage";
import Container from "./Container.vue";
import Backup from "./Backup.vue";
const app = useMainStore();
const i18n = app.i18n.main;
const fbText = "Sure you want to delete all subscriptions data?";
defineProps<{
data: Subscription[];
}>();
const ask = (message: string): boolean => {
return confirm(message);
};
const deleteAll = (): void => {
app.deleteSubs();
save(app.getState);
if (ask(fbText)) {
app.deleteSubs();
save(app.getState);
}
};
const toggleActive = (index: number): void => {
Expand All @@ -30,7 +38,7 @@ const toggleActive = (index: number): void => {
>
<h2 class="font-sans text-2xl font-bold">{{ i18n.list }}</h2>
<router-link to="/add" class="btn btn-accent w-full md:w-max">
{{ i18n.cta }}
{{ i18n.cta }}
</router-link>
</header>
<section
Expand All @@ -52,14 +60,16 @@ const toggleActive = (index: number): void => {
{{ item.name }}
</h2>
<p>
{{ item.price + item.currency }}, {{ item.recurrence }} - {{ i18n.expires }}
{{ item.price + item.currency }}, {{ item.recurrence }} -
{{ i18n.expires }}
{{ new Date(item.expiration).toLocaleDateString() }}
</p>
</div>
</article>
</section>
<Backup />
<button class="btn w-full mt-7 btn-error modal-button" @click="deleteAll">
{{ i18n.delete }}
{{ i18n.delete }}
</button>
</Container>
</template>
4 changes: 4 additions & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@
"cta": "Let's track some subscriptions!",
"or": "or",
"default": "Use the example data"
},
"backup": {
"export": "Export the data",
"import": "Import data"
}
}
12 changes: 8 additions & 4 deletions src/libs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type Subscription = {
};

export type I18n = {
main : {
main: {
title: string;
total: string;
inactives: string;
Expand All @@ -19,15 +19,19 @@ export type I18n = {
cta: string;
expires: string;
delete: string;
},
};
empty: {
title: string;
message: string;
cta: string;
or: string;
default: string;
}
}
};
backup: {
export: string;
import: string;
};
};

export type AppState = {
locale: string;
Expand Down
3 changes: 3 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export const useMainStore = defineStore("app", {
deleteSubs(): void {
this.data = [];
},
importSubs(data: Subscription[]): void {
this.data = data;
},
setState({ locale, theme, currency, data }: AppState): void {
console.log(theme);
this.locale = locale;
Expand Down

0 comments on commit 1f863a2

Please sign in to comment.