Skip to content

Commit 93c2df4

Browse files
feat: Shopping list UI overhaul - three dot menu (#4415)
Co-authored-by: Kuchenpirat <[email protected]>
1 parent 1e69577 commit 93c2df4

File tree

2 files changed

+183
-169
lines changed

2 files changed

+183
-169
lines changed

frontend/pages/shopping-lists/_id.vue

+92-160
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,69 @@
1717
<v-container>
1818
<v-row>
1919
<v-col cols="3" class="text-left">
20-
<ButtonLink :to="`/shopping-lists?disableRedirect=true`" :text="$tc('general.back')" :icon="$globals.icons.backArrow" />
20+
<ButtonLink :to="`/shopping-lists?disableRedirect=true`" :text="$tc('shopping-list.all-lists')" :icon="$globals.icons.backArrow" />
2121
</v-col>
22-
<v-col cols="6" class="d-flex justify-center">
22+
<v-col cols="6" class="d-none d-lg-flex justify-center">
2323
<v-img max-height="100" max-width="100" :src="require('~/static/svgs/shopping-cart.svg')"></v-img>
2424
</v-col>
25+
<v-col class="d-flex justify-end">
26+
<BaseButtonGroup
27+
:buttons="[
28+
{
29+
icon: $globals.icons.contentCopy,
30+
text: '',
31+
event: 'edit',
32+
children: [
33+
{
34+
icon: $globals.icons.contentCopy,
35+
text: $tc('shopping-list.copy-as-text'),
36+
event: 'copy-plain',
37+
},
38+
{
39+
icon: $globals.icons.contentCopy,
40+
text: $tc('shopping-list.copy-as-markdown'),
41+
event: 'copy-markdown',
42+
},
43+
],
44+
},
45+
{
46+
icon: $globals.icons.checkboxOutline,
47+
text: $tc('shopping-list.check-all-items'),
48+
event: 'check',
49+
},
50+
{
51+
icon: $globals.icons.dotsVertical,
52+
text: '',
53+
event: 'three-dot',
54+
children: [
55+
{
56+
icon: $globals.icons.tags,
57+
text: $tc('shopping-list.toggle-label-sort'),
58+
event: 'sort-by-labels',
59+
},
60+
{
61+
icon: $globals.icons.tags,
62+
text: $tc('shopping-list.reorder-labels'),
63+
event: 'reorder-labels',
64+
},
65+
{
66+
icon: $globals.icons.tags,
67+
text: $tc('shopping-list.manage-labels'),
68+
event: 'manage-labels',
69+
},
70+
],
71+
},
72+
]"
73+
@edit="edit = true"
74+
@three-dot="threeDot = true"
75+
@check="openCheckAll"
76+
@sort-by-labels="sortByLabels"
77+
@copy-plain="copyListItems('plain')"
78+
@copy-markdown="copyListItems('markdown')"
79+
@reorder-labels="toggleReorderLabelsDialog()"
80+
@manage-labels="$router.push(`/group/data/labels`)"
81+
/>
82+
</v-col>
2583
</v-row>
2684
</v-container>
2785
</template>
@@ -119,27 +177,6 @@
119177
</v-card>
120178
</BaseDialog>
121179

122-
<!-- Settings -->
123-
<BaseDialog
124-
v-model="settingsDialog"
125-
:icon="$globals.icons.cog"
126-
:title="$t('general.settings')"
127-
@confirm="updateSettings"
128-
>
129-
<v-container>
130-
<v-form>
131-
<v-select
132-
v-model="currentUserId"
133-
:items="allUsers"
134-
item-text="fullName"
135-
item-value="id"
136-
:label="$t('general.owner')"
137-
:prepend-icon="$globals.icons.user"
138-
/>
139-
</v-form>
140-
</v-container>
141-
</BaseDialog>
142-
143180
<!-- Create Item -->
144181
<div v-if="createEditorOpen">
145182
<ShoppingListItemEditor
@@ -154,78 +191,41 @@
154191
/>
155192
</div>
156193
<div v-else class="mt-4 d-flex justify-end">
157-
<BaseButton
158-
v-if="preferences.viewByLabel" edit class="mr-2"
159-
:disabled="$nuxt.isOffline"
160-
@click="toggleReorderLabelsDialog">
161-
<template #icon> {{ $globals.icons.tags }} </template>
162-
{{ $t('shopping-list.reorder-labels') }}
163-
</BaseButton>
164194
<BaseButton create @click="createEditorOpen = true" > {{ $t('general.add') }} </BaseButton>
165195
</div>
166196

167-
<!-- Action Bar -->
168-
<div class="d-flex justify-end mb-4 mt-2">
169-
<BaseButtonGroup
170-
:buttons="[
171-
{
172-
icon: $globals.icons.contentCopy,
173-
text: '',
174-
event: 'edit',
175-
children: [
176-
{
177-
icon: $globals.icons.contentCopy,
178-
text: $tc('shopping-list.copy-as-text'),
179-
event: 'copy-plain',
180-
},
181-
{
182-
icon: $globals.icons.contentCopy,
183-
text: $tc('shopping-list.copy-as-markdown'),
184-
event: 'copy-markdown',
185-
},
186-
],
187-
},
188-
{
189-
icon: $globals.icons.delete,
190-
text: $tc('shopping-list.delete-checked'),
191-
event: 'delete',
192-
},
193-
{
194-
icon: $globals.icons.tags,
195-
text: $tc('shopping-list.toggle-label-sort'),
196-
event: 'sort-by-labels',
197-
},
198-
{
199-
icon: $globals.icons.checkboxBlankOutline,
200-
text: $tc('shopping-list.uncheck-all-items'),
201-
event: 'uncheck',
202-
},
203-
{
204-
icon: $globals.icons.checkboxOutline,
205-
text: $tc('shopping-list.check-all-items'),
206-
event: 'check',
207-
},
208-
]"
209-
@edit="edit = true"
210-
@delete="openDeleteChecked"
211-
@uncheck="openUncheckAll"
212-
@check="openCheckAll"
213-
@sort-by-labels="sortByLabels"
214-
@copy-plain="copyListItems('plain')"
215-
@copy-markdown="copyListItems('markdown')"
216-
/>
217-
</div>
218-
219197
<!-- Checked Items -->
220198
<div v-if="listItems.checked && listItems.checked.length > 0" class="mt-6">
221-
<button @click="toggleShowChecked()">
222-
<span>
223-
<v-icon>
224-
{{ showChecked ? $globals.icons.chevronDown : $globals.icons.chevronRight }}
225-
</v-icon>
226-
</span>
227-
{{ $tc('shopping-list.items-checked-count', listItems.checked ? listItems.checked.length : 0) }}
228-
</button>
199+
<div class="d-flex">
200+
<div class="flex-grow-1">
201+
<button @click="toggleShowChecked()">
202+
<span>
203+
<v-icon>
204+
{{ showChecked ? $globals.icons.chevronDown : $globals.icons.chevronRight }}
205+
</v-icon>
206+
</span>
207+
{{ $tc('shopping-list.items-checked-count', listItems.checked ? listItems.checked.length : 0) }}
208+
</button>
209+
</div>
210+
<div class="justify-end mt-n2">
211+
<BaseButtonGroup
212+
:buttons="[
213+
{
214+
icon: $globals.icons.checkboxBlankOutline,
215+
text: $tc('shopping-list.uncheck-all-items'),
216+
event: 'uncheck',
217+
},
218+
{
219+
icon: $globals.icons.delete,
220+
text: $tc('shopping-list.delete-checked'),
221+
event: 'delete',
222+
},
223+
]"
224+
@uncheck="openUncheckAll"
225+
@delete="openDeleteChecked"
226+
/>
227+
</div>
228+
</div>
229229
<v-divider class="my-4"></v-divider>
230230
<v-expand-transition>
231231
<div v-show="showChecked">
@@ -277,29 +277,6 @@
277277
</RecipeList>
278278
</section>
279279
</v-lazy>
280-
281-
<v-lazy>
282-
<div class="d-flex justify-end">
283-
<BaseButton
284-
edit
285-
:disabled="$nuxt.isOffline"
286-
@click="toggleSettingsDialog"
287-
>
288-
<template #icon> {{ $globals.icons.cog }} </template>
289-
{{ $t('general.settings') }}
290-
</BaseButton>
291-
</div>
292-
</v-lazy>
293-
294-
<v-lazy>
295-
<div v-if="$nuxt.isOnline" class="d-flex justify-end mt-10">
296-
<ButtonLink
297-
:to="`/group/data/labels`"
298-
:text="$tc('shopping-list.manage-labels')"
299-
:icon="$globals.icons.tags"
300-
/>
301-
</div>
302-
</v-lazy>
303280
<WakelockSwitch/>
304281
</v-container>
305282
</template>
@@ -314,7 +291,6 @@ import { useUserApi } from "~/composables/api";
314291
import MultiPurposeLabelSection from "~/components/Domain/ShoppingList/MultiPurposeLabelSection.vue"
315292
import ShoppingListItem from "~/components/Domain/ShoppingList/ShoppingListItem.vue";
316293
import { ShoppingListItemOut, ShoppingListMultiPurposeLabelOut, ShoppingListOut } from "~/lib/api/types/household";
317-
import { UserOut } from "~/lib/api/types/user";
318294
import RecipeList from "~/components/Domain/Recipe/RecipeList.vue";
319295
import ShoppingListItemEditor from "~/components/Domain/ShoppingList/ShoppingListItemEditor.vue";
320296
import { useFoodStore, useLabelStore, useUnitStore } from "~/composables/store";
@@ -349,8 +325,8 @@ export default defineComponent({
349325
const userApi = useUserApi();
350326
351327
const edit = ref(false);
328+
const threeDot = ref(false);
352329
const reorderLabelsDialog = ref(false);
353-
const settingsDialog = ref(false);
354330
const preserveItemOrder = ref(false);
355331
356332
const route = useRoute();
@@ -678,13 +654,6 @@ export default defineComponent({
678654
localLabels.value = shoppingList.value?.labelSettings
679655
}
680656
681-
async function toggleSettingsDialog() {
682-
if (!settingsDialog.value) {
683-
await fetchAllUsers();
684-
}
685-
settingsDialog.value = !settingsDialog.value;
686-
}
687-
688657
function updateLabelOrder(labelSettings: ShoppingListMultiPurposeLabelOut[]) {
689658
if (!shoppingList.value) {
690659
return;
@@ -1064,39 +1033,6 @@ export default defineComponent({
10641033
refresh();
10651034
}
10661035
1067-
// ===============================================================
1068-
// Shopping List Settings
1069-
1070-
const allUsers = ref<UserOut[]>([]);
1071-
const currentUserId = ref<string | undefined>();
1072-
async function fetchAllUsers() {
1073-
const { data } = await userApi.households.fetchMembers();
1074-
if (!data) {
1075-
return;
1076-
}
1077-
1078-
// update current user
1079-
allUsers.value = data.items.sort((a, b) => ((a.fullName || "") < (b.fullName || "") ? -1 : 1));
1080-
currentUserId.value = shoppingList.value?.userId;
1081-
}
1082-
1083-
async function updateSettings() {
1084-
if (!shoppingList.value || !currentUserId.value) {
1085-
return;
1086-
}
1087-
1088-
loadingCounter.value += 1;
1089-
const { data } = await userApi.shopping.lists.updateOne(
1090-
shoppingList.value.id,
1091-
{...shoppingList.value, userId: currentUserId.value},
1092-
);
1093-
loadingCounter.value -= 1;
1094-
1095-
if (data) {
1096-
refresh();
1097-
}
1098-
}
1099-
11001036
return {
11011037
...toRefs(state),
11021038
addRecipeReferenceToList,
@@ -1112,6 +1048,7 @@ export default defineComponent({
11121048
openDeleteChecked,
11131049
deleteListItem,
11141050
edit,
1051+
threeDot,
11151052
getLabelColor,
11161053
groupSlug,
11171054
itemsByLabel,
@@ -1123,8 +1060,6 @@ export default defineComponent({
11231060
removeRecipeReferenceToList,
11241061
reorderLabelsDialog,
11251062
toggleReorderLabelsDialog,
1126-
settingsDialog,
1127-
toggleSettingsDialog,
11281063
localLabels,
11291064
updateLabelOrder,
11301065
cancelLabelOrder,
@@ -1144,9 +1079,6 @@ export default defineComponent({
11441079
updateIndexUncheckedByLabel,
11451080
allUnits,
11461081
allFoods,
1147-
allUsers,
1148-
currentUserId,
1149-
updateSettings,
11501082
getTextColor,
11511083
};
11521084
},

0 commit comments

Comments
 (0)