diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue
index 58cb12708..e836badec 100644
--- a/src/components/common/VnCard.vue
+++ b/src/components/common/VnCard.vue
@@ -20,6 +20,8 @@ const props = defineProps({
     searchUrl: { type: String, default: undefined },
     searchbarLabel: { type: String, default: '' },
     searchbarInfo: { type: String, default: '' },
+    searchCustomRouteRedirect: { type: String, default: undefined },
+    searchRedirect: { type: Boolean, default: false },
 });
 
 const stateStore = useStateStore();
@@ -62,6 +64,8 @@ watchEffect(() => {
                     :url="props.searchUrl"
                     :label="props.searchbarLabel"
                     :info="props.searchbarInfo"
+                    :custom-route-redirect-name="searchCustomRouteRedirect"
+                    :redirect="searchRedirect"
                 />
             </slot>
         </Teleport>
diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue
index 38dcf97d1..e5b2f02d2 100644
--- a/src/components/ui/VnSearchbar.vue
+++ b/src/components/ui/VnSearchbar.vue
@@ -1,5 +1,5 @@
 <script setup>
-import { onMounted, ref } from 'vue';
+import { onMounted, ref, watch } from 'vue';
 import { useQuasar } from 'quasar';
 import { useArrayData } from 'composables/useArrayData';
 import VnInput from 'src/components/common/VnInput.vue';
@@ -67,11 +67,19 @@ const props = defineProps({
     },
 });
 
-const arrayData = useArrayData(props.dataKey, { ...props });
-const { store } = arrayData;
+let arrayData = useArrayData(props.dataKey, { ...props });
+let store = arrayData.store;
 const searchText = ref('');
 const { navigate } = useRedirect();
 
+watch(
+    () => props.dataKey,
+    (val) => {
+        arrayData = useArrayData(val, { ...props });
+        store = arrayData.store;
+    }
+);
+
 onMounted(() => {
     const params = store.userParams;
     if (params && params.search) {
diff --git a/src/components/CreateDepartmentChild.vue b/src/pages/Worker/CreateDepartmentChild.vue
similarity index 100%
rename from src/components/CreateDepartmentChild.vue
rename to src/pages/Worker/CreateDepartmentChild.vue
diff --git a/src/pages/Worker/WorkerDepartment.vue b/src/pages/Worker/WorkerDepartment.vue
index 3c0e5fdd0..fe4c23051 100644
--- a/src/pages/Worker/WorkerDepartment.vue
+++ b/src/pages/Worker/WorkerDepartment.vue
@@ -1,10 +1,10 @@
 <script setup>
-import VnTree from 'components/ui/VnTree.vue';
+import WorkerDepartmentTree from './WorkerDepartmentTree.vue';
 </script>
 
 <template>
     <QPage class="column items-center q-pa-md">
-        <VnTree />
+        <WorkerDepartmentTree />
     </QPage>
 </template>
 
diff --git a/src/components/ui/VnTree.vue b/src/pages/Worker/WorkerDepartmentTree.vue
similarity index 99%
rename from src/components/ui/VnTree.vue
rename to src/pages/Worker/WorkerDepartmentTree.vue
index 928d045e9..34340b019 100644
--- a/src/components/ui/VnTree.vue
+++ b/src/pages/Worker/WorkerDepartmentTree.vue
@@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
 import { useState } from 'src/composables/useState';
 import { useQuasar } from 'quasar';
 import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
-import CreateDepartmentChild from '../CreateDepartmentChild.vue';
+import CreateDepartmentChild from './CreateDepartmentChild.vue';
 import axios from 'axios';
 import useNotify from 'src/composables/useNotify.js';
 import { useRouter } from 'vue-router';
diff --git a/src/pages/Zone/Card/ZoneCard.vue b/src/pages/Zone/Card/ZoneCard.vue
index f435893c0..1abbb78bf 100644
--- a/src/pages/Zone/Card/ZoneCard.vue
+++ b/src/pages/Zone/Card/ZoneCard.vue
@@ -5,38 +5,29 @@ import { computed } from 'vue';
 
 import VnCard from 'components/common/VnCard.vue';
 import ZoneDescriptor from './ZoneDescriptor.vue';
-import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
-
-import { useStateStore } from 'stores/useStateStore';
 
 const { t } = useI18n();
-const stateStore = useStateStore();
 const route = useRoute();
 
 const routeName = computed(() => route.name);
+const customRouteRedirectName = computed(() => {
+    if (routeName.value === 'ZoneLocations') return null;
+    return routeName.value;
+});
 const searchBarDataKeys = {
     ZoneWarehouses: 'ZoneWarehouses',
     ZoneSummary: 'ZoneSummary',
+    ZoneLocations: 'ZoneLocations',
 };
 </script>
 <template>
-    <template v-if="stateStore.isHeaderMounted()">
-        <Teleport to="#searchbar">
-            <VnSearchbar
-                :data-key="searchBarDataKeys[routeName]"
-                :custom-route-redirect-name="routeName"
-                :label="t('list.searchZone')"
-                :info="t('list.searchInfo')"
-            />
-        </Teleport>
-    </template>
     <VnCard
         data-key="Zone"
-        base-url="Zones"
         :descriptor="ZoneDescriptor"
-        searchbar-data-key="ZoneList"
-        searchbar-url="Zones"
-        searchbar-label="Search zones"
-        searchbar-info="You can search by zone reference"
+        :search-data-key="searchBarDataKeys[routeName]"
+        :search-custom-route-redirect="customRouteRedirectName"
+        :search-redirect="!!customRouteRedirectName"
+        :searchbar-label="t('list.searchZone')"
+        :searchbar-info="t('list.searchInfo')"
     />
 </template>
diff --git a/src/pages/Zone/Card/ZoneLocations.vue b/src/pages/Zone/Card/ZoneLocations.vue
index e4305c898..76a216215 100644
--- a/src/pages/Zone/Card/ZoneLocations.vue
+++ b/src/pages/Zone/Card/ZoneLocations.vue
@@ -1 +1,80 @@
-<template>Zone Locations</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+import { useRoute } from 'vue-router';
+
+import ZoneLocationsTree from './ZoneLocationsTree.vue';
+
+import axios from 'axios';
+
+const { t } = useI18n();
+const route = useRoute();
+
+const onSelected = async (val, node) => {
+    try {
+        if (val === null) val = undefined;
+        const params = { geoId: node.id, isIncluded: val };
+        await axios.post(`Zones/${route.params.id}/toggleIsIncluded`, params);
+    } catch (err) {
+        console.error('Error updating included', err);
+    }
+};
+</script>
+
+<template>
+    <QPage class="column items-center q-pa-md">
+        <QCard class="full-width q-pa-md" style="max-width: 800px">
+            <ZoneLocationsTree :root-label="t('zoneLocations.locations')">
+                <template #checkbox="{ node }">
+                    <QCheckbox
+                        v-if="node.id"
+                        v-model="node.selected"
+                        :label="node.name"
+                        @update:model-value="($event) => onSelected($event, node)"
+                        toggle-indeterminate
+                        color="transparent"
+                        :class="[
+                            'checkbox',
+                            node.selected
+                                ? '--checked'
+                                : node.selected == false
+                                ? '--unchecked'
+                                : '--indeterminate',
+                        ]"
+                    />
+                </template>
+            </ZoneLocationsTree>
+        </QCard>
+    </QPage>
+</template>
+
+<style lang="scss">
+.checkbox {
+    &.--checked {
+        .q-checkbox__bg {
+            border: 1px solid $info !important;
+        }
+        .q-checkbox__svg {
+            color: white !important;
+            background-color: $info !important;
+        }
+    }
+
+    &.--unchecked {
+        .q-checkbox__bg {
+            border: 1px solid $negative !important;
+        }
+        .q-checkbox__svg {
+            background-color: $negative !important;
+        }
+    }
+
+    &.--indeterminate {
+        .q-checkbox__bg {
+            border: 1px solid $white !important;
+        }
+        .q-checkbox__svg {
+            color: transparent !important;
+        }
+    }
+}
+</style>
diff --git a/src/pages/Zone/Card/ZoneLocationsTree.vue b/src/pages/Zone/Card/ZoneLocationsTree.vue
new file mode 100644
index 000000000..a42111592
--- /dev/null
+++ b/src/pages/Zone/Card/ZoneLocationsTree.vue
@@ -0,0 +1,172 @@
+<script setup>
+import { onMounted, ref, computed, watch } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { useRoute } from 'vue-router';
+
+import { useState } from 'src/composables/useState';
+import axios from 'axios';
+import { useArrayData } from 'composables/useArrayData';
+import { onUnmounted } from 'vue';
+
+const { t } = useI18n();
+const route = useRoute();
+const state = useState();
+
+const treeRef = ref();
+const expanded = ref([]);
+
+const arrayData = useArrayData('ZoneLocations', {
+    url: `Zones/${route.params.id}/getLeaves`,
+});
+const { store } = arrayData;
+const storeData = computed(() => store.data);
+
+const nodes = ref([
+    { id: null, name: t('zoneLocations.locations'), sons: true, childs: [{}] },
+]);
+
+const previousExpandedNodes = ref(new Set());
+
+const onNodeExpanded = async (nodeKeysArray) => {
+    let nodeKeysSet = new Set(nodeKeysArray);
+    const lastNodeKey = nodeKeysArray.at(-1);
+
+    if (!nodeKeysSet.has(null)) return;
+
+    const wasExpanded = !previousExpandedNodes.value.has(lastNodeKey);
+    if (wasExpanded) await fetchNodeLeaves(lastNodeKey);
+    else {
+        const difference = new Set(
+            [...previousExpandedNodes.value].filter((x) => !nodeKeysSet.has(x))
+        );
+        const collapsedNode = Array.from(difference).pop();
+        const node = treeRef.value?.getNodeByKey(collapsedNode);
+        const allNodeIds = getNodeIds(node);
+        expanded.value = expanded.value.filter((id) => !allNodeIds.includes(id));
+    }
+    previousExpandedNodes.value = nodeKeysSet;
+};
+
+const formatNodeSelected = (node) => {
+    if (node.selected === 1) node.selected = true;
+    else if (node.selected === 0) node.selected = false;
+
+    if (node.childs && node.childs.length > 0) {
+        expanded.value.push(node.id);
+
+        node.childs.forEach((childNode) => {
+            formatNodeSelected(childNode);
+        });
+    }
+
+    if (node.sons > 0 && !node.childs) node.childs = [{}];
+};
+
+const fetchNodeLeaves = async (nodeKey) => {
+    try {
+        const node = treeRef.value?.getNodeByKey(nodeKey);
+        if (!node || node.sons === 0) return;
+
+        const params = { parentId: node.id };
+        const response = await axios.get(`Zones/${route.params.id}/getLeaves`, {
+            params,
+        });
+        if (response.data) {
+            node.childs = response.data.map((n) => {
+                formatNodeSelected(n);
+                return n;
+            });
+        }
+
+        state.set('Tree', node);
+    } catch (err) {
+        console.error('Error fetching department leaves', err);
+        throw new Error();
+    }
+};
+
+function getNodeIds(node) {
+    let ids = [];
+    if (node.id) ids.push(node.id);
+
+    if (node.childs)
+        node.childs.forEach((child) => {
+            ids = ids.concat(getNodeIds(child));
+        });
+    return ids;
+}
+
+watch(storeData, async (val) => {
+    // Se triggerea cuando se actualiza el store.data, el cual es el resultado del fetch de la searchbar
+    nodes.value[0].childs = [...val];
+    const fetchedNodeKeys = val.flatMap(getNodeIds);
+    state.set('Tree', [...fetchedNodeKeys]);
+
+    if (store.userParams?.search === '') {
+        val.forEach((n) => {
+            formatNodeSelected(n);
+        });
+    } else {
+        for (let n of state.get('Tree')) {
+            await fetchNodeLeaves(n);
+        }
+        expanded.value = [null, ...fetchedNodeKeys];
+    }
+    previousExpandedNodes.value = new Set(expanded.value);
+});
+
+onMounted(async () => {
+    if (store.userParams?.search) {
+        await arrayData.fetch({ append: false });
+        return;
+    }
+    const stateTree = state.get('Tree');
+    const tree = stateTree ? [...state.get('Tree')] : [null];
+    const lastStateTree = state.get('TreeState');
+    if (tree) {
+        for (let n of tree) {
+            await fetchNodeLeaves(n);
+        }
+
+        if (lastStateTree) {
+            tree.push(lastStateTree);
+            await fetchNodeLeaves(lastStateTree);
+        }
+    }
+
+    setTimeout(() => {
+        if (lastStateTree) {
+            document.getElementById(lastStateTree).scrollIntoView();
+        }
+    }, 1000);
+
+    previousExpandedNodes.value = new Set(expanded.value);
+});
+
+onUnmounted(() => {
+    state.set('Tree', undefined);
+});
+</script>
+
+<template>
+    <QTree
+        ref="treeRef"
+        :nodes="nodes"
+        node-key="id"
+        label-key="name"
+        children-key="childs"
+        v-model:expanded="expanded"
+        @update:expanded="onNodeExpanded($event)"
+        :default-expand-all="true"
+    >
+        <template #default-header="{ node }">
+            <div
+                :id="node.id"
+                class="qtr row justify-between full-width q-pr-md cursor-pointer"
+            >
+                <span v-if="!node.id">{{ node.name }}</span>
+                <slot name="checkbox" :node="node" />
+            </div>
+        </template>
+    </QTree>
+</template>
diff --git a/src/pages/Zone/locale/en.yml b/src/pages/Zone/locale/en.yml
index bae89fda9..a1d741b84 100644
--- a/src/pages/Zone/locale/en.yml
+++ b/src/pages/Zone/locale/en.yml
@@ -42,6 +42,8 @@ summary:
 filterPanel:
     name: Name
     agencyModeFk: Agency
+zoneLocations:
+    locations: Locations
 deliveryPanel:
     pickup: Pick up
     delivery: Delivery
diff --git a/src/pages/Zone/locale/es.yml b/src/pages/Zone/locale/es.yml
index d74238a6e..d12c4f204 100644
--- a/src/pages/Zone/locale/es.yml
+++ b/src/pages/Zone/locale/es.yml
@@ -42,6 +42,8 @@ summary:
 filterPanel:
     name: Nombre
     agencyModeFk: Agencia
+zoneLocations:
+    locations: Localizaciones
 deliveryPanel:
     pickup: Recogida
     delivery: Entrega
diff --git a/src/router/modules/zone.js b/src/router/modules/zone.js
index c355856b1..cf2e5321e 100644
--- a/src/router/modules/zone.js
+++ b/src/router/modules/zone.js
@@ -106,7 +106,7 @@ export default {
                     path: 'location',
                     meta: {
                         title: 'locations',
-                        icon: 'vn:greuge',
+                        icon: 'my_location',
                     },
                     component: () => import('src/pages/Zone/Card/ZoneLocations.vue'),
                 },