@nuxt-customer-portal/service-requests 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +16 -0
- package/app/components/Admin/RequestDashboard.vue +64 -0
- package/app/components/Admin/RequestTable.vue +158 -0
- package/app/components/CustomerRequestDetail.vue +76 -0
- package/app/components/CustomerRequestForm.vue +143 -0
- package/app/components/ServiceRequestsDashboardAttention.vue +55 -0
- package/app/components/ServiceRequestsDashboardOverview.vue +55 -0
- package/app/components/StatusBadge.vue +16 -0
- package/app/composables/useAdminServiceRequests.ts +60 -0
- package/app/composables/usePaginatedServiceRequests.ts +21 -0
- package/app/composables/useServiceRequestAccess.ts +18 -0
- package/app/composables/useServiceRequestMenu.ts +34 -0
- package/app/composables/useServiceRequests.ts +134 -0
- package/app/composables/useServiceRequestsDashboard.ts +13 -0
- package/app/pages/admin/requests/[id].vue +140 -0
- package/app/pages/admin/requests/index.vue +55 -0
- package/app/pages/requests/[id].vue +161 -0
- package/app/pages/requests/index.vue +873 -0
- package/app/pages/requests/new.vue +37 -0
- package/app/plugins/service-requests-feature.ts +18 -0
- package/i18n/locales/en.json +97 -0
- package/i18n/locales/nl.json +97 -0
- package/migrations/0000_baseline.sql +30 -0
- package/migrations/0001_required_client.sql +6 -0
- package/migrations/meta/0000_snapshot.json +245 -0
- package/migrations/meta/_journal.json +13 -0
- package/nuxt.config.ts +29 -0
- package/package.json +53 -0
- package/portal.manifest.mjs +9 -0
- package/server/api/service-requests/[id].delete.ts +42 -0
- package/server/api/service-requests/[id].get.ts +39 -0
- package/server/api/service-requests/[id].patch.ts +44 -0
- package/server/api/service-requests/admin/[id].patch.ts +43 -0
- package/server/api/service-requests/admin/index.get.ts +19 -0
- package/server/api/service-requests/dashboard.get.ts +11 -0
- package/server/api/service-requests/index.get.ts +22 -0
- package/server/api/service-requests/index.post.ts +39 -0
- package/server/db/schema/service-requests.ts +78 -0
- package/server/plugins/openapi-contracts.ts +22 -0
- package/server/utils/service-request-repository.ts +185 -0
- package/server/utils/service-request-scope.ts +41 -0
- package/server/utils/service-request-validation.ts +54 -0
- package/shared/feature.ts +90 -0
- package/shared/types/service-request.ts +111 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ServiceRequestCreateInput } from '@nuxt-customer-portal/service-requests/shared/types/service-request'
|
|
3
|
+
|
|
4
|
+
const { createRequest, loading } = useServiceRequests()
|
|
5
|
+
const toast = useToast()
|
|
6
|
+
const { t } = useI18n()
|
|
7
|
+
|
|
8
|
+
useSeoMeta({
|
|
9
|
+
title: () => t('features.serviceRequests.create')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const handleSubmit = async (data: ServiceRequestCreateInput) => {
|
|
13
|
+
try {
|
|
14
|
+
await createRequest(data)
|
|
15
|
+
toast.add({
|
|
16
|
+
title: t('common.success'),
|
|
17
|
+
description: t('features.serviceRequests.messages.createSuccess')
|
|
18
|
+
})
|
|
19
|
+
navigateTo('/requests')
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(error)
|
|
22
|
+
toast.add({
|
|
23
|
+
title: t('common.error'),
|
|
24
|
+
description: t('features.serviceRequests.messages.createError'),
|
|
25
|
+
color: 'error'
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div class="container mx-auto py-8 max-w-2xl">
|
|
33
|
+
<h1 class="text-3xl font-bold mb-6">{{ t('features.serviceRequests.create') }}</h1>
|
|
34
|
+
|
|
35
|
+
<CustomerRequestForm :loading="loading" @submit="handleSubmit" @cancel="navigateTo('/requests')" />
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { serviceRequestFeature } from '@nuxt-customer-portal/service-requests/shared/feature'
|
|
2
|
+
|
|
3
|
+
export default defineNuxtPlugin(() => {
|
|
4
|
+
const { registerFeature } = usePortalFeatures()
|
|
5
|
+
const { activeOrganizationRole, activeOrganizationType } = usePortalSession()
|
|
6
|
+
const register = () => {
|
|
7
|
+
const canManage =
|
|
8
|
+
activeOrganizationType.value === 'PROVIDER' &&
|
|
9
|
+
(activeOrganizationRole.value === 'owner' || activeOrganizationRole.value === 'admin')
|
|
10
|
+
registerFeature({
|
|
11
|
+
...serviceRequestFeature,
|
|
12
|
+
dashboardWidgets: serviceRequestFeature.dashboardWidgets?.filter(
|
|
13
|
+
(widget) => widget.id !== 'service-requests-attention' || canManage
|
|
14
|
+
)
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
watch([activeOrganizationRole, activeOrganizationType], register, { immediate: true })
|
|
18
|
+
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"features": {
|
|
3
|
+
"serviceRequests": {
|
|
4
|
+
"title": "Service Requests",
|
|
5
|
+
"resultCount": "{count} Service Request | {count} Service Requests",
|
|
6
|
+
"create": "Create Request",
|
|
7
|
+
"edit": "Edit Request",
|
|
8
|
+
"delete": "Delete Request",
|
|
9
|
+
"navigation": {
|
|
10
|
+
"myRequests": "Service Requests",
|
|
11
|
+
"manageRequests": "Manage Service Requests",
|
|
12
|
+
"newRequest": "New request"
|
|
13
|
+
},
|
|
14
|
+
"dashboard": {
|
|
15
|
+
"error": "Service requests could not be loaded.",
|
|
16
|
+
"retry": "Try again",
|
|
17
|
+
"new": "New request",
|
|
18
|
+
"viewAll": "View all",
|
|
19
|
+
"manage": "Manage requests",
|
|
20
|
+
"active": "{count} active",
|
|
21
|
+
"resolved": "{count} resolved",
|
|
22
|
+
"urgent": "{count} urgent",
|
|
23
|
+
"unassigned": "{count} unassigned",
|
|
24
|
+
"longOpen": "{count} open over 7 days",
|
|
25
|
+
"overview": {
|
|
26
|
+
"title": "Service requests",
|
|
27
|
+
"empty": "No service requests yet."
|
|
28
|
+
},
|
|
29
|
+
"attention": {
|
|
30
|
+
"title": "Requests needing attention",
|
|
31
|
+
"empty": "No requests currently need attention."
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"status": {
|
|
35
|
+
"open": "Open",
|
|
36
|
+
"in_progress": "In Progress",
|
|
37
|
+
"resolved": "Resolved",
|
|
38
|
+
"closed": "Closed"
|
|
39
|
+
},
|
|
40
|
+
"priority": {
|
|
41
|
+
"low": "Low",
|
|
42
|
+
"medium": "Medium",
|
|
43
|
+
"high": "High",
|
|
44
|
+
"urgent": "Urgent"
|
|
45
|
+
},
|
|
46
|
+
"filters": {
|
|
47
|
+
"title": "Filters",
|
|
48
|
+
"allStatuses": "All statuses",
|
|
49
|
+
"allPriorities": "All priorities",
|
|
50
|
+
"allCategories": "All categories",
|
|
51
|
+
"status": "Filter by status",
|
|
52
|
+
"priority": "Filter by priority",
|
|
53
|
+
"category": "Filter by category"
|
|
54
|
+
},
|
|
55
|
+
"fields": {
|
|
56
|
+
"title": "Title",
|
|
57
|
+
"client": "Client",
|
|
58
|
+
"description": "Description",
|
|
59
|
+
"priority": "Priority",
|
|
60
|
+
"category": "Category",
|
|
61
|
+
"status": "Status",
|
|
62
|
+
"createdBy": "Created by",
|
|
63
|
+
"assignedTo": "Assigned to",
|
|
64
|
+
"createdAt": "Created at",
|
|
65
|
+
"resolvedAt": "Resolved at",
|
|
66
|
+
"internalNotes": "Internal notes"
|
|
67
|
+
},
|
|
68
|
+
"actions": {
|
|
69
|
+
"back": "Back to requests",
|
|
70
|
+
"view": "View",
|
|
71
|
+
"assign": "Assign",
|
|
72
|
+
"resolve": "Resolve",
|
|
73
|
+
"close": "Close",
|
|
74
|
+
"saveChanges": "Save changes",
|
|
75
|
+
"adminActions": "Admin actions"
|
|
76
|
+
},
|
|
77
|
+
"placeholders": {
|
|
78
|
+
"category": "e.g. Technical, Billing, General",
|
|
79
|
+
"selectUser": "Select user",
|
|
80
|
+
"internalNotes": "Notes visible only to administrators"
|
|
81
|
+
},
|
|
82
|
+
"messages": {
|
|
83
|
+
"createSuccess": "Service request created successfully",
|
|
84
|
+
"updateSuccess": "Service request updated successfully",
|
|
85
|
+
"deleteSuccess": "Service request deleted successfully",
|
|
86
|
+
"fetchError": "Failed to load service requests",
|
|
87
|
+
"createError": "Failed to create service request",
|
|
88
|
+
"updateError": "Failed to update service request",
|
|
89
|
+
"deleteError": "Failed to delete service request",
|
|
90
|
+
"notFound": "Request not found",
|
|
91
|
+
"empty": "No service requests found",
|
|
92
|
+
"endOfList": "You've reached the end"
|
|
93
|
+
},
|
|
94
|
+
"confirmDelete": "Are you sure you want to delete this service request? This action cannot be undone."
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"features": {
|
|
3
|
+
"serviceRequests": {
|
|
4
|
+
"title": "Serviceaanvragen",
|
|
5
|
+
"resultCount": "{count} serviceaanvraag | {count} serviceaanvragen",
|
|
6
|
+
"create": "Aanvraag maken",
|
|
7
|
+
"edit": "Aanvraag bewerken",
|
|
8
|
+
"delete": "Aanvraag verwijderen",
|
|
9
|
+
"navigation": {
|
|
10
|
+
"myRequests": "Serviceaanvragen",
|
|
11
|
+
"manageRequests": "Serviceaanvragen beheren",
|
|
12
|
+
"newRequest": "Nieuwe aanvraag"
|
|
13
|
+
},
|
|
14
|
+
"dashboard": {
|
|
15
|
+
"error": "Serviceaanvragen konden niet worden geladen.",
|
|
16
|
+
"retry": "Opnieuw proberen",
|
|
17
|
+
"new": "Nieuwe aanvraag",
|
|
18
|
+
"viewAll": "Alles bekijken",
|
|
19
|
+
"manage": "Aanvragen beheren",
|
|
20
|
+
"active": "{count} actief",
|
|
21
|
+
"resolved": "{count} opgelost",
|
|
22
|
+
"urgent": "{count} urgent",
|
|
23
|
+
"unassigned": "{count} niet toegewezen",
|
|
24
|
+
"longOpen": "{count} langer dan 7 dagen open",
|
|
25
|
+
"overview": {
|
|
26
|
+
"title": "Serviceaanvragen",
|
|
27
|
+
"empty": "Nog geen serviceaanvragen."
|
|
28
|
+
},
|
|
29
|
+
"attention": {
|
|
30
|
+
"title": "Aanvragen die aandacht vragen",
|
|
31
|
+
"empty": "Geen aanvragen vragen momenteel aandacht."
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"status": {
|
|
35
|
+
"open": "Open",
|
|
36
|
+
"in_progress": "In behandeling",
|
|
37
|
+
"resolved": "Opgelost",
|
|
38
|
+
"closed": "Gesloten"
|
|
39
|
+
},
|
|
40
|
+
"priority": {
|
|
41
|
+
"low": "Laag",
|
|
42
|
+
"medium": "Gemiddeld",
|
|
43
|
+
"high": "Hoog",
|
|
44
|
+
"urgent": "Urgent"
|
|
45
|
+
},
|
|
46
|
+
"filters": {
|
|
47
|
+
"title": "Filters",
|
|
48
|
+
"allStatuses": "Alle statussen",
|
|
49
|
+
"allPriorities": "Alle prioriteiten",
|
|
50
|
+
"allCategories": "Alle categorieën",
|
|
51
|
+
"status": "Filter op status",
|
|
52
|
+
"priority": "Filter op prioriteit",
|
|
53
|
+
"category": "Filter op categorie"
|
|
54
|
+
},
|
|
55
|
+
"fields": {
|
|
56
|
+
"title": "Titel",
|
|
57
|
+
"client": "Klant",
|
|
58
|
+
"description": "Beschrijving",
|
|
59
|
+
"priority": "Prioriteit",
|
|
60
|
+
"category": "Categorie",
|
|
61
|
+
"status": "Status",
|
|
62
|
+
"createdBy": "Aangemaakt door",
|
|
63
|
+
"assignedTo": "Toegewezen aan",
|
|
64
|
+
"createdAt": "Aangemaakt op",
|
|
65
|
+
"resolvedAt": "Opgelost op",
|
|
66
|
+
"internalNotes": "Interne notities"
|
|
67
|
+
},
|
|
68
|
+
"actions": {
|
|
69
|
+
"back": "Terug naar aanvragen",
|
|
70
|
+
"view": "Bekijken",
|
|
71
|
+
"assign": "Toewijzen",
|
|
72
|
+
"resolve": "Oplossen",
|
|
73
|
+
"close": "Sluiten",
|
|
74
|
+
"saveChanges": "Wijzigingen opslaan",
|
|
75
|
+
"adminActions": "Beheeracties"
|
|
76
|
+
},
|
|
77
|
+
"placeholders": {
|
|
78
|
+
"category": "bijv. Technisch, Facturatie, Algemeen",
|
|
79
|
+
"selectUser": "Selecteer gebruiker",
|
|
80
|
+
"internalNotes": "Notities die alleen voor beheerders zichtbaar zijn"
|
|
81
|
+
},
|
|
82
|
+
"messages": {
|
|
83
|
+
"createSuccess": "Serviceaanvraag succesvol aangemaakt",
|
|
84
|
+
"updateSuccess": "Serviceaanvraag succesvol bijgewerkt",
|
|
85
|
+
"deleteSuccess": "Serviceaanvraag succesvol verwijderd",
|
|
86
|
+
"fetchError": "Serviceaanvragen laden mislukt",
|
|
87
|
+
"createError": "Serviceaanvraag maken mislukt",
|
|
88
|
+
"updateError": "Serviceaanvraag bijwerken mislukt",
|
|
89
|
+
"deleteError": "Serviceaanvraag verwijderen mislukt",
|
|
90
|
+
"notFound": "Aanvraag niet gevonden",
|
|
91
|
+
"empty": "Geen serviceaanvragen gevonden",
|
|
92
|
+
"endOfList": "Je hebt het einde bereikt"
|
|
93
|
+
},
|
|
94
|
+
"confirmDelete": "Weet je zeker dat je deze serviceaanvraag wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt."
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
CREATE SCHEMA "service_requests";
|
|
2
|
+
--> statement-breakpoint
|
|
3
|
+
CREATE TYPE "service_requests"."ServiceRequestPriority" AS ENUM('LOW', 'MEDIUM', 'HIGH', 'URGENT');--> statement-breakpoint
|
|
4
|
+
CREATE TYPE "service_requests"."ServiceRequestStatus" AS ENUM('OPEN', 'IN_PROGRESS', 'RESOLVED', 'CLOSED');--> statement-breakpoint
|
|
5
|
+
CREATE TABLE "service_requests"."service_request" (
|
|
6
|
+
"id" text PRIMARY KEY NOT NULL,
|
|
7
|
+
"title" text NOT NULL,
|
|
8
|
+
"description" text NOT NULL,
|
|
9
|
+
"status" "service_requests"."ServiceRequestStatus" DEFAULT 'OPEN' NOT NULL,
|
|
10
|
+
"priority" "service_requests"."ServiceRequestPriority" DEFAULT 'MEDIUM' NOT NULL,
|
|
11
|
+
"category" text,
|
|
12
|
+
"organization_id" text NOT NULL,
|
|
13
|
+
"created_by_id" text NOT NULL,
|
|
14
|
+
"assigned_to_id" text,
|
|
15
|
+
"attachments" jsonb,
|
|
16
|
+
"internal_notes" text,
|
|
17
|
+
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
18
|
+
"updated_at" timestamp DEFAULT now() NOT NULL,
|
|
19
|
+
"resolved_at" timestamp,
|
|
20
|
+
"closed_at" timestamp
|
|
21
|
+
);
|
|
22
|
+
--> statement-breakpoint
|
|
23
|
+
ALTER TABLE "service_requests"."service_request" ADD CONSTRAINT "service_request_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
24
|
+
ALTER TABLE "service_requests"."service_request" ADD CONSTRAINT "service_request_created_by_id_user_id_fk" FOREIGN KEY ("created_by_id") REFERENCES "public"."user"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
25
|
+
ALTER TABLE "service_requests"."service_request" ADD CONSTRAINT "service_request_assigned_to_id_user_id_fk" FOREIGN KEY ("assigned_to_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
|
26
|
+
CREATE INDEX "service_request_organization_id_idx" ON "service_requests"."service_request" USING btree ("organization_id");--> statement-breakpoint
|
|
27
|
+
CREATE INDEX "service_request_created_by_id_idx" ON "service_requests"."service_request" USING btree ("created_by_id");--> statement-breakpoint
|
|
28
|
+
CREATE INDEX "service_request_assigned_to_id_idx" ON "service_requests"."service_request" USING btree ("assigned_to_id");--> statement-breakpoint
|
|
29
|
+
CREATE INDEX "service_request_status_idx" ON "service_requests"."service_request" USING btree ("status");--> statement-breakpoint
|
|
30
|
+
CREATE INDEX "service_request_created_at_idx" ON "service_requests"."service_request" USING btree ("created_at");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- Existing requests are intentionally not migrated: the legacy model has no reliable client relationship.
|
|
2
|
+
CREATE TABLE IF NOT EXISTS "service_requests"."legacy_service_request" AS
|
|
3
|
+
TABLE "service_requests"."service_request" WITH DATA;
|
|
4
|
+
TRUNCATE TABLE "service_requests"."service_request" CASCADE;
|
|
5
|
+
ALTER TABLE "service_requests"."service_request" ADD COLUMN IF NOT EXISTS "client_organization_id" text NOT NULL REFERENCES "organization"("id") ON DELETE restrict;
|
|
6
|
+
CREATE INDEX IF NOT EXISTS "service_request_client_organization_id_idx" ON "service_requests"."service_request" ("client_organization_id");
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "66a719da-55c8-4426-baac-3228c68d52ca",
|
|
3
|
+
"prevId": "00000000-0000-0000-0000-000000000000",
|
|
4
|
+
"version": "7",
|
|
5
|
+
"dialect": "postgresql",
|
|
6
|
+
"tables": {
|
|
7
|
+
"service_requests.service_request": {
|
|
8
|
+
"name": "service_request",
|
|
9
|
+
"schema": "service_requests",
|
|
10
|
+
"columns": {
|
|
11
|
+
"id": {
|
|
12
|
+
"name": "id",
|
|
13
|
+
"type": "text",
|
|
14
|
+
"primaryKey": true,
|
|
15
|
+
"notNull": true
|
|
16
|
+
},
|
|
17
|
+
"title": {
|
|
18
|
+
"name": "title",
|
|
19
|
+
"type": "text",
|
|
20
|
+
"primaryKey": false,
|
|
21
|
+
"notNull": true
|
|
22
|
+
},
|
|
23
|
+
"description": {
|
|
24
|
+
"name": "description",
|
|
25
|
+
"type": "text",
|
|
26
|
+
"primaryKey": false,
|
|
27
|
+
"notNull": true
|
|
28
|
+
},
|
|
29
|
+
"status": {
|
|
30
|
+
"name": "status",
|
|
31
|
+
"type": "ServiceRequestStatus",
|
|
32
|
+
"typeSchema": "service_requests",
|
|
33
|
+
"primaryKey": false,
|
|
34
|
+
"notNull": true,
|
|
35
|
+
"default": "'OPEN'"
|
|
36
|
+
},
|
|
37
|
+
"priority": {
|
|
38
|
+
"name": "priority",
|
|
39
|
+
"type": "ServiceRequestPriority",
|
|
40
|
+
"typeSchema": "service_requests",
|
|
41
|
+
"primaryKey": false,
|
|
42
|
+
"notNull": true,
|
|
43
|
+
"default": "'MEDIUM'"
|
|
44
|
+
},
|
|
45
|
+
"category": {
|
|
46
|
+
"name": "category",
|
|
47
|
+
"type": "text",
|
|
48
|
+
"primaryKey": false,
|
|
49
|
+
"notNull": false
|
|
50
|
+
},
|
|
51
|
+
"organization_id": {
|
|
52
|
+
"name": "organization_id",
|
|
53
|
+
"type": "text",
|
|
54
|
+
"primaryKey": false,
|
|
55
|
+
"notNull": true
|
|
56
|
+
},
|
|
57
|
+
"created_by_id": {
|
|
58
|
+
"name": "created_by_id",
|
|
59
|
+
"type": "text",
|
|
60
|
+
"primaryKey": false,
|
|
61
|
+
"notNull": true
|
|
62
|
+
},
|
|
63
|
+
"assigned_to_id": {
|
|
64
|
+
"name": "assigned_to_id",
|
|
65
|
+
"type": "text",
|
|
66
|
+
"primaryKey": false,
|
|
67
|
+
"notNull": false
|
|
68
|
+
},
|
|
69
|
+
"attachments": {
|
|
70
|
+
"name": "attachments",
|
|
71
|
+
"type": "jsonb",
|
|
72
|
+
"primaryKey": false,
|
|
73
|
+
"notNull": false
|
|
74
|
+
},
|
|
75
|
+
"internal_notes": {
|
|
76
|
+
"name": "internal_notes",
|
|
77
|
+
"type": "text",
|
|
78
|
+
"primaryKey": false,
|
|
79
|
+
"notNull": false
|
|
80
|
+
},
|
|
81
|
+
"created_at": {
|
|
82
|
+
"name": "created_at",
|
|
83
|
+
"type": "timestamp",
|
|
84
|
+
"primaryKey": false,
|
|
85
|
+
"notNull": true,
|
|
86
|
+
"default": "now()"
|
|
87
|
+
},
|
|
88
|
+
"updated_at": {
|
|
89
|
+
"name": "updated_at",
|
|
90
|
+
"type": "timestamp",
|
|
91
|
+
"primaryKey": false,
|
|
92
|
+
"notNull": true,
|
|
93
|
+
"default": "now()"
|
|
94
|
+
},
|
|
95
|
+
"resolved_at": {
|
|
96
|
+
"name": "resolved_at",
|
|
97
|
+
"type": "timestamp",
|
|
98
|
+
"primaryKey": false,
|
|
99
|
+
"notNull": false
|
|
100
|
+
},
|
|
101
|
+
"closed_at": {
|
|
102
|
+
"name": "closed_at",
|
|
103
|
+
"type": "timestamp",
|
|
104
|
+
"primaryKey": false,
|
|
105
|
+
"notNull": false
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"indexes": {
|
|
109
|
+
"service_request_organization_id_idx": {
|
|
110
|
+
"name": "service_request_organization_id_idx",
|
|
111
|
+
"columns": [
|
|
112
|
+
{
|
|
113
|
+
"expression": "organization_id",
|
|
114
|
+
"isExpression": false,
|
|
115
|
+
"asc": true,
|
|
116
|
+
"nulls": "last"
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"isUnique": false,
|
|
120
|
+
"concurrently": false,
|
|
121
|
+
"method": "btree",
|
|
122
|
+
"with": {}
|
|
123
|
+
},
|
|
124
|
+
"service_request_created_by_id_idx": {
|
|
125
|
+
"name": "service_request_created_by_id_idx",
|
|
126
|
+
"columns": [
|
|
127
|
+
{
|
|
128
|
+
"expression": "created_by_id",
|
|
129
|
+
"isExpression": false,
|
|
130
|
+
"asc": true,
|
|
131
|
+
"nulls": "last"
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"isUnique": false,
|
|
135
|
+
"concurrently": false,
|
|
136
|
+
"method": "btree",
|
|
137
|
+
"with": {}
|
|
138
|
+
},
|
|
139
|
+
"service_request_assigned_to_id_idx": {
|
|
140
|
+
"name": "service_request_assigned_to_id_idx",
|
|
141
|
+
"columns": [
|
|
142
|
+
{
|
|
143
|
+
"expression": "assigned_to_id",
|
|
144
|
+
"isExpression": false,
|
|
145
|
+
"asc": true,
|
|
146
|
+
"nulls": "last"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"isUnique": false,
|
|
150
|
+
"concurrently": false,
|
|
151
|
+
"method": "btree",
|
|
152
|
+
"with": {}
|
|
153
|
+
},
|
|
154
|
+
"service_request_status_idx": {
|
|
155
|
+
"name": "service_request_status_idx",
|
|
156
|
+
"columns": [
|
|
157
|
+
{
|
|
158
|
+
"expression": "status",
|
|
159
|
+
"isExpression": false,
|
|
160
|
+
"asc": true,
|
|
161
|
+
"nulls": "last"
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"isUnique": false,
|
|
165
|
+
"concurrently": false,
|
|
166
|
+
"method": "btree",
|
|
167
|
+
"with": {}
|
|
168
|
+
},
|
|
169
|
+
"service_request_created_at_idx": {
|
|
170
|
+
"name": "service_request_created_at_idx",
|
|
171
|
+
"columns": [
|
|
172
|
+
{
|
|
173
|
+
"expression": "created_at",
|
|
174
|
+
"isExpression": false,
|
|
175
|
+
"asc": true,
|
|
176
|
+
"nulls": "last"
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
"isUnique": false,
|
|
180
|
+
"concurrently": false,
|
|
181
|
+
"method": "btree",
|
|
182
|
+
"with": {}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"foreignKeys": {
|
|
186
|
+
"service_request_organization_id_organization_id_fk": {
|
|
187
|
+
"name": "service_request_organization_id_organization_id_fk",
|
|
188
|
+
"tableFrom": "service_request",
|
|
189
|
+
"tableTo": "organization",
|
|
190
|
+
"columnsFrom": ["organization_id"],
|
|
191
|
+
"columnsTo": ["id"],
|
|
192
|
+
"onDelete": "cascade",
|
|
193
|
+
"onUpdate": "no action"
|
|
194
|
+
},
|
|
195
|
+
"service_request_created_by_id_user_id_fk": {
|
|
196
|
+
"name": "service_request_created_by_id_user_id_fk",
|
|
197
|
+
"tableFrom": "service_request",
|
|
198
|
+
"tableTo": "user",
|
|
199
|
+
"columnsFrom": ["created_by_id"],
|
|
200
|
+
"columnsTo": ["id"],
|
|
201
|
+
"onDelete": "restrict",
|
|
202
|
+
"onUpdate": "no action"
|
|
203
|
+
},
|
|
204
|
+
"service_request_assigned_to_id_user_id_fk": {
|
|
205
|
+
"name": "service_request_assigned_to_id_user_id_fk",
|
|
206
|
+
"tableFrom": "service_request",
|
|
207
|
+
"tableTo": "user",
|
|
208
|
+
"columnsFrom": ["assigned_to_id"],
|
|
209
|
+
"columnsTo": ["id"],
|
|
210
|
+
"onDelete": "set null",
|
|
211
|
+
"onUpdate": "no action"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
"compositePrimaryKeys": {},
|
|
215
|
+
"uniqueConstraints": {},
|
|
216
|
+
"policies": {},
|
|
217
|
+
"checkConstraints": {},
|
|
218
|
+
"isRLSEnabled": false
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"enums": {
|
|
222
|
+
"service_requests.ServiceRequestPriority": {
|
|
223
|
+
"name": "ServiceRequestPriority",
|
|
224
|
+
"schema": "service_requests",
|
|
225
|
+
"values": ["LOW", "MEDIUM", "HIGH", "URGENT"]
|
|
226
|
+
},
|
|
227
|
+
"service_requests.ServiceRequestStatus": {
|
|
228
|
+
"name": "ServiceRequestStatus",
|
|
229
|
+
"schema": "service_requests",
|
|
230
|
+
"values": ["OPEN", "IN_PROGRESS", "RESOLVED", "CLOSED"]
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"schemas": {
|
|
234
|
+
"service_requests": "service_requests"
|
|
235
|
+
},
|
|
236
|
+
"sequences": {},
|
|
237
|
+
"roles": {},
|
|
238
|
+
"policies": {},
|
|
239
|
+
"views": {},
|
|
240
|
+
"_meta": {
|
|
241
|
+
"columns": {},
|
|
242
|
+
"schemas": {},
|
|
243
|
+
"tables": {}
|
|
244
|
+
}
|
|
245
|
+
}
|
package/nuxt.config.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url'
|
|
2
|
+
|
|
3
|
+
export default defineNuxtConfig({
|
|
4
|
+
$meta: { name: 'nuxt-customer-portal-service-requests' },
|
|
5
|
+
compatibilityDate: '2025-10-24',
|
|
6
|
+
modules: ['@nuxtjs/i18n'],
|
|
7
|
+
components: [
|
|
8
|
+
{
|
|
9
|
+
path: fileURLToPath(new URL('./app/components', import.meta.url)),
|
|
10
|
+
global: true
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
i18n: {
|
|
14
|
+
locales: [
|
|
15
|
+
{
|
|
16
|
+
code: 'en',
|
|
17
|
+
iso: 'en-US',
|
|
18
|
+
name: 'English',
|
|
19
|
+
file: 'en.json'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
code: 'nl',
|
|
23
|
+
iso: 'nl-NL',
|
|
24
|
+
name: 'Nederlands',
|
|
25
|
+
file: 'nl.json'
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
})
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuxt-customer-portal/service-requests",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"homepage": "https://nuxt-customer-portal.com",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/ludulicious/nuxt-customer-portal.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"main": "./nuxt.config.ts",
|
|
12
|
+
"files": [
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"CHANGELOG.md",
|
|
15
|
+
"app",
|
|
16
|
+
"i18n",
|
|
17
|
+
"migrations",
|
|
18
|
+
"server",
|
|
19
|
+
"shared",
|
|
20
|
+
"nuxt.config.ts",
|
|
21
|
+
"portal.manifest.mjs",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"exports": {
|
|
25
|
+
".": "./nuxt.config.ts",
|
|
26
|
+
"./feature": "./shared/feature.ts",
|
|
27
|
+
"./types": "./shared/types/service-request.ts",
|
|
28
|
+
"./schema": "./server/db/schema/service-requests.ts",
|
|
29
|
+
"./portal-manifest": "./portal.manifest.mjs",
|
|
30
|
+
"./app/*": "./app/*.ts",
|
|
31
|
+
"./server/*": "./server/*.ts",
|
|
32
|
+
"./shared/*": "./shared/*.ts"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@nuxtjs/i18n": "^10.6.0",
|
|
39
|
+
"@types/pg": "8.15.5",
|
|
40
|
+
"drizzle-orm": "^0.45.2",
|
|
41
|
+
"nanoid": "^5.1.6",
|
|
42
|
+
"pg": "^8.22.0",
|
|
43
|
+
"zod": "^4.4.3",
|
|
44
|
+
"@nuxt-customer-portal/core": "^0.3.0",
|
|
45
|
+
"@nuxt-customer-portal/clients": "^0.3.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"nuxt": "^4.5.1"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"nuxt": "^4.5.1"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
id: 'service-requests',
|
|
3
|
+
version: '0.3.0',
|
|
4
|
+
source: '@nuxt-customer-portal/service-requests',
|
|
5
|
+
clientModuleId: 'service-requests',
|
|
6
|
+
dependsOn: ['core', 'clients'],
|
|
7
|
+
schema: './server/db/schema/service-requests.ts',
|
|
8
|
+
migrations: './migrations'
|
|
9
|
+
}
|