Skip to content

Commit ea3e9eb

Browse files
author
Ahmed Osama
committed
fix: ensure clean state on logout and login
- Fix ShiftOpeningDialog to trigger initDialog on mount when already open using immediate watcher - Add resetAllDialogs method to clear all dialog states on logout - Fix PaymentDialog to use dynamic makeParams and guard against null posProfile - Add customer clearing to useInvoice clearCart function - Clear cart and dialogs on both logout and login page mount - Add backend validation for pos_profile parameter in get_payment_methods - Ensure router navigation to login page on logout
1 parent 1ed8d44 commit ea3e9eb

7 files changed

Lines changed: 117 additions & 18 deletions

File tree

POS/src/components/ShiftOpeningDialog.vue

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,19 @@ const paymentMethods = computed(() => {
235235
})
236236
237237
// Watch dialog open state
238-
watch(open, (isOpen) => {
239-
if (isOpen) {
240-
initDialog()
241-
} else {
242-
resetDialog()
243-
}
244-
})
238+
// Use { immediate: true } to ensure initDialog runs even when
239+
// the component mounts with open already true (e.g., after logout with dialog open)
240+
watch(
241+
open,
242+
(isOpen) => {
243+
if (isOpen) {
244+
initDialog()
245+
} else {
246+
resetDialog()
247+
}
248+
},
249+
{ immediate: true }
250+
)
245251
246252
watch(showClosingDialog, (isOpen) => {
247253
closingExistingShift.value = isOpen
@@ -252,13 +258,24 @@ watch(showClosingDialog, (isOpen) => {
252258
253259
async function initDialog() {
254260
step.value = 1
255-
profilesResource.fetch()
261+
selectedProfile.value = null
262+
existingShift.value = null
263+
openingBalances.value = {}
264+
dialogDataResource.reset()
256265
257-
// Check if user already has an open shift
258-
const checkResult = await checkOpeningShift.fetch()
259-
if (checkResult) {
260-
existingShift.value = checkResult
261-
step.value = 3
266+
try {
267+
// Await profile fetch to ensure data is loaded before proceeding
268+
await profilesResource.fetch()
269+
270+
// Check if user already has an open shift
271+
const checkResult = await checkOpeningShift.fetch()
272+
if (checkResult) {
273+
existingShift.value = checkResult
274+
step.value = 3
275+
}
276+
} catch (error) {
277+
console.error("Error initializing shift dialog:", error)
278+
// Error will be displayed via profilesResource.error in the UI
262279
}
263280
}
264281
@@ -267,6 +284,9 @@ function resetDialog() {
267284
selectedProfile.value = null
268285
openingBalances.value = {}
269286
existingShift.value = null
287+
profilesResource.reset()
288+
dialogDataResource.reset()
289+
createShiftResource.reset()
270290
}
271291
272292
function selectPosProfile(profile) {

POS/src/components/sale/PaymentDialog.vue

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,10 @@ const paymentEntries = ref([])
240240
241241
const paymentMethodsResource = createResource({
242242
url: "pos_next.api.pos_profile.get_payment_methods",
243-
params: {
244-
pos_profile: props.posProfile,
243+
makeParams() {
244+
return {
245+
pos_profile: props.posProfile,
246+
}
245247
},
246248
auto: false,
247249
onSuccess(data) {
@@ -256,6 +258,12 @@ const paymentMethodsResource = createResource({
256258
257259
// Load payment methods - from cache if offline, from server if online
258260
async function loadPaymentMethods() {
261+
// Guard: Don't load if posProfile is not set
262+
if (!props.posProfile) {
263+
console.warn("PaymentDialog: Cannot load payment methods - posProfile is not set")
264+
return
265+
}
266+
259267
if (props.isOffline) {
260268
// Load from cache when offline
261269
const cached = await getCachedPaymentMethods(props.posProfile)
@@ -268,7 +276,12 @@ async function loadPaymentMethods() {
268276
}
269277
} else {
270278
// Load from server when online
271-
paymentMethodsResource.reload()
279+
// Use fetch() instead of reload() for proper initialization
280+
try {
281+
await paymentMethodsResource.fetch()
282+
} catch (error) {
283+
console.error("Error loading payment methods:", error)
284+
}
272285
}
273286
}
274287

POS/src/composables/useInvoice.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ export function useInvoice() {
629629

630630
async function clearCart() {
631631
invoiceItems.value = []
632+
customer.value = null
632633
payments.value = []
633634
additionalDiscount.value = 0
634635
couponCode.value = null

POS/src/pages/Login.vue

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,19 @@
9696
</template>
9797

9898
<script setup>
99-
import { reactive, watch, ref } from "vue"
99+
import { reactive, watch, ref, onMounted } from "vue"
100100
import { useRouter } from "vue-router"
101101
import { session } from "../data/session"
102102
import ShiftOpeningDialog from "../components/ShiftOpeningDialog.vue"
103103
import { FeatherIcon } from "frappe-ui"
104+
import { useShift } from "../composables/useShift"
105+
import { usePOSCartStore } from "@/stores/posCart"
106+
import { usePOSUIStore } from "@/stores/posUI"
104107
105108
const router = useRouter()
109+
const { shiftState } = useShift()
110+
const cartStore = usePOSCartStore()
111+
const uiStore = usePOSUIStore()
106112
107113
const loginForm = reactive({
108114
email: "",
@@ -112,6 +118,33 @@ const loginForm = reactive({
112118
const showShiftDialog = ref(false)
113119
const showPassword = ref(false)
114120
121+
// Reset state when login page mounts
122+
onMounted(() => {
123+
// Clear login form
124+
loginForm.email = ""
125+
loginForm.password = ""
126+
showPassword.value = false
127+
showShiftDialog.value = false
128+
129+
// Clear any login errors
130+
if (session.login.error) {
131+
session.login.reset()
132+
}
133+
134+
// Clear cart and UI state to ensure clean slate
135+
cartStore.clearCart()
136+
uiStore.resetAllDialogs()
137+
138+
// Clear any stale shift state
139+
shiftState.value = {
140+
pos_opening_shift: null,
141+
pos_profile: null,
142+
company: null,
143+
isOpen: false,
144+
}
145+
localStorage.removeItem("pos_shift_data")
146+
})
147+
115148
function submit() {
116149
if (!loginForm.email || !loginForm.password) {
117150
return

POS/src/pages/POSSale.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,8 @@ function handleShiftClosed() {
904904
// Check if logout should happen after closing shift
905905
if (logoutAfterClose.value) {
906906
logoutAfterClose.value = false
907+
// Clear all dialog states to prevent stale state on next login
908+
uiStore.resetAllDialogs()
907909
session.logout.submit()
908910
} else {
909911
setTimeout(() => {
@@ -1279,7 +1281,10 @@ function getCurrentUser() {
12791281
12801282
function confirmLogout() {
12811283
logoutAfterClose.value = false
1282-
uiStore.showLogoutDialog = false
1284+
// Clear cart to prevent stale items on next login
1285+
cartStore.clearCart()
1286+
// Clear all dialog states to prevent stale state on next login
1287+
uiStore.resetAllDialogs()
12831288
session.logout.submit()
12841289
}
12851290

POS/src/stores/posUI.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,28 @@ export const usePOSUIStore = defineStore('posUI', () => {
127127
}
128128
}
129129

130+
function resetAllDialogs() {
131+
// Close all dialogs on logout to prevent stale state
132+
showPaymentDialog.value = false
133+
showCustomerDialog.value = false
134+
showSuccessDialog.value = false
135+
showOpenShiftDialog.value = false
136+
showCloseShiftDialog.value = false
137+
showDraftDialog.value = false
138+
showReturnDialog.value = false
139+
showCouponDialog.value = false
140+
showOffersDialog.value = false
141+
showBatchSerialDialog.value = false
142+
showHistoryDialog.value = false
143+
showOfflineInvoicesDialog.value = false
144+
showCreateCustomerDialog.value = false
145+
showClearCartDialog.value = false
146+
showLogoutDialog.value = false
147+
showItemSelectionDialog.value = false
148+
showErrorDialog.value = false
149+
clearError()
150+
}
151+
130152
return {
131153
// State
132154
isLoading,
@@ -177,5 +199,6 @@ export const usePOSUIStore = defineStore('posUI', () => {
177199
setResizing,
178200
updateLayoutBounds,
179201
clampLeftPanelWidth,
202+
resetAllDialogs,
180203
}
181204
})

pos_next/api/pos_profile.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ def get_pos_profile_data(pos_profile):
5959
def get_payment_methods(pos_profile):
6060
"""Get available payment methods from POS Profile"""
6161
try:
62+
# Validate pos_profile parameter
63+
if not pos_profile:
64+
frappe.throw(_("POS Profile is required"))
65+
6266
payment_methods = frappe.get_list(
6367
"POS Payment Method",
6468
filters={"parent": pos_profile},

0 commit comments

Comments
 (0)