chore: migrate remaining pages to script setup (#7310)

This commit is contained in:
Kuchenpirat
2026-03-24 16:07:08 +01:00
committed by GitHub
parent 27cb585c80
commit 18b3c4beab
57 changed files with 4160 additions and 4971 deletions

View File

@@ -100,6 +100,7 @@ const {
usernameErrorMessages,
validateUsername,
validateEmail,
domAccountForm,
} = useUserRegistrationForm();
</script>

View File

@@ -21,5 +21,6 @@ export default withNuxt({
],
"vue/no-mutating-props": "error",
"vue/no-v-html": "error",
"vue/component-api-style": ["error", ["script-setup"]],
},
});

View File

@@ -48,17 +48,16 @@
</v-app>
</template>
<script lang="ts">
<script setup lang="ts">
import { useGlobalI18n } from "~/composables/use-global-i18n";
export default defineNuxtComponent({
props: {
const props = defineProps({
error: {
type: Object,
default: null,
},
},
setup(props) {
});
definePageMeta({
layout: "basic",
});
@@ -132,13 +131,6 @@ export default defineNuxtComponent({
const buttons = [
{ icon: $globals.icons.home, to: "/", text: i18n.t("general.home") },
];
return {
buttons,
ready,
};
},
});
</script>
<style scoped>

View File

@@ -1,9 +1,9 @@
<template>
<NuxtPage />
</template>
<script setup lang="ts">
definePageMeta({
middleware: ["admin-only"],
});
</script>
<template>
<NuxtPage />
</template>

View File

@@ -3,7 +3,7 @@
<section>
<!-- Delete Dialog -->
<BaseDialog
v-model="deleteDialog"
v-model="state.deleteDialog"
:title="$t('settings.backup.delete-backup')"
color="error"
:icon="$globals.icons.alertCircle"
@@ -17,7 +17,7 @@
<!-- Import Dialog -->
<BaseDialog
v-model="importDialog"
v-model="state.importDialog"
color="error"
:title="$t('settings.backup.backup-restore')"
:icon="$globals.icons.database"
@@ -40,7 +40,7 @@
</p>
<v-checkbox
v-model="confirmImport"
v-model="state.confirmImport"
class="checkbox-top"
color="error"
hide-details
@@ -50,7 +50,7 @@
<v-card-actions class="justify-center pt-0">
<BaseButton
delete
:disabled="!confirmImport || runningRestore"
:disabled="!state.confirmImport || state.runningRestore"
@click="restoreBackup(selected)"
>
<template #icon>
@@ -63,7 +63,7 @@
{{ selected }}
</p>
<v-progress-linear
v-if="runningRestore"
v-if="state.runningRestore"
indeterminate
/>
</BaseDialog>
@@ -81,7 +81,7 @@
>
<BaseButton
class="mr-2"
:loading="runningBackup"
:loading="state.runningBackup"
@click="createBackup"
>
{{ $t("settings.backup.create-heading") }}
@@ -96,13 +96,13 @@
</v-toolbar>
<v-data-table
:headers="headers"
:headers="state.headers"
:items="backups.imports || []"
class="elevation-0"
:items-per-page="-1"
hide-default-footer
disable-pagination
:search="search"
:search="state.search"
@click:row="setSelected"
>
<template #[`item.date`]="{ item }">
@@ -115,7 +115,7 @@
color="error"
variant="text"
@click.stop="
deleteDialog = true;
state.deleteDialog = true;
deleteTarget = item.name;
"
>
@@ -130,7 +130,7 @@
/>
<BaseButton
small
@click.stop="setSelected(item); importDialog = true"
@click.stop="setSelected(item); state.importDialog = true"
>
<template #icon>
{{ $globals.icons.backupRestore }}
@@ -151,21 +151,16 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useAdminApi } from "~/composables/api";
import type { AllBackups } from "~/lib/api/types/admin";
import { alert } from "~/composables/use-toast";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "admin",
});
const i18n = useI18n();
const auth = useMealieAuth();
const route = useRoute();
const groupSlug = computed(() => route.params.groupSlug || auth.user.value?.groupSlug || "");
const adminApi = useAdminApi();
const selected = ref("");
@@ -256,25 +251,8 @@ export default defineNuxtComponent({
onMounted(refreshBackups);
return {
groupSlug,
restoreBackup,
selected,
...toRefs(state),
backups,
createBackup,
deleteBackup,
deleteTarget,
setSelected,
refreshBackups,
backupsFileNameDownload,
};
},
head() {
return {
title: useI18n().t("sidebar.backups"),
};
},
useHead({
title: i18n.t("sidebar.backups"),
});
</script>

View File

@@ -83,12 +83,10 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useAdminApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "admin",
});
@@ -104,7 +102,6 @@ export default defineNuxtComponent({
const loading = ref(false);
const response = ref("");
const uploadForm = ref<VForm | null>(null);
const uploadedImage = ref<Blob | File>();
const uploadedImageName = ref<string>("");
const uploadedImagePreviewUrl = ref<string>();
@@ -135,17 +132,4 @@ export default defineNuxtComponent({
response.value = data.response || (data.success ? "Test Successful" : "Test Failed");
}
}
return {
loading,
response,
uploadForm,
uploadedImage,
uploadedImagePreviewUrl,
uploadImage,
clearImage,
testOpenAI,
};
},
});
</script>

View File

@@ -11,7 +11,7 @@
<div class="d-flex align-center justify-center justify-md-start flex-wrap">
<v-btn-toggle
v-model="parser"
v-model="state.parser"
density="compact"
mandatory="force"
@change="processIngredient"
@@ -38,7 +38,7 @@
<v-card flat>
<v-card-text>
<v-text-field
v-model="ingredient"
v-model="state.ingredient"
:label="$t('admin.ingredient-text')"
/>
</v-card-text>
@@ -55,9 +55,9 @@
</v-card-actions>
</v-card>
</v-container>
<v-container v-if="results">
<v-container v-if="state.results">
<div
v-if="parser !== 'brute' && getConfidence('average')"
v-if="state.parser !== 'brute' && getConfidence('average')"
class="d-flex"
>
<v-chip
@@ -111,7 +111,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { alert } from "~/composables/use-toast";
import { useUserApi } from "~/composables/api";
import type { IngredientConfidence } from "~/lib/api/types/recipe";
@@ -119,8 +119,6 @@ import type { Parser } from "~/lib/api/user/recipes/recipe";
type ConfidenceAttribute = "average" | "comment" | "name" | "unit" | "quantity" | "food";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "admin",
});
@@ -254,20 +252,6 @@ export default defineNuxtComponent({
});
const showConfidence = ref(false);
return {
showConfidence,
getColor,
confidence,
getConfidence,
...toRefs(state),
tryText,
properties,
processTryText,
processIngredient,
};
},
});
</script>
<style scoped></style>

View File

@@ -96,12 +96,10 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useAdminApi } from "~/composables/api";
import type { MaintenanceStorageDetails, MaintenanceSummary } from "~/lib/api/types/admin";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "admin",
});
@@ -228,18 +226,6 @@ export default defineNuxtComponent({
subtitle: i18n.t("admin.maintenance.action-clean-images-description"),
},
];
return {
storageDetailsText,
openDetails,
storageDetails,
state,
info,
getSummary,
actions,
};
},
});
</script>
<style scoped>

View File

@@ -49,20 +49,15 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import GroupPreferencesEditor from "~/components/Domain/Group/GroupPreferencesEditor.vue";
import { useAdminApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import type { VForm } from "vuetify/components";
export default defineNuxtComponent({
components: {
GroupPreferencesEditor,
},
setup() {
definePageMeta({
layout: "admin",
});
const route = useRoute();
const i18n = useI18n();
@@ -108,13 +103,4 @@ export default defineNuxtComponent({
alert.error(i18n.t("settings.settings-update-failed"));
}
}
return {
group,
userError,
refGroupEditForm,
handleSubmit,
};
},
});
</script>

View File

@@ -1,28 +1,28 @@
<template>
<v-container fluid>
<BaseDialog
v-model="createDialog"
v-model="state.createDialog"
:title="$t('group.create-group')"
:icon="$globals.icons.group"
can-submit
@submit="createGroup(createGroupForm.data)"
@submit="createGroup(state.createGroupForm.data)"
>
<template #activator />
<v-card-text>
<AutoForm
v-model="createGroupForm.data"
:update-mode="updateMode"
:items="createGroupForm.items"
v-model="state.createGroupForm.data"
:update-mode="state.updateMode"
:items="state.createGroupForm.items"
/>
</v-card-text>
</BaseDialog>
<BaseDialog
v-model="confirmDialog"
v-model="state.confirmDialog"
:title="$t('general.confirm')"
color="error"
can-confirm
@confirm="deleteGroup(deleteTarget)"
@confirm="deleteGroup(state.deleteTarget)"
>
<template #activator />
<v-card-text>
@@ -43,14 +43,14 @@
</v-toolbar>
<v-data-table
:headers="headers"
:headers="state.headers"
:items="groups || []"
item-key="id"
class="elevation-0"
:items-per-page="-1"
hide-default-footer
disable-pagination
:search="search"
:search="state.search"
@click:row="($event, { item }) => handleRowClick(item)"
>
<template #[`item.households`]="{ item }">
@@ -73,8 +73,8 @@
color="error"
variant="text"
@click.stop="
confirmDialog = true;
deleteTarget = item.id;
state.confirmDialog = true;
state.deleteTarget = item.id;
"
>
<v-icon>
@@ -92,26 +92,28 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { fieldTypes } from "~/composables/forms";
import { useGroups } from "~/composables/use-groups";
import { validators } from "~/composables/use-validators";
import type { GroupInDB } from "~/lib/api/types/user";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "admin",
});
const i18n = useI18n();
useHead({
title: i18n.t("group.manage-groups"),
});
// Set page title
useSeoMeta({
title: i18n.t("group.manage-groups"),
});
const { groups, refreshAllGroups, deleteGroup, createGroup } = useGroups();
const { groups, deleteGroup, createGroup } = useGroups();
const state = reactive({
createDialog: false,
@@ -154,13 +156,4 @@ export default defineNuxtComponent({
function handleRowClick(item: GroupInDB) {
navigateTo(`/admin/manage/groups/${item.id}`);
}
return { ...toRefs(state), groups, refreshAllGroups, deleteGroup, createGroup, openDialog, handleRowClick };
},
head() {
return {
title: useI18n().t("group.manage-groups"),
};
},
});
</script>

View File

@@ -67,18 +67,14 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import HouseholdPreferencesEditor from "~/components/Domain/Household/HouseholdPreferencesEditor.vue";
import { useGroups } from "~/composables/use-groups";
import { useAdminApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import { validators } from "~/composables/use-validators";
import type { VForm } from "vuetify/components";
export default defineNuxtComponent({
components: {
HouseholdPreferencesEditor,
},
setup() {
definePageMeta({
layout: "admin",
});
@@ -125,15 +121,4 @@ export default defineNuxtComponent({
alert.error(i18n.t("settings.settings-update-failed"));
}
}
return {
groups,
household,
validators,
userError,
refHouseholdEditForm,
handleSubmit,
};
},
});
</script>

View File

@@ -137,7 +137,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useAdminApi, useUserApi } from "~/composables/api";
import { useGroups } from "~/composables/use-groups";
import { useAdminHouseholds } from "~/composables/use-households";
@@ -146,8 +146,6 @@ import { useUserForm } from "~/composables/use-users";
import { validators } from "~/composables/use-validators";
import type { UserOut } from "~/lib/api/types/user";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "admin",
});
@@ -227,22 +225,4 @@ export default defineNuxtComponent({
alert.error(i18n.t("profile.error-sending-email"));
}
}
return {
user,
disabledFields,
userError,
userForm,
refNewUserForm,
handleSubmit,
groups,
households,
validators,
handlePasswordReset,
resetUrl,
generatingToken,
sendResetEmail,
};
},
});
</script>

View File

@@ -2,11 +2,11 @@
<v-container fluid>
<UserInviteDialog v-model="inviteDialog" />
<BaseDialog
v-model="deleteDialog"
v-model="state.deleteDialog"
:title="$t('general.confirm')"
color="error"
can-confirm
@confirm="deleteUser(deleteTargetId)"
@confirm="deleteUser(state.deleteTargetId)"
>
<template #activator />
@@ -60,7 +60,7 @@
:items-per-page="-1"
hide-default-footer
disable-pagination
:search="search"
:search="state.search"
@click:row="($event, { item }) => handleRowClick(item)"
>
<template #[`item.admin`]="{ item }">
@@ -78,8 +78,8 @@
color="error"
variant="text"
@click.stop="
deleteDialog = true;
deleteTargetId = item.id;
state.deleteDialog = true;
state.deleteTargetId = item.id;
"
>
<v-icon>
@@ -93,30 +93,28 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useAdminApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import { useUser, useAllUsers } from "~/composables/use-user";
import type { UserOut } from "~/lib/api/types/user";
import UserInviteDialog from "~/components/Domain/User/UserInviteDialog.vue";
export default defineNuxtComponent({
components: {
UserInviteDialog,
},
setup() {
definePageMeta({
layout: "admin",
});
const i18n = useI18n();
useHead({
title: i18n.t("sidebar.manage-users"),
});
const api = useAdminApi();
const refUserDialog = ref();
const inviteDialog = ref();
const auth = useMealieAuth();
const user = computed(() => auth.user.value);
const i18n = useI18n();
const { $globals } = useNuxtApp();
const router = useRouter();
@@ -143,7 +141,7 @@ export default defineNuxtComponent({
});
const { users, refreshAllUsers } = useAllUsers();
const { loading, deleteUser: deleteUserMixin } = useUser(refreshAllUsers);
const { deleteUser: deleteUserMixin } = useUser(refreshAllUsers);
function deleteUser(id: string) {
deleteUserMixin(id);
@@ -190,26 +188,4 @@ export default defineNuxtComponent({
useSeoMeta({
title: i18n.t("sidebar.manage-users"),
});
return {
isUserOwnAccount,
unlockAllUsers,
...toRefs(state),
headers,
deleteUser,
loading,
refUserDialog,
inviteDialog,
users,
user,
handleRowClick,
ACTIONS_OPTIONS,
};
},
head() {
return {
title: useI18n().t("sidebar.manage-users"),
};
},
});
</script>

View File

@@ -126,7 +126,7 @@
</div>
<div>
<v-text-field
v-model="address"
v-model="state.address"
class="mr-4"
:label="$t('user.email')"
:rules="[validators.email]"
@@ -135,7 +135,7 @@
color="info"
variant="elevated"
:disabled="!appConfig.emailReady || !validEmail"
:loading="loading"
:loading="state.loading"
class="opacity-100"
@click="testEmail"
>
@@ -144,12 +144,12 @@
</template>
{{ $t("general.test") }}
</BaseButton>
<template v-if="tested">
<template v-if="state.tested">
<v-divider class="my-x mt-6" />
<v-card-text class="px-0">
<h4> {{ $t("settings.email-test-results") }}</h4>
<span class="pl-4">
{{ success ? $t('settings.succeeded') : $t('settings.failed') }}
{{ state.success ? $t('settings.succeeded') : $t('settings.failed') }}
</span>
</v-card-text>
</template>
@@ -226,7 +226,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import type { TranslateResult } from "vue-i18n";
import { useAdminApi, useUserApi } from "~/composables/api";
import { validators } from "~/composables/use-validators";
@@ -234,12 +234,6 @@ import { useAsyncKey } from "~/composables/use-utils";
import type { CheckAppConfig } from "~/lib/api/types/admin";
import AppLoader from "~/components/global/AppLoader.vue";
enum DockerVolumeState {
Unknown = "unknown",
Success = "success",
Error = "error",
}
interface SimpleCheck {
id: string;
text: TranslateResult;
@@ -254,9 +248,6 @@ interface CheckApp extends CheckAppConfig {
isSiteSecure?: boolean;
}
export default defineNuxtComponent({
components: { AppLoader },
setup() {
definePageMeta({
layout: "admin",
});
@@ -504,20 +495,6 @@ export default defineNuxtComponent({
text += `${i18n.t("settings.email-configured")}: ${appConfig.value.emailReady ? i18n.t("general.yes") : i18n.t("general.no")}\n`;
return text;
});
return {
bugReportDialog,
bugReportText,
DockerVolumeState,
simpleChecks,
appConfig,
validEmail,
validators,
...toRefs(state),
testEmail,
appInfo,
};
},
});
</script>
<style scoped>

View File

@@ -16,7 +16,7 @@
<v-card-text>
<v-form @submit.prevent="requestLink()">
<v-text-field
v-model="email"
v-model="state.email"
:prepend-inner-icon="$globals.icons.email"
variant="solo-filled"
flat
@@ -31,7 +31,7 @@
<v-card-actions class="justify-center">
<div class="max-button">
<v-btn
:loading="loading"
:loading="state.loading"
color="primary"
type="submit"
size="large"
@@ -60,12 +60,10 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "basic",
});
@@ -101,13 +99,6 @@ export default defineNuxtComponent({
alert.error(i18n.t("profile.error-sending-email"));
}
}
return {
requestLink,
...toRefs(state),
};
},
});
</script>
<style lang="css">

View File

@@ -2,10 +2,6 @@
<CookbookPage />
</template>
<script lang="ts">
<script setup lang="ts">
import CookbookPage from "@/components/Domain/Cookbook/CookbookPage.vue";
export default defineNuxtComponent({
components: { CookbookPage },
});
</script>

View File

@@ -135,7 +135,7 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { VueDraggable } from "vue-draggable-plus";
import { useCookbookStore } from "~/composables/store/use-cookbook-store";
import { useHouseholdSelf } from "@/composables/use-households";
@@ -143,10 +143,10 @@ import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue";
import type { CreateCookBook, ReadCookBook } from "~/lib/api/types/cookbook";
import { useCookbookPreferences } from "~/composables/use-users/preferences";
export default defineNuxtComponent({
components: { CookbookEditor, VueDraggable },
definePageMeta({
middleware: ["group-only"],
setup() {
});
const dialogStates = reactive({
create: false,
delete: false,
@@ -238,26 +238,4 @@ export default defineNuxtComponent({
handleUnmount();
window.removeEventListener("beforeunload", handleUnmount);
});
return {
myCookbooks,
cookbookPreferences,
actions,
dialogStates,
// create
createTargetKey,
createTarget,
createCookbook,
// update
updateAll,
// delete
deleteTarget,
deleteEventHandler,
deleteCookbook,
deleteCreateTarget,
};
},
});
</script>

View File

@@ -4,10 +4,6 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import RecipeExplorerPage from "~/components/Domain/Recipe/RecipeExplorerPage/RecipeExplorerPage.vue";
export default defineNuxtComponent({
components: { RecipeExplorerPage },
});
</script>

View File

@@ -42,14 +42,14 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import type { MenuItem } from "~/components/global/BaseOverflowButton.vue";
import AdvancedOnly from "~/components/global/AdvancedOnly.vue";
export default defineNuxtComponent({
components: { AdvancedOnly },
definePageMeta({
middleware: ["group-only"],
setup() {
});
const i18n = useI18n();
const auth = useMealieAuth();
const { $appInfo, $globals } = useNuxtApp();
@@ -109,12 +109,4 @@ export default defineNuxtComponent({
return route.path.split("/").pop() ?? "url";
},
});
return {
groupSlug,
subpages,
subpage,
};
},
});
</script>

View File

@@ -49,7 +49,7 @@
</template>
</v-text-field>
</v-col>
<template v-if="showCatTags">
<template v-if="state.showCatTags">
<v-col
cols="12"
xs="12"
@@ -115,14 +115,14 @@
{{ $t('general.new') }}
</BaseButton>
<RecipeDialogBulkAdd
v-model="bulkDialog"
v-model="state.bulkDialog"
class="mr-1 mr-sm-0 mb-1"
@bulk-data="assignUrls"
/>
</v-card-actions>
<div class="px-0">
<v-checkbox
v-model="showCatTags"
v-model="state.showCatTags"
hide-details
:label="$t('recipe.set-categories-and-tags')"
/>
@@ -154,7 +154,7 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { whenever } from "@vueuse/shared";
import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
@@ -162,12 +162,7 @@ import RecipeOrganizerSelector from "~/components/Domain/Recipe/RecipeOrganizerS
import type { ReportSummary } from "~/lib/api/types/reports";
import RecipeDialogBulkAdd from "~/components/Domain/Recipe/RecipeDialogBulkAdd.vue";
export default defineNuxtComponent({
components: { RecipeOrganizerSelector, RecipeDialogBulkAdd },
setup() {
const state = reactive({
error: false,
loading: false,
showCatTags: false,
bulkDialog: false,
});
@@ -230,16 +225,4 @@ export default defineNuxtComponent({
function assignUrls(urls: string[]) {
bulkUrls.value = urls.map(url => ({ url, categories: [], tags: [] }));
}
return {
assignUrls,
reports,
deleteReport,
bulkCreate,
bulkUrls,
lockBulkImport,
...toRefs(state),
};
},
});
</script>

View File

@@ -28,7 +28,7 @@
<v-card-text v-if="$appInfo.enableOpenai">
{{ $t('recipe.recipe-debugger-use-openai-description') }}
<v-checkbox
v-model="useOpenAI"
v-model="state.useOpenAI"
:label="$t('recipe.use-openai')"
/>
</v-card-text>
@@ -40,7 +40,7 @@
block
type="submit"
color="info"
:loading="loading"
:loading="state.loading"
>
<template #icon>
{{ $globals.icons.robot }}
@@ -67,15 +67,12 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import { validators } from "~/composables/use-validators";
import type { Recipe } from "~/lib/api/types/recipe";
export default defineNuxtComponent({
setup() {
const state = reactive({
error: false,
loading: false,
useOpenAI: false,
});
@@ -112,15 +109,4 @@ export default defineNuxtComponent({
state.loading = false;
debugData.value = data;
}
return {
recipeUrl,
debugTreeView,
debugUrl,
debugData,
...toRefs(state),
validators,
};
},
});
</script>

View File

@@ -90,7 +90,7 @@
rounded
block
type="submit"
:loading="loading"
:loading="state.loading"
/>
</div>
<v-card-text class="py-2">
@@ -103,7 +103,7 @@
</v-form>
</template>
<script lang="ts">
<script setup lang="ts">
import type { AxiosResponse } from "axios";
import { useTagStore } from "~/composables/store/use-tag-store";
import { useUserApi } from "~/composables/api";
@@ -111,8 +111,6 @@ import { useNewRecipeOptions } from "~/composables/use-new-recipe-options";
import { validators } from "~/composables/use-validators";
import type { VForm } from "~/types/auto-forms";
export default defineNuxtComponent({
setup() {
const state = reactive({
error: false,
loading: false,
@@ -203,21 +201,4 @@ export default defineNuxtComponent({
createStatus.value = null;
handleResponse(response, importKeywordsAsTags);
}
return {
domUrlForm,
importKeywordsAsTags,
stayInEditMode,
parseRecipe,
importCategories,
newRecipeData,
newRecipeUrl,
handleIsEditJson,
createStatus,
createFromHtmlOrJson,
...toRefs(state),
validators,
};
},
});
</script>

View File

@@ -37,7 +37,7 @@
:img="imageUrl"
cropper-height="100%"
cropper-width="100%"
:submitted="loading"
:submitted="state.loading"
class="mt-4 mb-2"
@save="(croppedImage) => updateUploadedImage(index, croppedImage)"
@delete="clearImage(index)"
@@ -45,7 +45,7 @@
<v-btn
v-if="uploadedImages.length > 1"
:disabled="loading || index === 0"
:disabled="state.loading || index === 0"
color="primary"
@click="() => setCoverImage(index)"
>
@@ -66,7 +66,7 @@
color="primary"
hide-details
:label="$t('recipe.should-translate-description')"
:disabled="loading"
:disabled="state.loading"
/>
<v-checkbox
v-if="uploadedImages.length"
@@ -74,15 +74,15 @@
color="primary"
hide-details
:label="$t('recipe.parse-recipe-ingredients-after-import')"
:disabled="loading"
:disabled="state.loading"
/>
</v-card-text>
<v-card-actions v-if="uploadedImages.length">
<div class="w-100 d-flex flex-column align-center">
<p style="width: 250px">
<BaseButton rounded block type="submit" :loading="loading" />
<BaseButton rounded block type="submit" :loading="state.loading" />
</p>
<p v-if="loading" class="mb-0">
<p v-if="state.loading" class="mb-0">
{{
uploadedImages.length > 1
? $t("recipe.please-wait-images-processing")
@@ -96,14 +96,12 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import { useNewRecipeOptions } from "~/composables/use-new-recipe-options";
import type { VForm } from "~/types/auto-forms";
export default defineNuxtComponent({
setup() {
const state = reactive({
loading: false,
});
@@ -187,20 +185,4 @@ export default defineNuxtComponent({
swapImages(0, index);
}
return {
...toRefs(state),
domUrlForm,
uploadedImages,
uploadedImagesPreviewUrls,
shouldTranslate,
parseRecipe,
uploadImages,
clearImage,
createRecipe,
updateUploadedImage,
setCoverImage,
};
},
});
</script>

View File

@@ -2,15 +2,10 @@
<div />
</template>
<script lang="ts">
export default defineNuxtComponent({
setup() {
<script setup lang="ts">
const router = useRouter();
onMounted(() => {
// Force redirect to first valid page
router.replace("/r/create/url");
});
return {};
},
});
</script>

View File

@@ -33,7 +33,7 @@
:disabled="newRecipeName.trim() === ''"
rounded
block
:loading="loading"
:loading="state.loading"
@click="createByName(newRecipeName)"
/>
</div>
@@ -41,14 +41,12 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import type { AxiosResponse } from "axios";
import { useUserApi } from "~/composables/api";
import { validators } from "~/composables/use-validators";
import type { VForm } from "~/types/auto-forms";
export default defineNuxtComponent({
setup() {
const state = reactive({
error: false,
loading: false,
@@ -79,13 +77,4 @@ export default defineNuxtComponent({
const { response } = await api.recipes.createOne({ name });
handleResponse(response as any, true);
}
return {
domCreateByName,
newRecipeName,
createByName,
...toRefs(state),
validators,
};
},
});
</script>

View File

@@ -72,7 +72,7 @@
rounded
block
type="submit"
:loading="loading"
:loading="state.loading"
/>
</div>
<v-card-text class="py-2">
@@ -85,7 +85,7 @@
</v-form>
<v-expand-transition>
<v-alert
v-if="error"
v-if="state.error"
color="error"
class="mt-6 white--text"
>
@@ -140,7 +140,7 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import type { AxiosResponse } from "axios";
import { useUserApi } from "~/composables/api";
import { useTagStore } from "~/composables/store/use-tag-store";
@@ -148,8 +148,6 @@ import { useNewRecipeOptions } from "~/composables/use-new-recipe-options";
import { validators } from "~/composables/use-validators";
import type { VForm } from "~/types/auto-forms";
export default defineNuxtComponent({
setup() {
definePageMeta({
key: route => route.path,
});
@@ -260,23 +258,6 @@ export default defineNuxtComponent({
createStatus.value = null;
handleResponse(response, importKeywordsAsTags);
}
return {
bulkImporterTarget,
htmlOrJsonImporterTarget,
recipeUrl,
importKeywordsAsTags,
importCategories: importCategories,
stayInEditMode,
parseRecipe,
domUrlForm,
createStatus,
createByUrl,
...toRefs(state),
validators,
};
},
});
</script>
<style scoped>

View File

@@ -27,7 +27,7 @@
:disabled="newRecipeZip === null"
rounded
block
:loading="loading"
:loading="state.loading"
@click="createByZip"
/>
</div>
@@ -36,14 +36,11 @@
</v-form>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import { useGlobalI18n } from "~/composables/use-global-i18n";
import { alert } from "~/composables/use-toast";
import { validators } from "~/composables/use-validators";
export default defineNuxtComponent({
setup() {
const state = reactive({
loading: false,
});
@@ -80,13 +77,4 @@ export default defineNuxtComponent({
state.loading = false;
}
}
return {
newRecipeZip,
createByZip,
...toRefs(state),
validators,
};
},
});
</script>

View File

@@ -15,27 +15,18 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import RecipeOrganizerPage from "~/components/Domain/Recipe/RecipeOrganizerPage.vue";
import { useCategoryStore } from "~/composables/store";
export default defineNuxtComponent({
components: {
RecipeOrganizerPage,
},
definePageMeta({
middleware: ["group-only"],
setup() {
});
const { store, actions } = useCategoryStore();
const i18n = useI18n();
useSeoMeta({
title: i18n.t("category.categories"),
});
return {
store,
actions,
};
},
});
</script>

View File

@@ -17,7 +17,7 @@
{{ $t('recipe-finder.recipe-finder-description') }}
</template>
</BasePageTitle>
<v-container v-if="ready">
<v-container v-if="state.ready">
<v-row>
<v-col :cols="useMobile ? 12 : 3">
<v-container class="ma-0 pa-0">
@@ -51,38 +51,38 @@
</SearchFilter>
<div :class="attrs.searchFilter.filterClass">
<v-badge
:model-value="!!queryFilterJSON.parts && queryFilterJSON.parts.length > 0"
:model-value="!!state.queryFilterJSON.parts && state.queryFilterJSON.parts.length > 0"
size="small"
color="primary"
:content="(queryFilterJSON.parts || []).length"
:content="(state.queryFilterJSON.parts || []).length"
>
<v-btn
size="small"
color="accent"
dark
@click="queryFilterMenu = !queryFilterMenu"
@click="state.queryFilterMenu = !state.queryFilterMenu"
>
<v-icon start>
{{ $globals.icons.filter }}
</v-icon>
{{ $t("recipe-finder.other-filters") }}
<BaseDialog
v-model="queryFilterMenu"
v-model="state.queryFilterMenu"
:title="$t('recipe-finder.other-filters')"
:icon="$globals.icons.filter"
width="100%"
max-width="1100px"
:submit-disabled="!queryFilterEditorValue"
:submit-disabled="!state.queryFilterEditorValue"
can-confirm
@confirm="saveQueryFilter"
>
<v-card-text>
<QueryFilterBuilder
:key="queryFilterMenuKey"
:initial-query-filter="queryFilterJSON"
:key="state.queryFilterMenuKey"
:initial-query-filter="state.queryFilterJSON"
:field-defs="queryFilterBuilderFields"
@input="(value) => queryFilterEditorValue = value"
@input-j-s-o-n="(value) => queryFilterEditorValueJSON = value"
@input="(value) => state.queryFilterEditorValue = value"
@input-j-s-o-n="(value) => state.queryFilterEditorValueJSON = value"
/>
</v-card-text>
<template #custom-card-action>
@@ -113,7 +113,7 @@
:class="attrs.settings.colClass"
>
<v-menu
v-model="settingsMenu"
v-model="state.settingsMenu"
offset-y
nudge-bottom="3"
:close-on-content-click="false"
@@ -135,7 +135,7 @@
<v-card-text>
<div>
<v-number-input
v-model="settings.maxMissingFoods"
v-model="state.settings.maxMissingFoods"
:precision="null"
:min="0"
control-variant="stacked"
@@ -144,7 +144,7 @@
:label="$t('recipe-finder.max-missing-ingredients')"
/>
<v-number-input
v-model="settings.maxMissingTools"
v-model="state.settings.maxMissingTools"
:precision="null"
:min="0"
control-variant="stacked"
@@ -157,7 +157,7 @@
<div class="mt-1">
<v-checkbox
v-if="isOwnGroup"
v-model="settings.includeFoodsOnHand"
v-model="state.settings.includeFoodsOnHand"
density="compact"
size="small"
hide-details
@@ -166,7 +166,7 @@
/>
<v-checkbox
v-if="isOwnGroup"
v-model="settings.includeToolsOnHand"
v-model="state.settings.includeToolsOnHand"
density="compact"
size="small"
hide-details
@@ -328,7 +328,7 @@
:recipe="item.recipe"
:missing-foods="item.missingFoods"
:missing-tools="item.missingTools"
:disable-checkbox="loading"
:disable-checkbox="state.loading"
@add-food="addFood"
@remove-food="removeFood"
@add-tool="addTool"
@@ -356,7 +356,7 @@
:recipe="item.recipe"
:missing-foods="item.missingFoods"
:missing-tools="item.missingTools"
:disable-checkbox="loading"
:disable-checkbox="state.loading"
@add-food="addFood"
@remove-food="removeFood"
@add-tool="addTool"
@@ -366,7 +366,7 @@
</v-col>
</v-row>
</v-container>
<v-container v-else-if="!recipesReady">
<v-container v-else-if="!state.recipesReady">
<v-row>
<v-col
cols="12"
@@ -411,7 +411,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { watchDebounced } from "@vueuse/core";
import { useUserApi } from "~/composables/api";
import { usePublicExploreApi } from "~/composables/api/api-client";
@@ -431,9 +431,6 @@ interface RecipeSuggestions {
missingItems: RecipeSuggestionResponseItem[];
}
export default defineNuxtComponent({
components: { QueryFilterBuilder, RecipeSuggestion, SearchFilter },
setup() {
const display = useDisplay();
const i18n = useI18n();
const auth = useMealieAuth();
@@ -511,6 +508,7 @@ export default defineNuxtComponent({
});
const foodStore = isOwnGroup.value ? useFoodStore() : usePublicFoodStore(groupSlug.value);
const foods = foodStore.store.value;
const selectedFoods = ref<IngredientFood[]>([]);
function addFood(food: IngredientFood) {
selectedFoods.value = [...selectedFoods.value, food];
@@ -532,6 +530,7 @@ export default defineNuxtComponent({
);
const toolStore = isOwnGroup.value ? useToolStore() : usePublicToolStore(groupSlug.value);
const tools = toolStore.store.value;
const selectedTools = ref<RecipeTool[]>([]);
function addTool(tool: RecipeTool) {
selectedTools.value = [...selectedTools.value, tool];
@@ -685,25 +684,4 @@ export default defineNuxtComponent({
state.queryFilterJSON = state.queryFilterEditorValueJSON || { parts: [] } as QueryFilterJSON;
state.queryFilterMenu = false;
}
return {
...toRefs(state),
useMobile,
attrs,
isOwnGroup,
foods: foodStore.store,
selectedFoods,
addFood,
removeFood,
tools: toolStore.store,
selectedTools,
addTool,
removeTool,
recipeSuggestions,
queryFilterBuilderFields,
clearQueryFilter,
saveQueryFilter,
};
},
});
</script>

View File

@@ -15,27 +15,18 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import RecipeOrganizerPage from "~/components/Domain/Recipe/RecipeOrganizerPage.vue";
import { useTagStore } from "~/composables/store";
export default defineNuxtComponent({
components: {
RecipeOrganizerPage,
},
definePageMeta({
middleware: ["group-only"],
setup() {
});
const { store, actions } = useTagStore();
const i18n = useI18n();
useSeoMeta({
title: i18n.t("tag.tags"),
});
return {
store,
actions,
};
},
});
</script>

View File

@@ -30,14 +30,14 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import RecipeTimeline from "~/components/Domain/Recipe/RecipeTimeline.vue";
export default defineNuxtComponent({
components: { RecipeTimeline },
definePageMeta({
middleware: ["group-only"],
setup() {
});
const i18n = useI18n();
const api = useUserApi();
const ready = ref<boolean>(false);
@@ -59,12 +59,4 @@ export default defineNuxtComponent({
}
useAsyncData("house-hold", fetchHousehold);
return {
groupName,
queryFilter,
ready,
};
},
});
</script>

View File

@@ -15,7 +15,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import RecipeOrganizerPage from "~/components/Domain/Recipe/RecipeOrganizerPage.vue";
import { useToolStore } from "~/composables/store";
import type { RecipeTool } from "~/lib/api/types/recipe";
@@ -24,15 +24,12 @@ interface RecipeToolWithOnHand extends RecipeTool {
onHand: boolean;
}
export default defineNuxtComponent({
components: {
RecipeOrganizerPage,
},
definePageMeta({
middleware: ["group-only"],
setup() {
});
const auth = useMealieAuth();
const toolStore = useToolStore();
const dialog = ref(false);
const i18n = useI18n();
useSeoMeta({
@@ -67,13 +64,4 @@ export default defineNuxtComponent({
}
await toolStore.actions.updateOne(tool);
}
return {
dialog,
tools,
deleteOne,
updateOne,
};
},
});
</script>

View File

@@ -34,10 +34,11 @@
</v-container>
</template>
<script lang="ts">
export default defineNuxtComponent({
<script setup lang="ts">
definePageMeta({
middleware: ["can-organize-only"],
setup() {
});
const i18n = useI18n();
const buttonLookup: { [key: string]: string } = {
recipes: i18n.t("general.recipes"),
@@ -116,11 +117,4 @@ export default defineNuxtComponent({
useSeoMeta({
title: i18n.t("data-pages.data-management"),
});
return {
buttonText,
DATA_TYPE_OPTIONS,
};
},
});
</script>

View File

@@ -2,15 +2,10 @@
<div />
</template>
<script lang="ts">
export default defineNuxtComponent({
setup() {
<script setup lang="ts">
const router = useRouter();
onMounted(() => {
// Force redirect to first valid page
router.push("/group/data/foods");
});
return {};
},
});
</script>

View File

@@ -226,7 +226,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import RecipeDataTable from "~/components/Domain/Recipe/RecipeDataTable.vue";
import RecipeOrganizerSelector from "~/components/Domain/Recipe/RecipeOrganizerSelector.vue";
import { useUserApi } from "~/composables/api";
@@ -249,10 +249,10 @@ enum MODES {
changeOwner = "changeOwner",
}
export default defineNuxtComponent({
components: { RecipeDataTable, RecipeOrganizerSelector, GroupExportData, RecipeSettingsSwitches, UserAvatar },
definePageMeta({
scrollToTop: true,
setup() {
});
const i18n = useI18n();
const auth = useMealieAuth();
const { $globals } = useNuxtApp();
@@ -261,7 +261,7 @@ export default defineNuxtComponent({
title: i18n.t("data-pages.recipes.recipe-data"),
});
const { getAllRecipes, refreshRecipes } = useRecipes(true, true, false, `householdId=${auth.user.value?.householdId || ""}`);
const { refreshRecipes } = useRecipes(true, true, false, `householdId=${auth.user.value?.householdId || ""}`);
const selected = ref<Recipe[]>([]);
function resetAll() {
@@ -510,35 +510,6 @@ export default defineNuxtComponent({
return households.value.find(h => h.id === owner.householdId);
});
return {
recipeSettings,
selectAll,
loading,
actions,
allRecipes,
categorizeSelected,
deleteSelected,
dialog,
exportSelected,
getAllRecipes,
headerLabels,
headers,
MODES,
openDialog,
selected,
tagSelected,
toSetCategories,
toSetTags,
groupExports,
purgeExportsDialog,
purgeExports,
allUsers,
selectedOwner,
selectedOwnerHousehold,
};
},
});
</script>
<style>

View File

@@ -43,25 +43,19 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useGroupSelf } from "~/composables/use-groups";
export default defineNuxtComponent({
definePageMeta({
middleware: ["can-manage-only"],
setup() {
});
const { group, actions: groupActions } = useGroupSelf();
const i18n = useI18n();
useSeoMeta({
title: i18n.t("group.group"),
});
return {
group,
groupActions,
};
},
});
</script>
<style lang="css">

View File

@@ -19,7 +19,7 @@
<BaseCardSectionTitle :title="$t('migration.new-migration')" />
<v-card
variant="outlined"
:loading="loading"
:loading="state.loading"
style="border-color: lightgrey;"
>
<v-card-title> {{ $t('migration.choose-migration-type') }} </v-card-title>
@@ -29,7 +29,7 @@
>
<div class="mb-2">
<BaseOverflowButton
v-model="migrationType"
v-model="state.migrationType"
mode="model"
:items="items"
/>
@@ -37,7 +37,7 @@
{{ content.text }}
<v-treeview
v-if="content.tree && Array.isArray(content.tree)"
:key="migrationType"
:key="state.migrationType"
density="compact"
:items="content.tree"
>
@@ -59,15 +59,15 @@
:text-btn="false"
@uploaded="setFileObject"
/>
{{ fileObject.name || $t('migration.no-file-selected') }}
{{ state.fileObject.name || $t('migration.no-file-selected') }}
</v-card-text>
<v-card-text>
<v-checkbox v-model="addMigrationTag">
<v-checkbox v-model="state.addMigrationTag">
<template #label>
<i18n-t keypath="migration.tag-all-recipes">
<template #tag-name>
<b class="mx-1"> {{ migrationType }} </b>
<b class="mx-1"> {{ state.migrationType }} </b>
</template>
</i18n-t>
</template>
@@ -76,7 +76,7 @@
<v-card-actions class="justify-end">
<BaseButton
:disabled="!fileObject.name"
:disabled="!state.fileObject.name"
submit
@click="startMigration"
>
@@ -88,14 +88,14 @@
<v-container class="$vuetify.display.smAndDown ? 'px-0': ''">
<BaseCardSectionTitle :title="$t('migration.previous-migrations')" />
<ReportTable
:items="reports"
:items="state.reports"
@delete="deleteReport"
/>
</v-container>
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import type { ReportSummary } from "~/lib/api/types/reports";
import type { MenuItem } from "~/components/global/BaseOverflowButton.vue";
import { useUserApi } from "~/composables/api";
@@ -127,9 +127,10 @@ const MIGRATIONS = {
cookn: "cookn",
};
export default defineNuxtComponent({
definePageMeta({
middleware: ["advanced-only"],
setup() {
});
const i18n = useI18n();
const { $globals } = useNuxtApp();
@@ -508,18 +509,6 @@ export default defineNuxtComponent({
};
}
});
return {
...toRefs(state),
items,
content,
setFileObject,
deleteReport,
startMigration,
getMigrationReports,
};
},
});
</script>
<style lang="scss" scoped></style>

View File

@@ -47,12 +47,10 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import type { ReportOut } from "~/lib/api/types/reports";
export default defineNuxtComponent({
setup() {
const route = useRoute();
const id = route.params.id as string;
@@ -74,14 +72,6 @@ export default defineNuxtComponent({
{ title: "Message", value: "message" },
{ title: "Timestamp", value: "timestamp" },
];
return {
report,
id,
itemHeaders,
};
},
});
</script>
<style lang="scss" scoped></style>

View File

@@ -32,19 +32,16 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import HouseholdPreferencesEditor from "~/components/Domain/Household/HouseholdPreferencesEditor.vue";
import { useHouseholdSelf } from "~/composables/use-households";
import type { ReadHouseholdPreferences } from "~/lib/api/types/household";
import { alert } from "~/composables/use-toast";
import type { VForm } from "~/types/auto-forms";
export default defineNuxtComponent({
components: {
HouseholdPreferencesEditor,
},
definePageMeta({
middleware: ["can-manage-household-only"],
setup() {
});
const { household, actions: householdActions } = useHouseholdSelf();
const i18n = useI18n();
@@ -54,82 +51,6 @@ export default defineNuxtComponent({
const refHouseholdEditForm = ref<VForm | null>(null);
type Preference = {
key: keyof ReadHouseholdPreferences;
value: boolean;
label: string;
description: string;
};
const preferencesEditor = computed<Preference[]>(() => {
if (!household.value || !household.value.preferences) {
return [];
}
return [
{
key: "recipePublic",
value: household.value.preferences.recipePublic || false,
label: i18n.t("household.allow-users-outside-of-your-household-to-see-your-recipes"),
description: i18n.t("household.allow-users-outside-of-your-household-to-see-your-recipes-description"),
} as Preference,
{
key: "recipeShowNutrition",
value: household.value.preferences.recipeShowNutrition || false,
label: i18n.t("group.show-nutrition-information"),
description: i18n.t("group.show-nutrition-information-description"),
} as Preference,
{
key: "recipeShowAssets",
value: household.value.preferences.recipeShowAssets || false,
label: i18n.t("group.show-recipe-assets"),
description: i18n.t("group.show-recipe-assets-description"),
} as Preference,
{
key: "recipeLandscapeView",
value: household.value.preferences.recipeLandscapeView || false,
label: i18n.t("group.default-to-landscape-view"),
description: i18n.t("group.default-to-landscape-view-description"),
} as Preference,
{
key: "recipeDisableComments",
value: household.value.preferences.recipeDisableComments || false,
label: i18n.t("group.disable-users-from-commenting-on-recipes"),
description: i18n.t("group.disable-users-from-commenting-on-recipes-description"),
} as Preference,
];
});
const allDays = [
{
name: i18n.t("general.sunday"),
value: 0,
},
{
name: i18n.t("general.monday"),
value: 1,
},
{
name: i18n.t("general.tuesday"),
value: 2,
},
{
name: i18n.t("general.wednesday"),
value: 3,
},
{
name: i18n.t("general.thursday"),
value: 4,
},
{
name: i18n.t("general.friday"),
value: 5,
},
{
name: i18n.t("general.saturday"),
value: 6,
},
];
async function handleSubmit() {
if (!refHouseholdEditForm.value?.validate() || !household.value?.preferences) {
console.log(refHouseholdEditForm.value?.validate());
@@ -144,17 +65,6 @@ export default defineNuxtComponent({
alert.error(i18n.t("settings.settings-update-failed"));
}
}
return {
household,
householdActions,
allDays,
preferencesEditor,
refHouseholdEditForm,
handleSubmit,
};
},
});
</script>
<style lang="css">

View File

@@ -86,7 +86,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { isSameDay, addDays, parseISO, format, isValid } from "date-fns";
import RecipeDialogAddToShoppingList from "~/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue";
import { useHouseholdSelf } from "~/composables/use-households";
@@ -95,11 +95,6 @@ import { useUserMealPlanPreferences } from "~/composables/use-users/preferences"
import type { ShoppingListSummary } from "~/lib/api/types/household";
import { useUserApi } from "~/composables/api";
export default defineNuxtComponent({
components: {
RecipeDialogAddToShoppingList,
},
setup() {
const TABS = {
view: "household-mealplan-planner-view",
edit: "household-mealplan-planner-edit",
@@ -257,23 +252,6 @@ export default defineNuxtComponent({
state.value.shoppingListDialog = true;
state.value.addAllLoading = false;
}
return {
TABS,
route,
state,
actions,
mealsByDate,
weekRange,
firstDayOfWeek,
numberOfDays,
hasRecipes,
shoppingLists,
weekRecipesWithScales,
addAllToList,
};
},
});
</script>
<style lang="css">

View File

@@ -129,9 +129,9 @@
</v-icon>
</v-btn>
<v-menu offset-y>
<template #activator="{ props }">
<template #activator="{ props: menuProps }">
<v-chip
v-bind="props"
v-bind="menuProps"
label
variant="elevated"
size="small"
@@ -232,7 +232,7 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { format } from "date-fns";
import type { SortableEvent } from "sortablejs";
import { VueDraggable } from "vue-draggable-plus";
@@ -246,22 +246,11 @@ import { useHouseholdSelf } from "~/composables/use-households";
import { normalizeFilter } from "~/composables/use-utils";
import { useRecipeSearch } from "~/composables/recipes/use-recipe-search";
export default defineNuxtComponent({
components: {
VueDraggable,
RecipeCardImage,
},
props: {
mealplans: {
type: Array as () => MealsByDate[],
required: true,
},
actions: {
type: Object as () => ReturnType<typeof useMealplans>["actions"],
required: true,
},
},
setup(props) {
const props = defineProps<{
mealplans: MealsByDate[];
actions: ReturnType<typeof useMealplans>["actions"];
}>();
const api = useUserApi();
const auth = useMealieAuth();
const { household } = useHouseholdSelf();
@@ -410,30 +399,4 @@ export default defineNuxtComponent({
onMounted(async () => {
await search.trigger();
});
return {
state,
onMoveCallback,
planTypeOptions,
getEntryTypeText,
requiredRule,
isCreateDisabled,
normalizeFilter,
// Dialog
dialog,
newMeal,
newMealDateString,
openDialog,
editMeal,
resetDialog,
randomMeal,
// Search
search,
firstDayOfWeek,
mealplansByDate,
};
},
});
</script>

View File

@@ -50,7 +50,7 @@
</v-container>
</template>
<script lang="ts" setup>
<script setup lang="ts">
import type { MealsByDate } from "./types";
import type { ReadPlanEntry } from "~/lib/api/types/meal-plan";
import GroupMealPlanDayContextMenu from "~/components/Domain/Household/GroupMealPlanDayContextMenu.vue";

View File

@@ -171,25 +171,13 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import type { PlanRulesCreate, PlanRulesOut } from "~/lib/api/types/meal-plan";
import GroupMealPlanRuleForm from "~/components/Domain/Household/GroupMealPlanRuleForm.vue";
import { useAsyncKey } from "~/composables/use-utils";
import RecipeChips from "~/components/Domain/Recipe/RecipeChips.vue";
export default defineNuxtComponent({
components: {
GroupMealPlanRuleForm,
RecipeChips,
},
props: {
modelValue: {
type: Boolean,
default: false,
},
},
setup() {
const api = useUserApi();
const i18n = useI18n();
@@ -256,17 +244,4 @@ export default defineNuxtComponent({
toggleEditState(rule.id);
}
}
return {
allRules,
createDataFormKey,
createData,
createRule,
deleteRule,
editState,
updateRule,
toggleEditState,
};
},
});
</script>

View File

@@ -115,17 +115,11 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import type { UserOut } from "~/lib/api/types/user";
import UserAvatar from "~/components/Domain/User/UserAvatar.vue";
export default defineNuxtComponent({
components: {
UserAvatar,
},
setup() {
const auth = useMealieAuth();
const api = useUserApi();
const i18n = useI18n();
@@ -168,8 +162,4 @@ export default defineNuxtComponent({
onMounted(async () => {
await refreshMembers();
});
return { members, headers, setPermissions, sessionUser: auth.user };
},
});
</script>

View File

@@ -1,19 +1,19 @@
<template>
<v-container class="narrow-container">
<BaseDialog
v-model="deleteDialog"
v-model="state.deleteDialog"
color="error"
:title="$t('general.confirm')"
:icon="$globals.icons.alertCircle"
can-confirm
@confirm="deleteNotifier(deleteTargetId)"
@confirm="deleteNotifier(state.deleteTargetId)"
>
<v-card-text>
{{ $t("general.confirm-delete-generic") }}
</v-card-text>
</BaseDialog>
<BaseDialog
v-model="createDialog"
v-model="state.createDialog"
:title="$t('events.new-notification')"
:icon="$globals.icons.bellPlus"
can-submit
@@ -83,7 +83,7 @@
<BaseButton
create
@click="createDialog = true"
@click="state.createDialog = true"
/>
<v-expansion-panels
v-if="notifiers"
@@ -182,7 +182,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import { useAsyncKey } from "~/composables/use-utils";
import type { GroupEventNotifierCreate, GroupEventNotifierOut } from "~/lib/api/types/household";
@@ -198,9 +198,10 @@ interface OptionSection {
options: OptionKey[];
}
export default defineNuxtComponent({
definePageMeta({
middleware: ["advanced-only"],
setup() {
});
const api = useUserApi();
const i18n = useI18n();
@@ -388,20 +389,6 @@ export default defineNuxtComponent({
],
},
];
return {
...toRefs(state),
openDelete,
notifiers,
createNotifierData,
optionsSections,
deleteNotifier,
testNotifier,
saveNotifier,
createNewNotifier,
};
},
});
</script>
<style>

View File

@@ -68,28 +68,19 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useGroupWebhooks, timeUTC } from "~/composables/use-group-webhooks";
import GroupWebhookEditor from "~/components/Domain/Household/GroupWebhookEditor.vue";
import { alert } from "~/composables/use-toast";
export default defineNuxtComponent({
components: { GroupWebhookEditor },
definePageMeta({
middleware: ["advanced-only"],
setup() {
});
const i18n = useI18n();
const { actions, webhooks } = useGroupWebhooks();
useSeoMeta({
title: i18n.t("settings.webhooks.webhooks"),
});
return {
alert,
webhooks,
actions,
timeUTC,
};
},
});
</script>

View File

@@ -2,14 +2,12 @@
<div />
</template>
<script lang="ts">
<script setup lang="ts">
import useDefaultActivity from "~/composables/use-default-activity";
import { useUserActivityPreferences } from "~/composables/use-users/preferences";
import { useAsyncKey } from "~/composables/use-utils";
import type { AppInfo, AppStartupInfo } from "~/lib/api/types/admin";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "blank",
});
@@ -54,6 +52,4 @@ export default defineNuxtComponent({
redirectPublicUserToDefaultGroup();
}
});
},
});
</script>

View File

@@ -210,7 +210,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useDark, whenever } from "@vueuse/core";
import { useLoggedInState } from "~/composables/use-logged-in-state";
import { usePasswordField } from "~/composables/use-passwords";
@@ -219,8 +219,6 @@ import { useAsyncKey } from "~/composables/use-utils";
import type { AppStartupInfo } from "~/lib/api/types/admin";
import { useUserActivityPreferences } from "~/composables/use-users/preferences";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "blank",
});
@@ -359,21 +357,6 @@ export default defineNuxtComponent({
alert.error(i18n.t("events.something-went-wrong"));
}
}
return {
isDark,
form,
loggingIn,
authenticate,
oidcAuthenticate,
oidcLoggingIn,
passwordIcon,
inputType,
togglePasswordShow,
isFirstLogin,
};
},
});
</script>
<style lang="css" scoped>

View File

@@ -298,7 +298,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useDark } from "@vueuse/core";
import { States, RegistrationType, useRegistration } from "./states";
import { useUserRegistrationForm } from "~/composables/use-users/user-registration-form";
@@ -307,24 +307,20 @@ import { validators, useAsyncValidator } from "~/composables/use-validators";
import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import type { CreateUserRegistration } from "~/lib/api/types/user";
import { usePasswordField } from "~/composables/use-passwords";
import { usePublicApi } from "~/composables/api/api-client";
import { useLocales } from "~/composables/use-locales";
import UserRegistrationForm from "~/components/Domain/User/UserRegistrationForm.vue";
import type { VForm } from "~/types/auto-forms";
definePageMeta({
layout: "blank",
});
const inputAttrs = {
variant: "filled",
validateOnBlur: true,
};
export default defineNuxtComponent({
components: { UserRegistrationForm },
setup() {
definePageMeta({
layout: "blank",
});
const i18n = useI18n();
const isDark = useDark();
@@ -334,19 +330,12 @@ export default defineNuxtComponent({
}
return false;
}
// ================================================================
// Registration Context
//
// State is used to manage the registration process states and provide
// a state machine esq interface to interact with the registration workflow.
const state = useRegistration();
// ================================================================
// Handle Token URL / Initialization
//
const token = useRouteQuery("token");
// TODO: We need to have some way to check to see if the site is in a state
// Where it needs to be initialized with a user, in that case we'll handle that
// somewhere...
function initialUser() {
return false;
}
@@ -360,7 +349,7 @@ export default defineNuxtComponent({
state.setType(RegistrationType.InitialGroup);
}
});
// ================================================================
// Initial
const initial = {
createGroup: () => {
@@ -375,7 +364,7 @@ export default defineNuxtComponent({
state.setType(RegistrationType.JoinGroup);
},
};
// ================================================================
// Provide Token
const domTokenForm = ref<VForm | null>(null);
function validateToken() {
@@ -391,7 +380,7 @@ export default defineNuxtComponent({
}
},
};
// ================================================================
// Provide Group Details
const publicApi = usePublicApi();
const domGroupForm = ref<VForm | null>(null);
@@ -416,15 +405,11 @@ export default defineNuxtComponent({
state.setState(States.ProvideAccountDetails);
},
};
const pwFields = usePasswordField();
const {
accountDetails,
credentials,
domAccountForm,
emailErrorMessages,
usernameErrorMessages,
validateUsername,
validateEmail,
} = useUserRegistrationForm();
async function accountDetailsNext() {
if (!await accountDetails.validate()) {
@@ -432,11 +417,11 @@ export default defineNuxtComponent({
}
state.setState(States.Confirmation);
}
// ================================================================
// Locale
const { locale } = useLocales();
const langDialog = ref(false);
// ================================================================
// Confirmation
const confirmationData = computed(() => {
return [
@@ -477,6 +462,7 @@ export default defineNuxtComponent({
},
];
});
const api = useUserApi();
const router = useRouter();
async function submitRegistration() {
@@ -508,38 +494,6 @@ export default defineNuxtComponent({
alert.error(i18n.t("events.something-went-wrong"));
}
}
return {
accountDetails,
accountDetailsNext,
confirmationData,
credentials,
emailErrorMessages,
groupDetails,
groupErrorMessages,
initial,
inputAttrs,
isDark,
langDialog,
provideToken,
pwFields,
RegistrationType,
state,
States,
token,
usernameErrorMessages,
validators,
submitRegistration,
// Validators
validGroupName,
validateUsername,
validateEmail,
// Dom Refs
domAccountForm,
domGroupForm,
domTokenForm,
};
},
});
</script>
<style lang="css" scoped>

View File

@@ -16,7 +16,7 @@
<v-card-text>
<v-form @submit.prevent="requestLink()">
<v-text-field
v-model="email"
v-model="state.email"
:prepend-inner-icon="$globals.icons.email"
variant="solo-filled"
flat
@@ -26,7 +26,7 @@
type="text"
/>
<v-text-field
v-model="password"
v-model="state.password"
variant="solo-filled"
flat
:prepend-inner-icon="$globals.icons.lock"
@@ -36,7 +36,7 @@
:rules="[validators.required]"
/>
<v-text-field
v-model="passwordConfirm"
v-model="state.passwordConfirm"
variant="solo-filled"
flat
validate-on="blur"
@@ -52,7 +52,7 @@
<v-card-actions class="justify-center">
<div class="max-button">
<v-btn
:loading="loading"
:loading="state.loading"
color="primary"
:disabled="token === ''"
type="submit"
@@ -81,14 +81,12 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import { validators } from "@/composables/use-validators";
import { useRouteQuery } from "~/composables/use-router";
export default defineNuxtComponent({
setup() {
definePageMeta({
layout: "basic",
});
@@ -139,16 +137,6 @@ export default defineNuxtComponent({
alert.error(i18n.t("events.something-went-wrong"));
}
}
return {
passwordMatch,
token,
requestLink,
validators,
...toRefs(state),
};
},
});
</script>
<style lang="css">

View File

@@ -331,7 +331,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { VueDraggable } from "vue-draggable-plus";
import RecipeList from "~/components/Domain/Recipe/RecipeList.vue";
import MultiPurposeLabelSection from "~/components/Domain/ShoppingList/MultiPurposeLabelSection.vue";
@@ -339,29 +339,15 @@ import ShoppingListItem from "~/components/Domain/ShoppingList/ShoppingListItem.
import ShoppingListItemEditor from "~/components/Domain/ShoppingList/ShoppingListItemEditor.vue";
import { useShoppingListPage } from "~/composables/shopping-list-page/use-shopping-list-page";
import { useFoodStore, useLabelStore, useUnitStore } from "~/composables/store";
import { getTextColor } from "~/composables/use-text-color";
import { useShoppingListPreferences } from "~/composables/use-users/preferences";
export default defineNuxtComponent({
components: {
VueDraggable,
MultiPurposeLabelSection,
ShoppingListItem,
RecipeList,
ShoppingListItemEditor,
},
setup() {
const { mdAndUp } = useDisplay();
const i18n = useI18n();
const auth = useMealieAuth();
const preferences = useShoppingListPreferences();
useSeoMeta({
title: i18n.t("shopping-list.shopping-list"),
});
const route = useRoute();
const groupSlug = computed(() => route.params.groupSlug as string || auth.user.value?.groupSlug || "");
const id = route.params.id as string;
const shoppingListPage = useShoppingListPage(id);
@@ -369,18 +355,40 @@ export default defineNuxtComponent({
const { store: allUnits } = useUnitStore();
const { store: allFoods } = useFoodStore();
return {
groupSlug,
preferences,
allLabels,
allUnits,
allFoods,
getTextColor,
mdAndUp,
...shoppingListPage,
};
},
});
const {
shoppingList,
state,
checkAll,
uncheckAll,
deleteChecked,
reorderLabelsDialog,
localLabels,
saveLabelOrder,
cancelLabelOrder,
updateLabelOrder,
edit,
threeDot,
openCheckAll,
copyListItems,
toggleReorderLabelsDialog,
isOffline,
createEditorOpen,
createListItemData,
createListItem,
itemsByLabel,
getLabelColor,
loadingCounter,
updateIndexUncheckedByLabel,
recipeMap,
saveListItem,
deleteListItem,
listItems,
openUncheckAll,
openDeleteChecked,
recipeList,
removeRecipeReferenceToList,
addRecipeReferenceToList,
} = shoppingListPage;
</script>
<style>

View File

@@ -4,14 +4,14 @@
class="narrow-container"
>
<BaseDialog
v-model="createDialog"
v-model="state.createDialog"
:title="$t('shopping-list.create-shopping-list')"
can-submit
@submit="createOne"
>
<v-card-text>
<v-text-field
v-model="createName"
v-model="state.createName"
autofocus
:label="$t('shopping-list.new-list')"
/>
@@ -20,7 +20,7 @@
<!-- Settings -->
<BaseDialog
v-model="ownerDialog"
v-model="state.ownerDialog"
:icon="$globals.icons.admin"
:title="$t('user.edit-user')"
can-confirm
@@ -41,7 +41,7 @@
</BaseDialog>
<BaseDialog
v-model="deleteDialog"
v-model="state.deleteDialog"
:title="$t('general.confirm')"
color="error"
can-confirm
@@ -73,7 +73,7 @@
<BaseButton
create
class="my-0"
@click="createDialog = true"
@click="state.createDialog = true"
/>
</v-container>
@@ -123,15 +123,13 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import type { ShoppingListOut } from "~/lib/api/types/household";
import { useUserApi } from "~/composables/api";
import { useAsyncKey } from "~/composables/use-utils";
import { useShoppingListPreferences } from "~/composables/use-users/preferences";
import type { UserOut } from "~/lib/api/types/user";
export default defineNuxtComponent({
setup() {
const auth = useMealieAuth();
const i18n = useI18n();
const ready = ref(false);
@@ -142,7 +140,6 @@ export default defineNuxtComponent({
title: i18n.t("shopping-list.shopping-list"),
});
const groupSlug = computed(() => route.params.groupSlug || auth.user.value?.groupSlug || "");
const overrideDisableRedirect = ref(false);
const disableRedirect = computed(() => route.query.disableRedirect === "true" || overrideDisableRedirect.value);
const preferences = useShoppingListPreferences();
@@ -272,21 +269,4 @@ export default defineNuxtComponent({
refresh();
}
}
return {
...toRefs(state),
ready,
groupSlug,
preferences,
shoppingListChoices,
createOne,
toggleOwnerDialog,
allUsers,
updateUserId,
updateOwner,
deleteOne,
openDelete,
};
},
});
</script>

View File

@@ -14,14 +14,11 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
import { useLazyRecipes } from "~/composables/recipes";
import { useLoggedInState } from "~/composables/use-logged-in-state";
export default defineNuxtComponent({
components: { RecipeCardSection },
setup() {
const route = useRoute();
const i18n = useI18n();
const { isOwnGroup } = useLoggedInState();
@@ -33,18 +30,6 @@ export default defineNuxtComponent({
const userId = route.params.id;
const query = { queryFilter: `favoritedBy.id = "${userId}"` };
const { recipes, appendRecipes, assignSorted, removeRecipe, replaceRecipes } = useLazyRecipes();
return {
query,
recipes,
isOwnGroup,
appendRecipes,
assignSorted,
removeRecipe,
replaceRecipes,
};
},
});
</script>
<style scoped></style>

View File

@@ -106,13 +106,14 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import type { VForm } from "~/types/auto-forms";
export default defineNuxtComponent({
definePageMeta({
middleware: ["advanced-only"],
setup() {
});
const i18n = useI18n();
const auth = useMealieAuth();
@@ -164,8 +165,4 @@ export default defineNuxtComponent({
auth.refresh();
return data;
}
return { createToken, deleteToken, createdToken, loading, name, user, resetCreate };
},
});
</script>

View File

@@ -24,9 +24,9 @@
<section class="mt-5">
<ToggleState tag="article">
<template #activator="{ toggle, state }">
<template #activator="{ toggle, modelValue: toggleState }">
<v-btn
v-if="!state && $appInfo.allowPasswordLogin"
v-if="!toggleState && $appInfo.allowPasswordLogin"
color="info"
class="mt-2 mb-n3"
@click="toggle"
@@ -48,13 +48,13 @@
{{ $t("settings.profile") }}
</v-btn>
</template>
<template #default="{ state }">
<template #default="{ modelValue: toggleState }">
<v-slide-x-transition
leave-absolute
hide-on-leave
>
<div
v-if="!state"
v-if="!toggleState"
key="personal-info"
>
<BaseCardSectionTitle
@@ -214,22 +214,16 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import UserAvatar from "~/components/Domain/User/UserAvatar.vue";
import UserPasswordStrength from "~/components/Domain/User/UserPasswordStrength.vue";
import { validators } from "~/composables/use-validators";
import type { VForm } from "~/types/auto-forms";
import { useUserActivityPreferences } from "~/composables/use-users/preferences";
import useDefaultActivity from "~/composables/use-default-activity";
import { ActivityKey } from "~/lib/api/types/activity";
import type { UserBase } from "~/lib/api/types/user";
export default defineNuxtComponent({
components: {
UserAvatar,
UserPasswordStrength,
},
setup() {
const i18n = useI18n();
const auth = useMealieAuth();
const { getDefaultActivityLabels, getActivityLabel, getActivityKey } = useDefaultActivity();
@@ -246,15 +240,13 @@ export default defineNuxtComponent({
activityPreferences.value.defaultActivity = getActivityKey(i18n, selectedDefaultActivity.value) ?? ActivityKey.RECIPES;
});
const userCopy = ref({ ...user.value });
watch(user, () => {
userCopy.value = { ...user.value };
});
const userCopy = ref({ ...user.value });
const api = useUserApi();
const domUpdatePassword = ref<VForm | null>(null);
const showPassword = ref(false);
const password = reactive({
current: "",
newOne: "",
@@ -264,8 +256,26 @@ export default defineNuxtComponent({
const passwordsMatch = computed(() => password.newOne === password.newTwo && password.newOne.length > 0);
async function updateUser() {
if (!userCopy.value?.id) return;
const { response } = await api.users.updateOne(userCopy.value.id, userCopy.value);
const userData = userCopy.value;
if (!userData?.id || !userData.email) return;
const updatePayload: UserBase = {
id: userData.id,
username: userData.username,
fullName: userData.fullName,
email: userData.email,
authMethod: userData.authMethod,
admin: userData.admin,
group: userData.group,
household: userData.household,
advanced: userData.advanced,
canInvite: userData.canInvite,
canManage: userData.canManage,
canManageHousehold: userData.canManageHousehold,
canOrganize: userData.canOrganize,
};
const { response } = await api.users.updateOne(userData.id, updatePayload);
if (response?.status === 200) {
auth.refresh();
}
@@ -284,27 +294,4 @@ export default defineNuxtComponent({
console.log("Password Changed");
}
}
const state = reactive({
hideImage: false,
passwordLoading: false,
showPassword: false,
loading: false,
});
return {
...toRefs(state),
updateUser,
updatePassword,
userCopy,
selectedDefaultActivity,
activityOptions,
password,
domUpdatePassword,
passwordsMatch,
validators,
auth,
};
},
});
</script>

View File

@@ -274,7 +274,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import UserProfileLinkCard from "@/components/Domain/User/UserProfileLinkCard.vue";
import { useUserApi } from "~/composables/api";
import UserAvatar from "@/components/Domain/User/UserAvatar.vue";
@@ -283,16 +283,11 @@ import StatsCards from "~/components/global/StatsCards.vue";
import type { UserOut } from "~/lib/api/types/user";
import UserInviteDialog from "~/components/Domain/User/UserInviteDialog.vue";
export default defineNuxtComponent({
definePageMeta({
name: "UserProfile",
components: {
UserInviteDialog,
UserProfileLinkCard,
UserAvatar,
StatsCards,
},
scrollToTop: true,
async setup() {
});
const i18n = useI18n();
const auth = useMealieAuth();
const { $appInfo } = useNuxtApp();
@@ -365,16 +360,4 @@ export default defineNuxtComponent({
function getStatsTo(key: string) {
return statsTo.value[key] ?? "unknown";
}
return {
groupSlug,
getStatsTitle,
getStatsIcon,
getStatsTo,
inviteDialog,
stats,
user,
};
},
});
</script>