Pinia Store Error Fix
March 20, 2025 Β· AI Conversations
at setup (FullLayout.vue:8:20)
<script>
import { RouterView } from 'vue-router';
import VerticalSidebarVue from './vertical-sidebar/VerticalSidebar.vue';
import VerticalHeaderVue from './vertical-header/VerticalHeader.vue';
import Customizer from './customizer/CustomizerPanel.vue';
import FooterPanel from './footer/FooterPanel.vue';
import { useCustomizerStore } from '@/stores/customizer';
const customizer = useCustomizerStore();
</script>
pinia.js?v=5601174a:941 Uncaught (in promise) TypeError: Cannot destructure property 'state' of 'options' as it is undefined.
suggests that Pinia is unable to find the expected `state` property in the store's setup, possibly due to incorrect store initialization or a missing Pinia plugin.
### **Possible Causes and Fixes:**
#### 1. **Ensure Pinia is Properly Installed and Registered**
Make sure Pinia is installed in your project:
yarn add pinia
or
npm install pinia
Then, ensure you have registered Pinia in your `main.ts` (or `main.js`):
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
#### 2. **Check Your Customizer Store**
Ensure `useCustomizerStore` is properly defined in `@/stores/customizer.ts`. A proper Pinia store should be structured as follows:
import { defineStore } from 'pinia';
export const useCustomizerStore = defineStore({
id: 'customizer',
state: () => ({
fontTheme: 'default-font',
mini_sidebar: false,
inputBg: false,
Customizer_drawer: false,
}),
actions: {
SET_CUSTOMIZER_DRAWER(value: boolean) {
this.Customizer_drawer = value;
},
},
});
If you are using **the setup store syntax**, define it like this:
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useCustomizerStore = defineStore('customizer', () => {
const fontTheme = ref('default-font');
const mini_sidebar = ref(false);
const inputBg = ref(false);
const Customizer_drawer = ref(false);
function SET_CUSTOMIZER_DRAWER(value: boolean) {
Customizer_drawer.value = value;
}
return { fontTheme, mini_sidebar, inputBg, Customizer_drawer, SET_CUSTOMIZER_DRAWER };
});
#### 3. **Ensure Store Import and Usage is Correct**
In `FullLayout.vue`, verify that you're calling the store function correctly:
import { useCustomizerStore } from '@/stores/customizer';
const customizer = useCustomizerStore();
If using **Composition API**, ensure the store is properly called inside `setup`:
import { useCustomizerStore } from '@/stores/customizer';
import { storeToRefs } from 'pinia';
const customizer = useCustomizerStore();
const { fontTheme, mini_sidebar, inputBg, Customizer_drawer } = storeToRefs(customizer);
#### 4. **Restart Dev Server**
After making changes, restart your development server:
yarn dev
or
npm run dev
This will clear any potential stale caches and reload Pinia correctly.
### **Summary of Fixes**
1. Ensure Pinia is installed and registered in `main.ts`.
2. Check the structure of your `useCustomizerStore` store.
3. Ensure you are correctly calling and using `useCustomizerStore` inside `setup()`.
4. Restart your development server after making these changes.
Let me know if the issue persists! π
import { defineStore } from 'pinia';
import config from '@/config';
export const useCustomizerStore = defineStore({
id: 'customizer',
state: () => ({
Sidebar_drawer: config.Sidebar_drawer,
Customizer_drawer: config.Customizer_drawer,
mini_sidebar: config.mini_sidebar,
fontTheme: config.fontTheme,
inputBg: config.inputBg
}),
getters: {},
actions: {
SET_SIDEBAR_DRAWER() {
this.Sidebar_drawer = !this.Sidebar_drawer;
},
SET_MINI_SIDEBAR(payload: boolean) {
this.mini_sidebar = payload;
},
SET_CUSTOMIZER_DRAWER(payload: boolean) {
this.Customizer_drawer = payload;
},
SET_FONT(payload: string) {
this.fontTheme = payload;
}
}
});
TypeError: Cannot destructure property 'state' of 'options' as it is undefined.
it seems that the store might not be properly initialized. Below are potential fixes and debugging steps:
—
## π **Possible Issues & Fixes**
### 1οΈβ£ **Ensure Pinia is Properly Installed and Registered**
Since you're using Pinia, make sure it's installed and added to your project:
yarn add pinia
or
npm install pinia
Then, ensure it is **registered** in your `main.ts`:
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.use(router);
app.mount('#app');
—
### 2οΈβ£ **Refactor the Store to Use the Object Syntax Properly**
The `defineStore` function supports two types of syntax:
– **Object Syntax** (What you're using)
– **Setup Syntax** (Alternative)
#### β
**Fix: Use `state` and `actions` Correctly**
Modify your store like this:
import { defineStore } from 'pinia';
import config from '@/config';
export const useCustomizerStore = defineStore('customizer', {
state: () => ({
Sidebar_drawer: config.Sidebar_drawer ?? false,
Customizer_drawer: config.Customizer_drawer ?? false,
mini_sidebar: config.mini_sidebar ?? false,
fontTheme: config.fontTheme ?? 'default-font',
inputBg: config.inputBg ?? false
}),
actions: {
SET_SIDEBAR_DRAWER() {
this.Sidebar_drawer = !this.Sidebar_drawer;
},
SET_MINI_SIDEBAR(payload: boolean) {
this.mini_sidebar = payload;
},
SET_CUSTOMIZER_DRAWER(payload: boolean) {
this.Customizer_drawer = payload;
},
SET_FONT(payload: string) {
this.fontTheme = payload;
}
}
});
—
### 3οΈβ£ **Check the Import & Usage in `FullLayout.vue`**
Verify that the store is properly imported and used inside the `setup` function in `FullLayout.vue`:
#### β **Fix: Ensure Proper Store Import**
import { useCustomizerStore } from '@/stores/customizer';
import { storeToRefs } from 'pinia';
const customizer = useCustomizerStore();
const { fontTheme, mini_sidebar, inputBg, Customizer_drawer } = storeToRefs(customizer);
—
### 4οΈβ£ **Restart Your Dev Server**
Sometimes, Pinia caches old states or fails to pick up changes. Restart your server:
yarn dev
or
npm run dev
—
## π― **Final Summary**
β Ensure `pinia` is **installed and registered** in `main.ts`
β **Fix state initialization** in `customizer.ts` using `??` defaults
β Use `storeToRefs()` when **accessing state in Vue components**
β **Restart** the development server
—
Try these fixes, and let me know if the error persists! π
<script>
import { ref } from 'vue';
import Google from '@/assets/images/auth/social-google.svg';
import { useAuthStore } from '@/stores/auth';
import { Form } from 'vee-validate';
const checkbox = ref(false);
const valid = ref(false);
const show1 = ref(false);
//const logform = ref();
const password = ref('admin123');
const username = ref('info@codedthemes.com');
const passwordRules = ref([
(v: string) => !!v || 'Password is required',
(v: string) => (v && v.length <= 10) || 'Password must be less than 10 characters'
]);
const emailRules = ref([(v: string) => !!v || 'E-mail is required', (v: string) => /.+@.+..+/.test(v) || 'E-mail must be valid']);
/* eslint-disable @typescript-eslint/no-explicit-any */
function validate(values: any, { setErrors }: any) {
const authStore = useAuthStore();
return authStore.login(username.value, password.value).catch((error) => setErrors({ apiError: error }));
}
</script>
Sign in with Google
OR
Sign in with Email address
Forgot password?
Sign In
{{ errors.apiError }}
Don't Have an account?
<style>
.custom-devider {
border-color: rgba(0, 0, 0, 0.08) !important;
}
.googleBtn {
border-color: rgba(0, 0, 0, 0.08);
margin: 30px 0 20px 0;
}
.outlinedInput .v-field {
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: none;
}
.orbtn {
padding: 2px 40px;
border-color: rgba(0, 0, 0, 0.08);
margin: 20px 15px;
}
.pwdInput {
position: relative;
.v-input__append {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
}
.loginForm {
.v-text-field .v-field--active input {
font-weight: 500;
}
}
</style>
adjust below form like above
<script>
import { ref,inject,onMounted } from "vue";
import { useForm, useField } from 'vee-validate'
import { useAuthStore } from '@/stores/auth';
import { useRouter } from 'vue-router';
import publicApi from '@/publicApi';
import SingleColumn from '@/layouts/SingleColumn.vue';
import {signInWithGoogle, signInWithGithub} from '@/firebase';
import { useLoadingStore } from '@/stores/loading';
import { nextTick } from "vue";
const loadingStore = useLoadingStore();
const authStore = useAuthStore();
const router = useRouter();
const apiUrl = inject('apiUrl');
const showPassword = ref(false);
const user = ref(null);
const alertMessage=ref("");
const alertColor=ref("");
console.log(apiUrl);
const { handleSubmit, handleReset, values } = useForm({
validationSchema: {
email (value:string) {
if (/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/i.test(value)) return true
return 'Must be a valid e-mail.'
},
password (value:string) {
if (value?.length >= 6) return true
return 'Password needs to be at least 6 characters.'
}
},
})
const email = useField('email')
const password = useField('password')
const submit = handleSubmit(async (values) => {
loadingStore.setLoading(true);
alertMessage.value = "";
alertColor.value = "";
try {
const response = await publicApi.post(`${apiUrl}/login`, {
email: values.email,
password: values.password
});
console.log(response);
if (response.data.success) {
alertMessage.value = "Login successful!";
alertColor.value = 'success';
authStore.setUser(response.data.user, response.data.token);
router.push('/dashboard');
} else {
console.log(response.data);
alertMessage.value = response.data.message;
alertColor.value = 'error';
console.error("Login failed:", response.data.message);
}
} catch (error: any) {
console.log(error);
alertMessage.value =error.response?.data.message;
alertColor.value = 'error';
console.error("Error during login:", error.response?.data.message || error.message);
} finally {
loadingStore.setLoading(false);
}
})
onMounted(() => {
if (authStore.isAuthenticated) {
router.push("/dashboard"); // Redirect if already logged in
}
});
const getFirebaseToken = async (provider:string) => {
try {
// Sign in with Google or GitHub
const result = provider === "google" ? await signInWithGoogle() : await signInWithGithub();
//console.log(result);
// Get Firebase ID token
const idToken = await result.user.getIdToken();
console.log(result.user.displayName, result.user.email, result.user.photoURL, result.user.uid);
const userData = {
name: result.user.displayName,
email: result.user.email,
avatar: result.user.photoURL,
firebase_uid: result.user.uid,
id_token: idToken,
};
loadingStore.setLoading(true);
const response = await publicApi.post(`${apiUrl}/firebase-login`, {
name: result.user.displayName,
email: result.user.email,
avatar: result.user.photoURL,
firebase_uid: result.user.uid,
id_token: idToken,
});
console.log(result.user.displayName);
console.log(response);
if (response.data.success) {
alertMessage.value = "Login successful!";
alertColor.value = 'success';
authStore.setUser(response.data.user, response.data.token);
router.push('/dashboard');
} else {
console.log(response.data);
alertMessage.value = response.data.message;
alertColor.value = 'error';
console.error("Login failed:", response.data.message);
}
} catch (error: any) {
console.log("Error getting Firebase Token:", error);
alertMessage.value = error.response?.data.message;
alertColor.value = 'error';
console.error("Error during login:", error.response?.data.message || error.message);
} finally{
loadingStore.setLoading(false);
}
};
</script>
Login
login
clear
Forgot Password?
Login with Google
—
### **Key Adjustments**
1. **Use `vee-validate` Properly:**
– `useForm` is now handling the form submission.
– `useField` is used for validation.
2. **Proper Pinia Store Usage:**
– `useAuthStore()` is correctly initialized.
3. **Loading and Error Handling:**
– Properly manages UI feedback for login attempts.
4. **Google Authentication Support:**
– Integrated `getFirebaseToken` for social login.
—
### **Updated Code**
<script setup lang="ts">
import { ref, inject, onMounted } from "vue";
import { useForm, useField } from "vee-validate";
import { useAuthStore } from "@/stores/auth";
import { useRouter } from "vue-router";
import publicApi from "@/publicApi";
import SingleColumn from "@/layouts/SingleColumn.vue";
import { signInWithGoogle, signInWithGithub } from "@/firebase";
import { useLoadingStore } from "@/stores/loading";
const loadingStore = useLoadingStore();
const authStore = useAuthStore();
const router = useRouter();
const apiUrl = inject("apiUrl");
const showPassword = ref(false);
const alertMessage = ref("");
const alertColor = ref("");
const { handleSubmit, handleReset } = useForm({
validationSchema: {
email(value: string) {
if (/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/i.test(value))
return true;
return "Must be a valid e-mail.";
},
password(value: string) {
if (value?.length >= 6) return true;
return "Password needs to be at least 6 characters.";
},
},
});
const email = useField("email");
const password = useField("password");
const submit = handleSubmit(async (values) => {
loadingStore.setLoading(true);
alertMessage.value = "";
alertColor.value = "";
try {
const response = await publicApi.post(`${apiUrl}/login`, {
email: values.email,
password: values.password,
});
if (response.data.success) {
alertMessage.value = "Login successful!";
alertColor.value = "success";
authStore.setUser(response.data.user, response.data.token);
router.push("/dashboard");
} else {
alertMessage.value = response.data.message;
alertColor.value = "error";
}
} catch (error: any) {
alertMessage.value = error.response?.data.message || "Login failed.";
alertColor.value = "error";
} finally {
loadingStore.setLoading(false);
}
});
onMounted(() => {
if (authStore.isAuthenticated) {
router.push("/dashboard"); // Redirect if already logged in
}
});
const getFirebaseToken = async (provider: string) => {
try {
// Sign in with Google or GitHub
const result =
provider === "google" ? await signInWithGoogle() : await signInWithGithub();
const idToken = await result.user.getIdToken();
const userData = {
name: result.user.displayName,
email: result.user.email,
avatar: result.user.photoURL,
firebase_uid: result.user.uid,
id_token: idToken,
};
loadingStore.setLoading(true);
const response = await publicApi.post(`${apiUrl}/firebase-login`, userData);
if (response.data.success) {
alertMessage.value = "Login successful!";
alertColor.value = "success";
authStore.setUser(response.data.user, response.data.token);
router.push("/dashboard");
} else {
alertMessage.value = response.data.message;
alertColor.value = "error";
}
} catch (error: any) {
alertMessage.value = error.response?.data.message || "Authentication failed.";
alertColor.value = "error";
} finally {
loadingStore.setLoading(false);
}
};
</script>
<template>
<SingleColumn :md="12" :mt="4">
<h3 class="text-h4 text-center mb-4">Login</h3>
<v-card class="py-8 px-6 text-center mx-auto ma-4" elevation="12" max-width="600">
<v-sheet class="mx-auto mt-4 mb-4" max-width="600">
<form @submit.prevent="submit">
<v-text-field
v-model="email.value.value"
:error-messages="email.errorMessage.value"
label="E-mail"
variant="outlined"
></v-text-field>
<v-text-field
v-model="password.value.value"
:type="showPassword ? 'text' : 'password'"
:error-messages="password.errorMessage.value"
prepend-inner-icon="mdi-lock"
:append-inner-icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
@click:append-inner="showPassword = !showPassword"
label="Password"
variant="outlined"
></v-text-field>
<v-btn class="me-4" type="submit" :loading="loadingStore.isLoading">
Login
</v-btn>
<v-btn @click="handleReset"> Clear </v-btn>
</form>
<v-btn :to="`/forget-password`" color="primary" class="mt-2">Forgot Password?</v-btn>
<v-btn prepend-icon="mdi-google" color="primary" @click="getFirebaseToken('google')">
Login with Google
</v-btn>
</v-sheet>
</v-card>
<TheAlert v-if="alertMessage" :title="alertMessage" :color="alertColor" :icon="alertColor" />
</SingleColumn>
</template>
<style lang="scss">
.v-card {
text-align: center;
}
.v-text-field {
margin-bottom: 16px;
}
.v-btn {
margin-top: 16px;
}
</style>
—
### **πΉ Key Enhancements in This Code:**
β
**Uses `vee-validate` correctly** with `useForm` and `useField`
β
**Handles form submission and validation smoothly**
β
**Manages loading state** using `useLoadingStore`
β
**Improves UI feedback** with alerts and error messages
β
**Firebase authentication support** for Google login
Now, it should work as expected! Let me know if you need any modifications. π