Skip to content

Commit

Permalink
refactor: useModalController implementation, safely remove listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
Yizack committed Jul 21, 2024
1 parent 55dce0b commit a341ba0
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 60 deletions.
6 changes: 3 additions & 3 deletions app/components/bond/BondMarkers.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const props = defineProps({
});
const emit = defineEmits(["new", "delete", "select", "edit"]);
const { $bootstrap, $toasts } = useNuxtApp();
const { $toasts } = useNuxtApp();
const edit = ref(false);
const drag = ref(false);
Expand Down Expand Up @@ -61,7 +61,7 @@ const markerModal = (marker?: MappedLoveMarker) => {
location: `${marker.lat}, ${marker.lng}`
};
}
useModalController("marker", show => showModal.value = show);
useModalController("marker", showModal).show();
};
const deleteMarker = async (id: number) => {
Expand Down Expand Up @@ -108,7 +108,7 @@ const submitMarker = async () => {
emit("new", { marker });
}
$toasts.add({ message: form.value.id ? t("marker_updated") : t("marker_added"), success: true });
$bootstrap.hideModal("marker");
useModalController("marker").hide();
};
watch(() => props.markers, (value) => {
Expand Down
6 changes: 3 additions & 3 deletions app/components/bond/BondStories.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const props = defineProps({
});
const emit = defineEmits(["new", "delete"]);
const { $bootstrap, $toasts } = useNuxtApp();
const { $toasts } = useNuxtApp();
const { user } = useUserSession() as MappedLoveSessionComposable;
const deleteButton = ref<Record<number, boolean>>({});
Expand Down Expand Up @@ -45,7 +45,7 @@ const storyModal = (story?: MappedLoveStory) => {
form.value.marker = props.marker.id;
}
else form.value = { ...story, hash: story.hash };
useModalController("story", show => showModal.value = show);
useModalController("story", showModal).show();
};
const addImage = (event: Event) => {
Expand Down Expand Up @@ -84,7 +84,7 @@ const submitStory = async () => {
if (!story) return;
emit("new", { story, edit: Boolean(form.value.id) });
$toasts.add({ message: form.value.id ? t("story_updated") : t("story_added"), success: true });
$bootstrap.hideModal("story");
useModalController("story").hide();
};
watch(() => props.marker, () => {
Expand Down
6 changes: 3 additions & 3 deletions app/pages/app/premium/billing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ const requestRefund = async () => {
}).catch(() => null);
loading.value = false;
if (!res) return;
const { $toasts, $bootstrap } = useNuxtApp();
const { $toasts } = useNuxtApp();
$toasts.add({ message: t("refund_requested"), success: true });
$bootstrap.hideModal("refund");
useModalController("refund").hide();
refundForm.value.reason = "";
};
Expand Down Expand Up @@ -98,7 +98,7 @@ useSeo({
<p class="mb-0"><strong>{{ t("billing_manageable") }}</strong></p>
</div>
<div v-else-if="billing.subscription?.scheduled_change?.action === 'cancel'" class="text-center">
<button class="btn btn-lg btn-primary w-100 rounded-pill" @click="useModalController('refund');">{{ t("request_refund") }}</button>
<button class="btn btn-lg btn-primary w-100 rounded-pill" @click="useModalController('refund').show();">{{ t("request_refund") }}</button>
<a href="/legal/refund" target="_blank" class="small">{{ t("refund_info") }}</a>
</div>
<div v-else-if="billing.subscription?.management_urls" class="d-flex flex-column flex-lg-row gap-2">
Expand Down
82 changes: 44 additions & 38 deletions app/pages/map/[code].vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,53 +56,59 @@ const showModal = ref(false);
const openStory = (story: MappedLoveStory) => {
currentStory.value = story;
if (isMobile.value) expandCanvas.value = false;
useModalController("story", (show) => {
showModal.value = show;
if (!show) currentStory.value = undefined;
}, () => {
useModalController("story", showModal).show(() => {
document.querySelector(".modal-backdrop")?.classList.add("modal-map-backdrop");
});
};
onMounted(() => {
isMobile.value = isMobileScreen();
addEventListener("resize", () => {
isMobile.value = isMobileScreen();
});
watch(showModal, (show) => {
if (!show) currentStory.value = undefined;
});
mapInfo.value.addEventListener("hide.bs.offcanvas", () => {
$bootstrap.hideAllModals();
selected.value = 0;
});
const mapInfoHandler = () => {
$bootstrap.hideAllModals();
selected.value = 0;
};
const touch = {
startY: 0,
endY: 0
};
const touch = {
startY: 0,
endY: 0
};
canvasHeader.value.addEventListener("touchstart", (event) => {
touch.startY = event.changedTouches[0]!.screenY;
}, { passive: true });
canvasHeader.value.addEventListener("touchend", (event) => {
touch.endY = event.changedTouches[0]!.screenY;
if (touch.endY < touch.startY) {
expandCanvas.value = true;
return;
}
if (touch.endY > touch.startY) {
if (expandCanvas.value) expandCanvas.value = false;
return;
}
}, { passive: true });
const touchStartHandler = (event: TouchEvent) => {
touch.startY = event.changedTouches[0]!.screenY;
};
const touchEndHandler = (event: TouchEvent) => {
touch.endY = event.changedTouches[0]!.screenY;
if (touch.endY < touch.startY) {
expandCanvas.value = true;
return;
}
if (touch.endY > touch.startY) {
if (expandCanvas.value) expandCanvas.value = false;
return;
}
};
const resizeHandler = () => {
isMobile.value = isMobileScreen();
};
onMounted(() => {
isMobile.value = isMobileScreen();
addEventListener("resize", resizeHandler);
mapInfo.value.addEventListener("hide.bs.offcanvas", mapInfoHandler);
canvasHeader.value.addEventListener("touchstart", touchStartHandler, { passive: true });
canvasHeader.value.addEventListener("touchend", touchEndHandler, { passive: true });
});
onBeforeUnmount(() => {
canvasHeader.value.removeEventListener("touchstart", () => {}, false);
canvasHeader.value.removeEventListener("touchend", () => {}, false);
canvasBody.value.removeEventListener("touchstart", () => {}, false);
mapInfo.value.removeEventListener("hide.bs.offcanvas", () => {}, false);
removeEventListener("resize", resizeHandler);
canvasHeader.value.removeEventListener("touchstart", touchStartHandler);
canvasHeader.value.removeEventListener("touchend", touchEndHandler);
mapInfo.value.removeEventListener("hide.bs.offcanvas", mapInfoHandler);
$bootstrap.hideOffcanvas(mapInfo.value);
});
Expand Down
32 changes: 19 additions & 13 deletions app/utils/composables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,26 @@ export const useFormState = <T extends Record<string, unknown>>(initialState: T)
return { form, formReset };
};

export const useModalController = async (id: string, show?: (value: boolean) => void, callback?: () => void) => {
export const useModalController = (id: string, visible: Ref<boolean | undefined> = ref()) => {
const { $bootstrap } = useNuxtApp();
if (show) show(true);
await sleep(100);
const element = $bootstrap.showModal(id);
if (!element) return;
if (show) {
if (callback) callback();
const hideEvent = () => {
show(false);
element.removeEventListener("hidden.bs.modal", hideEvent);
};
element.addEventListener("hidden.bs.modal", hideEvent);
}
return {
show: async (callback?: () => void) => {
if (!visible.value) visible.value = true;
await sleep(100);
const element = $bootstrap.showModal(id);
if (!element) return;
if (visible.value) {
if (typeof callback === "function") callback();
const hideEvent = () => {
visible.value = false;
};
element.addEventListener("hidden.bs.modal", hideEvent, { once: true });
}
},
hide: () => {
$bootstrap.hideModal(id);
}
};
};

export const useSeo = (options: MappedLoveSeoOptions) => {
Expand Down

0 comments on commit a341ba0

Please sign in to comment.