Skip to content

Commit 927cf65

Browse files
committed
feat:Implement sync logic between tabs with localestorage
1 parent 78ea6fa commit 927cf65

File tree

3 files changed

+60
-43
lines changed

3 files changed

+60
-43
lines changed

src/composables/posts.composable.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default function useFetchPost() {
88

99
const post = ref(null);
1010

11-
function fetchPost(id) {
11+
async function fetchPost (id) {
1212
const cachedPosts = StorageService.get("cached-posts") || {};
1313

1414
if (cachedPosts[`post-${id}`]) {

src/services/storage.service.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ class StorageService {
4141
static has(name) {
4242
return Boolean(this.get(name));
4343
}
44+
45+
static observe(eventKey , callback){
46+
window.addEventListener('storage',(event)=>{
47+
if(event.key === eventKey && event.newValue !==null) {
48+
callback(JSON.parse(event.newValue))
49+
}
50+
})
51+
}
4452
}
4553

4654
export default StorageService;

src/views/CommentsView.vue

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div class="h3 mb-4">{{ $t('Comments') }}</div>
2+
<div class="h3 mb-4">{{ $t("Comments") }}</div>
33
<CommentsFilterForm class="mb-4" v-model="filters" />
44
<VTableServer :items="comments" :itemsLength="comments.length" :is-loading="commentsIsLoading">
55
<VColumn :header="$t('Id')" field="id">
@@ -29,13 +29,13 @@
2929
<VColumn :header="$t('Status')" field="id">
3030
<template #body="{ item }">
3131
<span v-if="item.status === 'PENDING'">
32-
{{ $t('Pending') }}
32+
{{ $t("Pending") }}
3333
</span>
3434
<span v-if="item.status === 'CONFIRMED'">
35-
{{ $t('Confirmed') }}
35+
{{ $t("Confirmed") }}
3636
</span>
3737
<span v-if="item.status === 'REJECTED'">
38-
{{ $('Rejected') }}
38+
{{ $("Rejected") }}
3939
</span>
4040
</template>
4141
</VColumn>
@@ -54,60 +54,70 @@
5454
</VColumn>
5555
</VTableServer>
5656
<VModal v-model="postModalIsOpen">
57-
<div v-if="postIsLoading">
58-
Loading...
59-
</div>
57+
<div v-if="postIsLoading">Loading...</div>
6058
<h1 v-if="!postIsLoading && post !== null">
6159
{{ post.title }}
6260
</h1>
6361
</VModal>
6462
</template>
6563

6664
<script>
67-
import CommentsFilterForm from '@/components/comments/CommentsFilterForm.vue';
68-
import VColumn from '@/components/data-table/VColumn.vue';
69-
import VTableServer from '@/components/data-table/VTableServer.vue';
70-
import VModal from '@/components/VModal.vue';
71-
import { useFetchComments } from '@/composables/comments.composable';
72-
import { useApplyFilters } from '@/composables/filter.composable';
73-
import useFetchPost from '@/composables/posts.composable';
74-
import { computed, ref } from 'vue';
65+
import CommentsFilterForm from "@/components/comments/CommentsFilterForm.vue";
66+
import VColumn from "@/components/data-table/VColumn.vue";
67+
import VTableServer from "@/components/data-table/VTableServer.vue";
68+
import VModal from "@/components/VModal.vue";
69+
import { useFetchComments } from "@/composables/comments.composable";
70+
import { useApplyFilters } from "@/composables/filter.composable";
71+
import useFetchPost from "@/composables/posts.composable";
72+
import StorageService from "@/services/storage.service";
73+
import { computed, ref, watch } from "vue";
7574
7675
export default {
77-
name: 'CommentsView',
76+
name: "CommentsView",
7877
setup() {
79-
const { comments, commentsIsLoading, fetchComments } = useFetchComments()
80-
fetchComments({})
81-
82-
const { post, postIsLoading, fetchPost } = useFetchPost()
83-
const postModalIsOpen = ref(false)
78+
const { comments, commentsIsLoading, fetchComments } = useFetchComments();
79+
fetchComments({});
8480
81+
const { post, postIsLoading, fetchPost } = useFetchPost();
82+
const postModalIsOpen = ref(false);
8583
const handleFetchPost = async (id) => {
8684
try {
87-
postModalIsOpen.value = true
88-
await fetchPost(id)
85+
postModalIsOpen.value = true;
86+
await fetchPost(id);
8987
} catch {
90-
postModalIsOpen.value = false
88+
postModalIsOpen.value = false;
9189
}
90+
};
9291
93-
94-
}
92+
const syncedFilters = StorageService.get("synced-filters");
9593
9694
const filters = useApplyFilters({
97-
searchQuery: undefined,
98-
status: undefined,
99-
email: undefined
95+
searchQuery: syncedFilters?.searchQuery || undefined,
96+
status: syncedFilters?.status || undefined,
97+
email: syncedFilters?.email || undefined,
98+
});
99+
100+
watch(filters, (newFilters) => {
101+
StorageService.set('synced-filters',{...filters,...newFilters})
102+
}, { immediate: true })
103+
104+
StorageService.observe("synced-filters", (newValue) => {
105+
filters.searchQuery = newValue?.searchQuery || undefined;
106+
filters.email = newValue?.email || undefined;
107+
filters.status = newValue?.status || undefined
100108
});
101109
102110
const filteredComments = computed(() => {
103111
const enteredEmail = filters?.email && filters.email.trim().toLowerCase();
104-
const query = filters?.searchQuery && isNaN(Number(filters.searchQuery)) ? filters.searchQuery.trim().toLowerCase() : filters.searchQuery;
112+
const query =
113+
filters?.searchQuery && isNaN(Number(filters.searchQuery)) ? filters.searchQuery.trim().toLowerCase() : filters.searchQuery;
105114
const status = filters?.status && filters.status.trim();
106115
107-
const matchesEmail = (email) => enteredEmail && email.trim().toLowerCase().includes(enteredEmail)
108-
const matchesQuery = (id, body, name) => id === Number(query) || body.trim().toLowerCase().includes(query) || name.trim().toLowerCase().includes(query)
116+
const matchesEmail = (email) => enteredEmail && email.trim().toLowerCase().includes(enteredEmail);
117+
const matchesQuery = (id, body, name) =>
118+
id === Number(query) || body.trim().toLowerCase().includes(query) || name.trim().toLowerCase().includes(query);
109119
110-
return comments.value?.filter(comment => {
120+
return comments.value?.filter((comment) => {
111121
if (!query && !enteredEmail && !status) return true;
112122
return matchesEmail(comment.email) || matchesQuery(comment.id, comment.body, comment.name) || status === comment.status;
113123
});
@@ -117,10 +127,9 @@ export default {
117127
const query = filters?.searchQuery && isNaN(Number(filters.searchQuery)) ? filters.searchQuery.trim().toLowerCase() : undefined;
118128
119129
if (!query) return text;
120-
const regex = new RegExp(`(${query})`, 'gi');
121-
return String(text).replace(regex, '<mark>$1</mark>');
122-
123-
}
130+
const regex = new RegExp(`(${query})`, "gi");
131+
return String(text).replace(regex, "<mark>$1</mark>");
132+
};
124133
125134
return {
126135
comments: filteredComments,
@@ -130,14 +139,14 @@ export default {
130139
post,
131140
postIsLoading,
132141
handleFetchPost,
133-
postModalIsOpen
134-
}
142+
postModalIsOpen,
143+
};
135144
},
136145
components: {
137146
VTableServer,
138147
VColumn,
139148
CommentsFilterForm,
140-
VModal
141-
}
142-
}
149+
VModal,
150+
},
151+
};
143152
</script>

0 commit comments

Comments
 (0)