diff --git a/.gitignore b/.gitignore index 557d98f..e97de80 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ # See http://help.github.com/ignore-files/ for more about ignoring files. # Compiled output -/dist /tmp /out-tsc /bazel-out diff --git a/package-lock.json b/package-lock.json index 5cfcdf1..f83c6d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "multer": "^1.4.5-lts.1", "ngx-cookie-service": "^16.1.0", "rxjs": "~7.8.0", + "stripe": "^14.19.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0", "tslib": "^2.3.0", @@ -12573,6 +12574,18 @@ "node": ">=6" } }, + "node_modules/stripe": { + "version": "14.19.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.19.0.tgz", + "integrity": "sha512-Je2USTpUib3hApIgoHXViLoYkDLp+AXdUJvJ6aMQ/AcvZK1PcC7N8nTceh+0gpdotX8izlWN4QyVdMcptubHBQ==", + "dependencies": { + "@types/node": ">=8.1.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/package.json b/package.json index 6180179..2843010 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "multer": "^1.4.5-lts.1", "ngx-cookie-service": "^16.1.0", "rxjs": "~7.8.0", + "stripe": "^14.19.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0", "tslib": "^2.3.0", diff --git a/server/api/invoice.yaml b/server/api/invoice.yaml index b25ed90..a18fde4 100644 --- a/server/api/invoice.yaml +++ b/server/api/invoice.yaml @@ -123,4 +123,62 @@ paths: example: "Internal Server Error" error: type: string + /api/invoice/search: + get: + tags: + - Invoices + summary: Search invoices by customer's first and last name + description: API endpoint to search for invoices based on the customer's first and last name. + operationId: searchInvoicesByName + parameters: + - name: firstName + in: query + description: The first name of the customer + required: true + schema: + type: string + - name: lastName + in: query + description: The last name of the customer + required: true + schema: + type: string + responses: + '200': + description: Query successful + content: + application/json: + schema: + type: array + items: + type: object + properties: + userName: + type: string + lineItems: + type: array + items: + type: object + properties: + title: + type: string + price: + type: number + partsAmount: + type: number + laborAmount: + type: number + lineItemTotal: + type: number + total: + type: number + firstName: + type: string + lastName: + type: string + '404': + description: No invoices found + '500': + description: Internal server error + diff --git a/server/models/invoice.js b/server/models/invoice.js index dac65e9..cbc6642 100644 --- a/server/models/invoice.js +++ b/server/models/invoice.js @@ -22,7 +22,8 @@ const invoiceSchema = new Schema({ orderDate: { type: Date, default: new Date() }, firstName: { type: String }, lastName: { type: String }, - status: { type: String, default: "Pending" } + status: { type: String, default: "Pending" }, + payStatus: { type: String, default: "Unpaid" } }); // Export Schema diff --git a/server/routes/invoiceApi.js b/server/routes/invoiceApi.js index 9d146bf..629f85e 100644 --- a/server/routes/invoiceApi.js +++ b/server/routes/invoiceApi.js @@ -105,10 +105,15 @@ router.get("/all", async (req, res) => { // Update invoices router.put("/:invoiceId", async (req, res) => { const { invoiceId } = req.params; - const { status } = req.body; + const { status, payStatus } = req.body; try { - const updatedInvoice = await Invoice.findByIdAndUpdate(invoiceId, { status }, { new: true }); + const updatedInvoice = await Invoice.findByIdAndUpdate( + invoiceId, + { $set: { status: status, payStatus: payStatus } }, + { new: true } + ); + res.status(200).json({ status: "200", message: "Invoice status updated successfully", @@ -124,5 +129,46 @@ router.put("/:invoiceId", async (req, res) => { } }); +// Search for Invoices by First Name and Last Name +router.get("/search", async (req, res) => { + const { firstName, lastName } = req.query; + + // Check if both firstName and lastName are provided + if (!firstName || !lastName) { + return res.status(400).json({ + status: "400", + message: "Both firstName and lastName are required" + }); + } + + try { + // Use the find method to search for invoices with the given firstName and lastName + const invoices = await Invoice.find({ firstName: firstName, lastName: lastName }); + + // Check if any invoices are found + if (!invoices.length) { + return res.status(404).json({ + status: "404", + message: "No invoices found with the provided firstName and lastName" + }); + } + + // Return the found invoices + res.status(200).json({ + status: "200", + message: "Query successful", + data: invoices + }); + + } catch (e) { + console.error(e); + res.status(500).json({ + status: "500", + message: "Internal Server Error", + error: e.message + }); + } +}); + module.exports = router; \ No newline at end of file diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index b8a5fa9..54414a0 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -28,6 +28,8 @@ import { MyProfileComponent } from './my-profile/my-profile.component'; import { ServiceRepairComponent } from './service-repair/service-repair.component'; import { InvoiceSummaryComponent } from './invoice-summary/invoice-summary.component'; import { ViewInvoicesComponent } from './view-invoices/view-invoices.component'; +import { InvoiceSearchComponent } from './invoice-search/invoice-search.component'; +import { ServicesComponent } from './services/services.component'; // routes array with a path, component, and title for each route in the application (e.g. home, about, contact, etc.) const routes: Routes = [ @@ -55,6 +57,11 @@ const routes: Routes = [ component: AboutComponent, title: 'BCRS: About' }, + { + path: 'services', + component: ServicesComponent, + title: 'BCRS: Services' + }, { path: 'security/signin', component: SigninComponent, @@ -65,6 +72,11 @@ const routes: Routes = [ component: FaqComponent, title: 'BCRS: FAQ' }, + { + path: 'invoice-search', + component: InvoiceSearchComponent, + title: 'BCRS: Invoice Search', + }, { path: 'employee-landing', component: EmployeeLandingComponent, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 00d1a8b..3eeef88 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -34,6 +34,8 @@ import { MyProfileComponent } from './my-profile/my-profile.component'; import { ServiceRepairComponent } from './service-repair/service-repair.component'; import { InvoiceSummaryComponent } from './invoice-summary/invoice-summary.component'; import { ViewInvoicesComponent } from './view-invoices/view-invoices.component'; +import { InvoiceSearchComponent } from './invoice-search/invoice-search.component'; +import { ServicesComponent } from './services/services.component'; // @NgModule assign declarations and imports with bootstrap value @NgModule({ @@ -55,7 +57,9 @@ import { ViewInvoicesComponent } from './view-invoices/view-invoices.component'; MyProfileComponent, ServiceRepairComponent, InvoiceSummaryComponent, - ViewInvoicesComponent + ViewInvoicesComponent, + InvoiceSearchComponent, + ServicesComponent ], imports: [ BrowserModule, diff --git a/src/app/invoice-search/invoice-search.component.css b/src/app/invoice-search/invoice-search.component.css new file mode 100644 index 0000000..1b68408 --- /dev/null +++ b/src/app/invoice-search/invoice-search.component.css @@ -0,0 +1,39 @@ +.btn { + border-radius: 0 !important; + color:#f8b400 !important; + border-color: #f8b400 !important; +} + +/* Override theme on hover */ +.btn:hover { + background-color: #f8b400 !important; + color: black !important; + border-color: #f8b400 !important; +} + +/* Remove border on input field and override color */ +input { + border: none; + border-radius: 0; + background-color: transparent; + border-bottom: 2px solid #f8b400; + outline: none; + color: white; +} + +/* Remove white background from input field when focused */ +input:focus { + background-color: transparent !important; + outline: none !important; + box-shadow: none !important; + color: white; +} + +/* Change placeholder color due to dark background */ +input::placeholder { + color: white; +} + +.input { + color: white; +} \ No newline at end of file diff --git a/src/app/invoice-search/invoice-search.component.html b/src/app/invoice-search/invoice-search.component.html new file mode 100644 index 0000000..227cf50 --- /dev/null +++ b/src/app/invoice-search/invoice-search.component.html @@ -0,0 +1,61 @@ +
| # | +Customer | +Total | +Order Date | +Services | +Pay Status | +Status | +Actions | +
|---|---|---|---|---|---|---|---|
| {{ i + 1 }} | +{{ invoice.firstName }} {{ invoice.lastName }} | +{{ invoice.total | currency }} | +{{ invoice.orderDate | date }} | +
+
+ {{ item.title }}: {{ item.price | currency }}
+
+ |
+ {{ invoice.payStatus }} | +{{ invoice.status }} | ++ + | +
Enhance your computer's performance by increasing its memory with a RAM upgrade.
+Price: $89.99
+Locked out of your system? We can help reset your password and regain access.
+Price: $29.99
+Comprehensive service to rebuild your PC, perfect for systems that are heavily damaged or outdated.
+Price: $149.99
+We'll run a full suite of tests to diagnose the health of your computer and identify any issues.
+Price: $69.99
+Improve your system's speed and efficiency with our PC clean up service, which includes removing unnecessary files and optimizing settings.
+Price: $69.99
+Restore your computer to its factory settings while preserving your personal files.
+Price: $59.99
+Need a new operating system installed? We can handle that for you, ensuring all drivers and updates are installed correctly.
+Price: $39.99
+Over time, dust and grime can cause your computer to overheat and slow down. Our hardware cleaning service can help.
+Price: $64.99
+