diff --git a/Layout/default/VueViews/WorkorderCompanyPWA.php b/Layout/default/VueViews/WorkorderCompanyPWA.php
new file mode 100644
index 000000000..e545ec327
--- /dev/null
+++ b/Layout/default/VueViews/WorkorderCompanyPWA.php
@@ -0,0 +1,541 @@
+
+
+
+
+
+
+ Workorders
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/application/WorkorderCompany/WorkorderCompanyController.php b/application/WorkorderCompany/WorkorderCompanyController.php
index 646f0909c..9ecc8aada 100644
--- a/application/WorkorderCompany/WorkorderCompanyController.php
+++ b/application/WorkorderCompany/WorkorderCompanyController.php
@@ -30,6 +30,20 @@ class WorkorderCompanyController extends WorkorderBaseController {
parent::indexAction();
}
+ public function mobileAction() {
+ $company = WorkorderCompanyModel::getFirst(['addressId' => $this->user->address_id]);
+
+ $vue_config = [
+ 'BASE_PATH' => '/WorkorderCompany',
+ 'COMPANY_ID' => $company ? $company->id : 0,
+ // You can add more global variables for your Vue app here
+ ];
+
+ // This tells the framework to use your new PWA layout file
+ $this->layout()->setTemplate("VueViews/WorkorderCompanyPWA");
+ $this->layout()->set("JSGlobals", $vue_config);
+ }
+
protected function getAction() {
$pagination = $this->postData['pagination'] ?? ['page' => 1, 'per_page' => 10];
$filters = $this->postData['filters'] ?? [];
diff --git a/public/js/pages/WorkorderBase/WorkorderServiceWorker.js b/public/js/pages/WorkorderBase/WorkorderServiceWorker.js
new file mode 100644
index 000000000..4c1df3860
--- /dev/null
+++ b/public/js/pages/WorkorderBase/WorkorderServiceWorker.js
@@ -0,0 +1,73 @@
+const CACHE_NAME = 'workorder-company-cache-v1';
+const URLS_TO_CACHE = [
+ // We don't cache the root URL here as the scope is /WorkorderCompany/
+ '/WorkorderCompany/mobile', // The main entry point
+ // Add other assets like icons if you have them
+];
+
+// Install the service worker and cache essential assets
+self.addEventListener('install', event => {
+ event.waitUntil(
+ caches.open(CACHE_NAME)
+ .then(cache => {
+ console.log('Opened cache');
+ return cache.addAll(URLS_TO_CACHE);
+ })
+ );
+});
+
+// Serve cached content when offline
+self.addEventListener('fetch', event => {
+ // Only handle requests within the specified scope
+ if (event.request.url.includes('/WorkorderCompany/')) {
+ event.respondWith(
+ caches.match(event.request)
+ .then(response => {
+ // Cache hit - return response
+ if (response) {
+ return response;
+ }
+
+ // Not in cache, fetch from network
+ return fetch(event.request).then(
+ function(response) {
+ // Check if we received a valid response
+ if(!response || response.status !== 200 || response.type !== 'basic') {
+ return response;
+ }
+
+ // IMPORTANT: Clone the response. A response is a stream
+ // and because we want the browser to consume the response
+ // as well as the cache consuming the response, we need
+ // to clone it so we have two streams.
+ var responseToCache = response.clone();
+
+ caches.open(CACHE_NAME)
+ .then(function(cache) {
+ cache.put(event.request, responseToCache);
+ });
+
+ return response;
+ }
+ );
+ })
+ );
+ }
+ // For other requests, do nothing and let the browser handle it.
+});
+
+// Update the cache with new assets
+self.addEventListener('activate', event => {
+ const cacheWhitelist = [CACHE_NAME];
+ event.waitUntil(
+ caches.keys().then(cacheNames => {
+ return Promise.all(
+ cacheNames.map(cacheName => {
+ if (cacheWhitelist.indexOf(cacheName) === -1) {
+ return caches.delete(cacheName);
+ }
+ })
+ );
+ })
+ );
+});
diff --git a/public/js/pages/WorkorderBase/manifest.json b/public/js/pages/WorkorderBase/manifest.json
new file mode 100644
index 000000000..63ee4ec3d
--- /dev/null
+++ b/public/js/pages/WorkorderBase/manifest.json
@@ -0,0 +1,24 @@
+{
+ "name": "Workorder Company PWA",
+ "short_name": "Workorders",
+ "description": "A PWA for managing workorders efficiently on mobile devices.",
+ "start_url": "/WorkorderCompany/mobile",
+ "display": "standalone",
+ "background_color": "#f1f5f9",
+ "theme_color": "#4f46e5",
+ "orientation": "portrait-primary",
+ "icons": [
+ {
+ "src": "https://placehold.co/192x192/4f46e5/ffffff?text=WO",
+ "type": "image/png",
+ "sizes": "192x192",
+ "purpose": "any maskable"
+ },
+ {
+ "src": "https://placehold.co/512x512/4f46e5/ffffff?text=WO",
+ "type": "image/png",
+ "sizes": "512x512",
+ "purpose": "any maskable"
+ }
+ ]
+}