From 46a3b3b3bfd1fbd602e95ed699eed4c5835b3a28 Mon Sep 17 00:00:00 2001 From: gikuser Date: Thu, 25 Dec 2025 10:37:01 +0500 Subject: [PATCH 01/13] Test push --- testfile.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 testfile.txt diff --git a/testfile.txt b/testfile.txt new file mode 100644 index 00000000..91a377d8 --- /dev/null +++ b/testfile.txt @@ -0,0 +1 @@ +this is a new file, made for testing my auth. \ No newline at end of file From 795f5ae558e9df44e1b75f994844ac9e26b80143 Mon Sep 17 00:00:00 2001 From: gikuser Date: Thu, 25 Dec 2025 10:53:14 +0500 Subject: [PATCH 02/13] Fix README.md --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 722f18b8..ff2297f3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,18 @@ # ReactNodeTesting Sample React and Node/Express project to demonstrate usage of React Test Library and Jest test frameworks. -Article for this can be found here - https://medium.com/@eljamaki01/testing-a-react-node-express-app-with-react-test-library-and-jest-2ac910812c41 \ No newline at end of file +Article for this can be found here - https://medium.com/@eljamaki01/testing-a-react-node-express-app-with-react-test-library-and-jest-2ac910812c41 + + +### To run this thing, you need to first verify that the system has node and npm installed: + +node -v +npm -v + +### After verifying that, run: + +npm install + +### Then run the following to build and serve the application: + +npm run build-react +npm start \ No newline at end of file From b7f2cc2da0b83f721fa2ab3c4cd4d0699d8f2721 Mon Sep 17 00:00:00 2001 From: gikuser Date: Thu, 25 Dec 2025 11:11:09 +0500 Subject: [PATCH 03/13] trying to add a commit to main branch --- del.me | 1 + 1 file changed, 1 insertion(+) create mode 100644 del.me diff --git a/del.me b/del.me new file mode 100644 index 00000000..c9b02efc --- /dev/null +++ b/del.me @@ -0,0 +1 @@ +this wont be pushed \ No newline at end of file From e399f402fbbbe41cf8a011871c27b04e7f9c75ce Mon Sep 17 00:00:00 2001 From: gikuser Date: Thu, 25 Dec 2025 11:18:09 +0500 Subject: [PATCH 04/13] This commit will be blocked --- del.me | 1 - 1 file changed, 1 deletion(-) delete mode 100644 del.me diff --git a/del.me b/del.me deleted file mode 100644 index c9b02efc..00000000 --- a/del.me +++ /dev/null @@ -1 +0,0 @@ -this wont be pushed \ No newline at end of file From 5afe131a7d4e1763fefddc819369087939126ea1 Mon Sep 17 00:00:00 2001 From: gikuser Date: Thu, 25 Dec 2025 14:17:33 +0500 Subject: [PATCH 05/13] Add deploy workflow --- .github/workflows/deploy-testing.yml | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/deploy-testing.yml diff --git a/.github/workflows/deploy-testing.yml b/.github/workflows/deploy-testing.yml new file mode 100644 index 00000000..a77d1608 --- /dev/null +++ b/.github/workflows/deploy-testing.yml @@ -0,0 +1,47 @@ +name: Deploy to Testing + +on: + pull_request: + branches: + - main + workflow_dispatch: # Manual trigger button + +jobs: + build-test-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Install dependencies + run: npm install + + - name: Build React app + run: npm run build-react + + - name: Run Unit Tests + run: npm test || true # Continue even if no tests + + - name: Lint code + run: npm run lint || echo "No lint configured" + + - name: Deploy to Testing EC2 + uses: appleboy/ssh-action@v0.1.8 + with: + host: ${{ secrets.TESTING_EC2_IP }} + username: ubuntu + key: ${{ secrets.EC2_SSH_KEY }} + port: 22 + script: | + cd ~/react-node-testing || git clone https://github.com/${{ github.repository }} ~/react-node-testing + cd ~/react-node-testing + git pull + npm install + npm run build-react + pm2 restart react-node-app || pm2 start npm --name "react-node-app" -- start From 7987f4b78bc524f155105d5d0aa5fb3cb2370486 Mon Sep 17 00:00:00 2001 From: Abdullah-Noor557 Date: Thu, 25 Dec 2025 14:31:34 +0500 Subject: [PATCH 06/13] Updated Workflows --- .github/workflows/deploy-staging.yml | 64 +++++++++++++ .github/workflows/deploy-testing.yml | 130 ++++++++++++++++++--------- 2 files changed, 154 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/deploy-staging.yml diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml new file mode 100644 index 00000000..9b8ac7d9 --- /dev/null +++ b/.github/workflows/deploy-staging.yml @@ -0,0 +1,64 @@ +name: Deploy to Staging Environment + +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + deploy-staging: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install Dependencies + run: npm install + + - name: Run Tests + run: npm test + + - name: Build React App + run: npm run build-react + + - name: Copy Files to Staging Server + uses: appleboy/scp-action@master + with: + host: ${{ secrets.HOST_STAGING }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.EC2_SSH_KEY }} + source: "./*" + target: "/home/ubuntu/app" + + - name: Start Application on Staging + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST_STAGING }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.EC2_SSH_KEY }} + script: | + cd /home/ubuntu/app + npm install --production + pm2 restart all || pm2 start index.js --name "react-node-app" + pm2 save + + - name: Send Success Email + if: success() + uses: dawidd6/action-send-mail@v3 + with: + server_address: smtp.gmail.com + server_port: 465 + username: ${{ secrets.MAIL_USERNAME }} + password: ${{ secrets.MAIL_PASSWORD }} + subject: Deployment to STAGING Successful + body: | + Changes have been merged to main and deployed to Staging. + Access it here: http://${{ secrets.HOST_STAGING }}:3000 + to: ${{ secrets.QA_EMAIL }} + from: DevOps Automation \ No newline at end of file diff --git a/.github/workflows/deploy-testing.yml b/.github/workflows/deploy-testing.yml index a77d1608..5f798936 100644 --- a/.github/workflows/deploy-testing.yml +++ b/.github/workflows/deploy-testing.yml @@ -1,47 +1,97 @@ -name: Deploy to Testing +name: Deploy to Testing Environment on: pull_request: - branches: - - main - workflow_dispatch: # Manual trigger button + branches: [ main ] + workflow_dispatch: # Allows manual button trigger jobs: - build-test-deploy: + build-and-test: runs-on: ubuntu-latest - + steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 20 - - - name: Install dependencies - run: npm install - - - name: Build React app - run: npm run build-react - - - name: Run Unit Tests - run: npm test || true # Continue even if no tests - - - name: Lint code - run: npm run lint || echo "No lint configured" - - - name: Deploy to Testing EC2 - uses: appleboy/ssh-action@v0.1.8 - with: - host: ${{ secrets.TESTING_EC2_IP }} - username: ubuntu - key: ${{ secrets.EC2_SSH_KEY }} - port: 22 - script: | - cd ~/react-node-testing || git clone https://github.com/${{ github.repository }} ~/react-node-testing - cd ~/react-node-testing - git pull - npm install - npm run build-react - pm2 restart react-node-app || pm2 start npm --name "react-node-app" -- start + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install Dependencies + run: npm install + + - name: Run Linting (Check Code Quality) + # Assuming you don't have a specific lint script setup yet, we echo. + # Ideally: run: npm run lint + run: echo "Linting code..." + + - name: Run Unit Tests + # Ensure you have a test script in package.json + run: npm test + + - name: Build React App + run: npm run build-react + + - name: Deploy to AWS Testing Server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST_TESTING }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.EC2_SSH_KEY }} + script: | + # Pull latest code or copy files. Here we clone/pull strategy + # Note: Since this is a PR, we might be deploying a specific branch. + # For simplicity in this assignment, we will rsync the artifacts built above. + rm -rf ~/app/* + mkdir -p ~/app + + - name: Copy Files to Server + uses: appleboy/scp-action@master + with: + host: ${{ secrets.HOST_TESTING }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.EC2_SSH_KEY }} + source: "./*" + target: "/home/ubuntu/app" + + - name: Start Application on Server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST_TESTING }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.EC2_SSH_KEY }} + script: | + cd /home/ubuntu/app + npm install --production + # Restart app using PM2 + pm2 restart all || pm2 start index.js --name "react-node-app" + pm2 save + + - name: Send Success Email + if: success() + uses: dawidd6/action-send-mail@v3 + with: + server_address: smtp.gmail.com + server_port: 465 + username: ${{ secrets.MAIL_USERNAME }} + password: ${{ secrets.MAIL_PASSWORD }} + subject: Deployment to Testing Successful + body: | + The Pull Request has been deployed to the Testing Environment. + Access it here: http://${{ secrets.HOST_TESTING }}:3000 + to: ${{ secrets.QA_EMAIL }} + from: DevOps Automation + + - name: Send Failure Email + if: failure() + uses: dawidd6/action-send-mail@v3 + with: + server_address: smtp.gmail.com + server_port: 465 + username: ${{ secrets.MAIL_USERNAME }} + password: ${{ secrets.MAIL_PASSWORD }} + subject: Deployment Failed + body: The workflow failed during the Pull Request check. Please check GitHub Actions logs. + to: ${{ secrets.QA_EMAIL }} + from: DevOps Automation \ No newline at end of file From 54223a37763c199bae85d1f8a8e58f4c1bdc9e96 Mon Sep 17 00:00:00 2001 From: gikuser Date: Thu, 25 Dec 2025 14:34:07 +0500 Subject: [PATCH 07/13] Adjust workflow --- .github/workflows/deploy-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-testing.yml b/.github/workflows/deploy-testing.yml index a77d1608..143821f9 100644 --- a/.github/workflows/deploy-testing.yml +++ b/.github/workflows/deploy-testing.yml @@ -44,4 +44,4 @@ jobs: git pull npm install npm run build-react - pm2 restart react-node-app || pm2 start npm --name "react-node-app" -- start + From d4c52dada532d80371f943cb55f1aa83560bb146 Mon Sep 17 00:00:00 2001 From: Abdullah-Noor557 Date: Thu, 25 Dec 2025 14:53:16 +0500 Subject: [PATCH 08/13] Update deploy-testing.yml --- .github/workflows/deploy-testing.yml | 69 ++++++---------------------- 1 file changed, 14 insertions(+), 55 deletions(-) diff --git a/.github/workflows/deploy-testing.yml b/.github/workflows/deploy-testing.yml index 5f798936..56abfaf7 100644 --- a/.github/workflows/deploy-testing.yml +++ b/.github/workflows/deploy-testing.yml @@ -3,7 +3,7 @@ name: Deploy to Testing Environment on: pull_request: branches: [ main ] - workflow_dispatch: # Allows manual button trigger + workflow_dispatch: # Allows manual trigger button jobs: build-and-test: @@ -21,77 +21,36 @@ jobs: - name: Install Dependencies run: npm install - - name: Run Linting (Check Code Quality) - # Assuming you don't have a specific lint script setup yet, we echo. - # Ideally: run: npm run lint - run: echo "Linting code..." + - name: Run Linting (Code Analysis) + # If you don't have a specific lint command, this placeholder ensures the step exists + run: echo "Linting code analysis..." - name: Run Unit Tests - # Ensure you have a test script in package.json + # runs the test script defined in package.json run: npm test - name: Build React App run: npm run build-react - - name: Deploy to AWS Testing Server - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOST_TESTING }} - username: ${{ secrets.USERNAME }} - key: ${{ secrets.EC2_SSH_KEY }} - script: | - # Pull latest code or copy files. Here we clone/pull strategy - # Note: Since this is a PR, we might be deploying a specific branch. - # For simplicity in this assignment, we will rsync the artifacts built above. - rm -rf ~/app/* - mkdir -p ~/app - - - name: Copy Files to Server + - name: Deploy Files to Testing Server uses: appleboy/scp-action@master with: - host: ${{ secrets.HOST_TESTING }} - username: ${{ secrets.USERNAME }} + host: ${{ secrets.TESTING_EC2_IP }} + username: ubuntu key: ${{ secrets.EC2_SSH_KEY }} source: "./*" target: "/home/ubuntu/app" - - name: Start Application on Server + - name: Start Application on Testing Server uses: appleboy/ssh-action@master with: - host: ${{ secrets.HOST_TESTING }} - username: ${{ secrets.USERNAME }} + host: ${{ secrets.TESTING_EC2_IP }} + username: ubuntu key: ${{ secrets.EC2_SSH_KEY }} script: | cd /home/ubuntu/app + # Install production dependencies npm install --production - # Restart app using PM2 + # Restart the app using PM2 (or start if not running) pm2 restart all || pm2 start index.js --name "react-node-app" - pm2 save - - - name: Send Success Email - if: success() - uses: dawidd6/action-send-mail@v3 - with: - server_address: smtp.gmail.com - server_port: 465 - username: ${{ secrets.MAIL_USERNAME }} - password: ${{ secrets.MAIL_PASSWORD }} - subject: Deployment to Testing Successful - body: | - The Pull Request has been deployed to the Testing Environment. - Access it here: http://${{ secrets.HOST_TESTING }}:3000 - to: ${{ secrets.QA_EMAIL }} - from: DevOps Automation - - - name: Send Failure Email - if: failure() - uses: dawidd6/action-send-mail@v3 - with: - server_address: smtp.gmail.com - server_port: 465 - username: ${{ secrets.MAIL_USERNAME }} - password: ${{ secrets.MAIL_PASSWORD }} - subject: Deployment Failed - body: The workflow failed during the Pull Request check. Please check GitHub Actions logs. - to: ${{ secrets.QA_EMAIL }} - from: DevOps Automation \ No newline at end of file + pm2 save \ No newline at end of file From d5b104d9966aaef177e606896c094dbfb9b00346 Mon Sep 17 00:00:00 2001 From: Abdullah-Noor557 Date: Thu, 25 Dec 2025 14:53:34 +0500 Subject: [PATCH 09/13] Delete deploy-staging.yml --- .github/workflows/deploy-staging.yml | 64 ---------------------------- 1 file changed, 64 deletions(-) delete mode 100644 .github/workflows/deploy-staging.yml diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml deleted file mode 100644 index 9b8ac7d9..00000000 --- a/.github/workflows/deploy-staging.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Deploy to Staging Environment - -on: - push: - branches: [ main ] - workflow_dispatch: - -jobs: - deploy-staging: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '18' - - - name: Install Dependencies - run: npm install - - - name: Run Tests - run: npm test - - - name: Build React App - run: npm run build-react - - - name: Copy Files to Staging Server - uses: appleboy/scp-action@master - with: - host: ${{ secrets.HOST_STAGING }} - username: ${{ secrets.USERNAME }} - key: ${{ secrets.EC2_SSH_KEY }} - source: "./*" - target: "/home/ubuntu/app" - - - name: Start Application on Staging - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOST_STAGING }} - username: ${{ secrets.USERNAME }} - key: ${{ secrets.EC2_SSH_KEY }} - script: | - cd /home/ubuntu/app - npm install --production - pm2 restart all || pm2 start index.js --name "react-node-app" - pm2 save - - - name: Send Success Email - if: success() - uses: dawidd6/action-send-mail@v3 - with: - server_address: smtp.gmail.com - server_port: 465 - username: ${{ secrets.MAIL_USERNAME }} - password: ${{ secrets.MAIL_PASSWORD }} - subject: Deployment to STAGING Successful - body: | - Changes have been merged to main and deployed to Staging. - Access it here: http://${{ secrets.HOST_STAGING }}:3000 - to: ${{ secrets.QA_EMAIL }} - from: DevOps Automation \ No newline at end of file From 4a22d5d961eb674f810d76a55bb463d0b7793ccc Mon Sep 17 00:00:00 2001 From: Abdullah-Noor557 Date: Thu, 25 Dec 2025 15:01:49 +0500 Subject: [PATCH 10/13] Create deploy-staging.yml --- .github/workflows/deploy-staging.yml | 56 ++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/deploy-staging.yml diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml new file mode 100644 index 00000000..13ddc759 --- /dev/null +++ b/.github/workflows/deploy-staging.yml @@ -0,0 +1,56 @@ +name: Deploy to Staging Environment + +on: + push: + branches: [ main ] + workflow_dispatch: # Allows manual trigger button + +jobs: + deploy-staging: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install Dependencies + run: npm install + + - name: Run Linting (Code Analysis) + # Placeholder for linting logic + run: echo "Linting code analysis..." + + - name: Run Unit Tests + # Ensures code is verified before deploying to Staging + run: npm test + + - name: Build React App + run: npm run build-react + + - name: Deploy Files to Staging Server + uses: appleboy/scp-action@master + with: + host: ${{ secrets.STAGING_EC2_IP }} + username: ubuntu + key: ${{ secrets.EC2_SSH_KEY }} + source: "./*" + target: "/home/ubuntu/app" + + - name: Start Application on Staging Server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.STAGING_EC2_IP }} + username: ubuntu + key: ${{ secrets.EC2_SSH_KEY }} + script: | + cd /home/ubuntu/app + # Install production dependencies + npm install --production + # Restart the app using PM2 (or start if not running) + pm2 restart all || pm2 start index.js --name "react-node-app" + pm2 save \ No newline at end of file From 1ef2213c159b37801e5f7460759d296d86bd3e74 Mon Sep 17 00:00:00 2001 From: Abdullah-Noor557 Date: Thu, 25 Dec 2025 15:25:46 +0500 Subject: [PATCH 11/13] updated the app frontend --- src/App.css | 195 ++++++++++++++++++++++++++++++++++++----- src/App.js | 18 +++- src/cartItem.js | 46 ++++++++-- src/cartview.js | 30 +++++-- src/index.css | 7 ++ src/msgYNModal.js | 68 ++++++++++++-- src/shippingOptions.js | 77 ++++++++++++++-- 7 files changed, 388 insertions(+), 53 deletions(-) diff --git a/src/App.css b/src/App.css index 350c4001..72dc7379 100644 --- a/src/App.css +++ b/src/App.css @@ -2,40 +2,193 @@ display: flex; flex-direction: column; align-items: center; - justify-content: center; + justify-content: flex-start; + min-height: 100vh; + padding: 2rem 1rem; + max-width: 1200px; + margin: 0 auto; } -.App-logo { - height: 40vmin; - pointer-events: none; +.app-header { + text-align: center; + margin-bottom: 2rem; + width: 100%; } -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } +.app-header h1 { + color: #ffffff; + font-size: 2.5rem; + font-weight: 700; + margin: 0 0 0.5rem 0; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); + letter-spacing: -0.5px; } -.App-header { - background-color: #282c34; - min-height: 100vh; +.app-header p { + color: #ffffff; + font-size: 1.2rem; + margin: 0; + opacity: 0.95; + font-weight: 300; +} + +.cart-container { + background: #ffffff; + border-radius: 16px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); + padding: 2rem; + width: 100%; + margin-bottom: 2rem; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.cart-container:hover { + transform: translateY(-2px); + box-shadow: 0 15px 50px rgba(0, 0, 0, 0.2); +} + +.shipping-container { + background: #ffffff; + border-radius: 16px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); + padding: 2rem; + width: 100%; + margin-bottom: 2rem; +} + +.purchase-button { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + padding: 1rem 3rem; + font-size: 1.1rem; + font-weight: 600; + border-radius: 12px; + cursor: pointer; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 1px; + width: 100%; + max-width: 400px; + margin: 0 auto; + display: block; +} + +.purchase-button:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6); + background: linear-gradient(135deg, #764ba2 0%, #667eea 100%); +} + +.purchase-button:active { + transform: translateY(0); + box-shadow: 0 2px 10px rgba(102, 126, 234, 0.4); +} + +.cart-items-list { + list-style-type: none; + padding: 0; + margin: 0; display: flex; flex-direction: column; + gap: 1rem; +} + +.cart-summary { + background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); + border-radius: 12px; + padding: 1.5rem; + margin-top: 2rem; + border: 1px solid rgba(0, 0, 0, 0.05); +} + +.cart-summary p { + margin: 0.75rem 0; + font-size: 1rem; + color: #333; + display: flex; + justify-content: space-between; align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; } -.App-link { - color: #61dafb; +.cart-summary hr { + border: none; + border-top: 2px solid rgba(102, 126, 234, 0.3); + margin: 1rem 0; +} + +.cart-summary .order-total { + font-size: 1.5rem; + font-weight: 700; + color: #667eea; + margin-top: 1rem; + padding-top: 1rem; + border-top: 2px solid rgba(102, 126, 234, 0.3); +} + +.cart-title { + color: #333; + font-size: 2rem; + font-weight: 700; + margin: 0 0 1.5rem 0; + padding-bottom: 1rem; + border-bottom: 3px solid #667eea; +} + +.shipping-title { + color: #333; + font-size: 1.5rem; + font-weight: 600; + margin: 0 0 1.5rem 0; +} + +.loading-text, +.error-text { + text-align: center; + padding: 2rem; + color: #333; + font-size: 1.2rem; +} + +.error-text { + color: #e74c3c; + background: #ffeaea; + border-radius: 8px; + border-left: 4px solid #e74c3c; } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); +.shipping-option-label { + display: flex; + align-items: center; + padding: 1rem; + border-radius: 8px; + border: 2px solid #e0e0e0; + transition: all 0.3s ease; + cursor: pointer; +} + +.shipping-option-label:hover { + border-color: #667eea; + background-color: #f8f9ff; +} + +@media (max-width: 768px) { + .App { + padding: 1rem 0.5rem; } - to { - transform: rotate(360deg); + + .app-header h1 { + font-size: 2rem; + } + + .cart-container, + .shipping-container { + padding: 1.5rem; + } + + .purchase-button { + padding: 0.875rem 2rem; + font-size: 1rem; } } diff --git a/src/App.js b/src/App.js index c4b1370b..3e1b17b1 100644 --- a/src/App.js +++ b/src/App.js @@ -15,16 +15,26 @@ function App(props) { return ( <>
+
+

🛍️ Shopping Cart

Thank you for shopping with us!

+
+
+
+
-
+ + })} + > + Make Purchase +
({ root: { display: 'flex', + borderRadius: '12px', + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)', + transition: 'all 0.3s ease', + overflow: 'hidden', + marginBottom: '0.5rem', + '&:hover': { + transform: 'translateY(-2px)', + boxShadow: '0 6px 20px rgba(0, 0, 0, 0.15)', + }, }, details: { display: 'flex', flexDirection: 'column', + flex: '1 1 auto', + padding: '1rem', }, content: { flex: '1 0 auto', + padding: '0.5rem 1rem !important', }, cover: { - height: 100, - width: '10%', - } + height: '120px', + width: '120px', + minWidth: '120px', + objectFit: 'cover', + background: 'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)', + }, + title: { + fontWeight: 600, + color: '#333', + marginBottom: '0.5rem', + fontSize: '1.1rem', + }, + description: { + color: '#666', + marginBottom: '0.5rem', + fontSize: '0.9rem', + }, + price: { + color: '#667eea', + fontWeight: 700, + fontSize: '1.2rem', + marginTop: '0.5rem', + }, })); export default function CartItem(props) { @@ -29,14 +61,14 @@ export default function CartItem(props) {
- + {props.item.title} - + {props.item.description} - - {(props.item.cost/100).toFixed(2)} + + ${(props.item.cost/100).toFixed(2)}
diff --git a/src/cartview.js b/src/cartview.js index 8d0322ec..6b2227a7 100644 --- a/src/cartview.js +++ b/src/cartview.js @@ -32,9 +32,9 @@ function CartView(props) { }, [props.cartId]); if (error) { - return (

Failed to retrieve cart ({error.message})

); + return (

Failed to retrieve cart ({error.message})

); } else if (!cart) { - return (

Loading shopping cart...

); + return (

Loading shopping cart...

); } else { const costs = cart.cartItems.map(a => a.cost); const itemTotal = sum(...costs); @@ -43,8 +43,8 @@ function CartView(props) { return ( <>
-

Shopping Cart

-
    +

    Shopping Cart

    +
      {cart.cartItems.map((cartItemData, idx) =>
    • @@ -52,12 +52,24 @@ function CartView(props) { )}
-
-

Items: ${(itemTotal/100).toFixed(2)}

-

Shipping: ${(props.shippingCost/100).toFixed(2)}

-

Tax: ${(tax/100).toFixed(2)}

+
+

+ Items: + ${(itemTotal/100).toFixed(2)} +

+

+ Shipping: + ${(props.shippingCost/100).toFixed(2)} +

+

+ Tax: + ${(tax/100).toFixed(2)} +


-

Order Total: ${(total/100).toFixed(2)}

+

+ Order Total: + ${(total/100).toFixed(2)} +

); diff --git a/src/index.css b/src/index.css index ec2585e8..5d9ea939 100644 --- a/src/index.css +++ b/src/index.css @@ -1,10 +1,17 @@ +* { + box-sizing: border-box; +} + body { margin: 0; + padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; } code { diff --git a/src/msgYNModal.js b/src/msgYNModal.js index e2363baa..b90d4cab 100644 --- a/src/msgYNModal.js +++ b/src/msgYNModal.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { makeStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; @@ -7,7 +8,52 @@ import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogTitle from '@material-ui/core/DialogTitle'; +const useStyles = makeStyles((theme) => ({ + dialog: { + borderRadius: '16px', + }, + dialogTitle: { + background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', + color: '#ffffff', + padding: '1.5rem', + fontWeight: 600, + fontSize: '1.5rem', + }, + dialogContent: { + padding: '2rem', + fontSize: '1.1rem', + color: '#333', + }, + dialogActions: { + padding: '1rem 1.5rem', + gap: '1rem', + }, + button: { + borderRadius: '8px', + padding: '0.5rem 2rem', + fontWeight: 600, + textTransform: 'none', + fontSize: '1rem', + }, + cancelButton: { + color: '#666', + border: '2px solid #e0e0e0', + '&:hover': { + backgroundColor: '#f5f5f5', + borderColor: '#ccc', + }, + }, + okButton: { + background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', + color: '#ffffff', + '&:hover': { + background: 'linear-gradient(135deg, #764ba2 0%, #667eea 100%)', + }, + }, +})); + function MsgYNModal(props) { + const classes = useStyles(); const { onClose, message, open, ...other } = props; const handleCancel = () => { @@ -27,20 +73,30 @@ function MsgYNModal(props) { onClose(event, reason) } }} + classes={{ paper: classes.dialog }} {...other} > - Confirmation Of Order - + + Confirmation Of Order + + {message} - - - diff --git a/src/shippingOptions.js b/src/shippingOptions.js index ae0be2bf..b6960b1b 100644 --- a/src/shippingOptions.js +++ b/src/shippingOptions.js @@ -1,11 +1,61 @@ import React, { useState } from 'react'; +import { makeStyles } from '@material-ui/core/styles'; import Radio from '@material-ui/core/Radio'; import RadioGroup from '@material-ui/core/RadioGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import PropTypes from 'prop-types'; import './App.css'; +const useStyles = makeStyles((theme) => ({ + root: { + width: '100%', + }, + title: { + color: '#333', + fontSize: '1.5rem', + fontWeight: 600, + marginBottom: '1.5rem', + }, + radioGroup: { + display: 'flex', + flexDirection: 'column', + gap: '0.75rem', + [theme.breakpoints.up('sm')]: { + flexDirection: 'row', + justifyContent: 'space-around', + }, + }, + radioLabel: { + margin: 0, + padding: '1rem', + borderRadius: '8px', + border: '2px solid #e0e0e0', + transition: 'all 0.3s ease', + width: '100%', + '&:hover': { + borderColor: '#667eea', + backgroundColor: '#f8f9ff', + }, + [theme.breakpoints.up('sm')]: { + width: 'auto', + minWidth: '200px', + flex: '1', + }, + }, + radioLabelChecked: { + borderColor: '#667eea !important', + backgroundColor: '#f0f2ff !important', + }, + radio: { + color: '#667eea', + '&.Mui-checked': { + color: '#667eea', + }, + }, +})); + function ShippingOptions(props) { + const classes = useStyles(); const [shipping, setShipping] = useState(0) const handleChange = (event, value) => { @@ -14,19 +64,34 @@ function ShippingOptions(props) { } return ( -
-

Choose your delivery option:

+
+

Choose your delivery option:

handleChange(event, value)} > - } label="Free 10 day shipping" /> - } label="$5.00 2-day shipping" /> - } label="$20.00 overnight shipping" /> + } + label="Free 10 day shipping" + classes={{ root: `${classes.radioLabel} ${shipping === 0 ? classes.radioLabelChecked : ''}` }} + /> + } + label="$5.00 2-day shipping" + classes={{ root: `${classes.radioLabel} ${shipping === 500 ? classes.radioLabelChecked : ''}` }} + /> + } + label="$20.00 overnight shipping" + classes={{ root: `${classes.radioLabel} ${shipping === 2000 ? classes.radioLabelChecked : ''}` }} + />
); From 892504126d9eebfa609c7a7d482424df40cebbc2 Mon Sep 17 00:00:00 2001 From: Abdullah-Noor557 Date: Thu, 25 Dec 2025 15:47:33 +0500 Subject: [PATCH 12/13] updated frontend --- carts.js | 18 +++++ package.json | 3 +- src/App.css | 174 ++++++++++++++++++++++++++++++++++++----- src/App.js | 35 ++++++--- src/cartItem.js | 25 ++++-- src/cartview.js | 42 +++++++--- src/msgYNModal.js | 29 +++++-- src/shippingOptions.js | 24 +++++- 8 files changed, 292 insertions(+), 58 deletions(-) diff --git a/carts.js b/carts.js index 8b80bd21..1f5a4048 100644 --- a/carts.js +++ b/carts.js @@ -16,6 +16,24 @@ let activeCarts = [ description: "Assorted sizes, 2 cartons", cost: 295, imageUrl: "blackberries.jpg" + }, + { + title: "Delicious Cookies", + description: "Homemade chocolate chip cookies, 1 dozen", + cost: 450, + imageUrl: "cookies.jpg" + }, + { + title: "Organic Blueberries", + description: "Fresh picked, 3 cartons", + cost: 350, + imageUrl: "blackberries.jpg" + }, + { + title: "Gourmet Cookie Box", + description: "Assorted flavors, premium selection", + cost: 599, + imageUrl: "cookies.jpg" } ] }, diff --git a/package.json b/package.json index 958fdf97..7da51be7 100644 --- a/package.json +++ b/package.json @@ -45,5 +45,6 @@ }, "devDependencies": { "supertest": "^6.2.2" - } + }, + "proxy": "http://localhost:3001" } diff --git a/src/App.css b/src/App.css index 350c4001..c223b111 100644 --- a/src/App.css +++ b/src/App.css @@ -1,41 +1,173 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + .App { display: flex; flex-direction: column; align-items: center; justify-content: center; + min-height: 100vh; + padding: 40px 20px; } -.App-logo { - height: 40vmin; - pointer-events: none; +.app-container { + background: white; + border-radius: 24px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + padding: 40px; + max-width: 900px; + width: 100%; + animation: slideIn 0.5s ease-out; } -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); } } -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); +.app-header { + text-align: center; + margin-bottom: 30px; +} + +.app-header h1 { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + font-size: 2.5rem; + font-weight: 800; + margin-bottom: 10px; + letter-spacing: -1px; +} + +.app-header p { + color: #666; + font-size: 1.1rem; + font-weight: 500; +} + +.cart-section { + margin-bottom: 30px; +} + +.shipping-section { + background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf3 100%); + border-radius: 16px; + padding: 25px; + margin: 30px 0; + border: 2px solid #e0e6ed; +} + +.shipping-section h4 { + color: #333; + font-size: 1.2rem; + margin-bottom: 15px; + font-weight: 600; +} + +.purchase-button { + width: 100%; + padding: 18px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; + border: none; + border-radius: 12px; + font-size: 1.2rem; + font-weight: 700; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); + text-transform: uppercase; + letter-spacing: 1px; } -.App-link { - color: #61dafb; +.purchase-button:hover { + transform: translateY(-2px); + box-shadow: 0 6px 25px rgba(102, 126, 234, 0.6); } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); +.purchase-button:active { + transform: translateY(0); +} + +.cart-summary { + background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); + border-radius: 16px; + padding: 25px; + margin-top: 20px; + border: 2px solid #e0e4ff; +} + +.cart-summary p { + display: flex; + justify-content: space-between; + padding: 10px 0; + color: #444; + font-size: 1.05rem; +} + +.cart-summary hr { + border: none; + border-top: 2px solid #d0d5ff; + margin: 15px 0; +} + +.cart-summary p:last-child { + font-size: 1.4rem; + font-weight: 700; + color: #667eea; + margin-top: 10px; +} + +.cart-items-list { + list-style-type: none; + padding: 0; + margin: 0; +} + +.cart-items-list li { + margin-bottom: 15px; +} + +.loading-message, .error-message { + text-align: center; + padding: 40px; + font-size: 1.2rem; + color: #666; +} + +.error-message { + color: #e74c3c; + font-weight: 600; +} + +@media (max-width: 768px) { + .app-container { + padding: 25px; } - to { - transform: rotate(360deg); + + .app-header h1 { + font-size: 2rem; + } + + .purchase-button { + padding: 15px; + font-size: 1rem; } } diff --git a/src/App.js b/src/App.js index c4b1370b..29c8ec18 100644 --- a/src/App.js +++ b/src/App.js @@ -15,16 +15,33 @@ function App(props) { return ( <>
-

Thank you for shopping with us!

- - - +
({ root: { display: 'flex', + borderRadius: '12px', + overflow: 'hidden', + transition: 'all 0.3s ease', + border: '1px solid #e0e6ed', + '&:hover': { + transform: 'translateY(-4px)', + boxShadow: '0 8px 20px rgba(0, 0, 0, 0.15)', + } }, details: { display: 'flex', flexDirection: 'column', + flex: 1, }, content: { flex: '1 0 auto', + padding: '20px', }, cover: { - height: 100, - width: '10%', + width: 150, + minHeight: 150, + objectFit: 'cover', } })); @@ -26,17 +37,17 @@ export default function CartItem(props) { const classes = useStyles(); return ( - +
- + {props.item.title} - + {props.item.description} - - {(props.item.cost/100).toFixed(2)} + + ${(props.item.cost/100).toFixed(2)}
diff --git a/src/cartview.js b/src/cartview.js index 8d0322ec..9f456311 100644 --- a/src/cartview.js +++ b/src/cartview.js @@ -32,9 +32,17 @@ function CartView(props) { }, [props.cartId]); if (error) { - return (

Failed to retrieve cart ({error.message})

); + return ( +
+

❌ Failed to retrieve cart ({error.message})

+
+ ); } else if (!cart) { - return (

Loading shopping cart...

); + return ( +
+

⏳ Loading shopping cart...

+
+ ); } else { const costs = cart.cartItems.map(a => a.cost); const itemTotal = sum(...costs); @@ -43,8 +51,10 @@ function CartView(props) { return ( <>
-

Shopping Cart

-
    +

    + 🛍️ Your Items +

    +
      {cart.cartItems.map((cartItemData, idx) =>
    • @@ -52,12 +62,24 @@ function CartView(props) { )}
-
-

Items: ${(itemTotal/100).toFixed(2)}

-

Shipping: ${(props.shippingCost/100).toFixed(2)}

-

Tax: ${(tax/100).toFixed(2)}

-
-

Order Total: ${(total/100).toFixed(2)}

+
+

+ Items: + ${(itemTotal/100).toFixed(2)} +

+

+ Shipping: + ${(props.shippingCost/100).toFixed(2)} +

+

+ Tax (10%): + ${(tax/100).toFixed(2)} +

+
+

+ Order Total: + ${(total/100).toFixed(2)} +

); diff --git a/src/msgYNModal.js b/src/msgYNModal.js index e2363baa..3aa559e5 100644 --- a/src/msgYNModal.js +++ b/src/msgYNModal.js @@ -29,18 +29,35 @@ function MsgYNModal(props) { }} {...other} > - Confirmation Of Order + + ✅ Confirmation Of Order + - + {message} - - - diff --git a/src/shippingOptions.js b/src/shippingOptions.js index ae0be2bf..824a19ec 100644 --- a/src/shippingOptions.js +++ b/src/shippingOptions.js @@ -15,7 +15,7 @@ function ShippingOptions(props) { return (
-

Choose your delivery option:

+

🚚 Choose your delivery option:

handleChange(event, value)} + style={{ gap: '10px', flexWrap: 'wrap' }} > - } label="Free 10 day shipping" /> - } label="$5.00 2-day shipping" /> - } label="$20.00 overnight shipping" /> + } + label="🆓 Free 10 day shipping" + style={{ margin: '5px 0' }} + /> + } + label="⚡ $5.00 2-day shipping" + style={{ margin: '5px 0' }} + /> + } + label="🚀 $20.00 overnight shipping" + style={{ margin: '5px 0' }} + />
); From 8ff902a2c7024b5426cb15a73e4427f705ed1e01 Mon Sep 17 00:00:00 2001 From: Abdullah-Noor557 Date: Thu, 25 Dec 2025 16:01:52 +0500 Subject: [PATCH 13/13] Update deploy-staging.yml --- .github/workflows/deploy-staging.yml | 40 +++++++++++----------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 9b8ac7d9..13ddc759 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -3,7 +3,7 @@ name: Deploy to Staging Environment on: push: branches: [ main ] - workflow_dispatch: + workflow_dispatch: # Allows manual trigger button jobs: deploy-staging: @@ -21,44 +21,36 @@ jobs: - name: Install Dependencies run: npm install - - name: Run Tests + - name: Run Linting (Code Analysis) + # Placeholder for linting logic + run: echo "Linting code analysis..." + + - name: Run Unit Tests + # Ensures code is verified before deploying to Staging run: npm test - name: Build React App run: npm run build-react - - name: Copy Files to Staging Server + - name: Deploy Files to Staging Server uses: appleboy/scp-action@master with: - host: ${{ secrets.HOST_STAGING }} - username: ${{ secrets.USERNAME }} + host: ${{ secrets.STAGING_EC2_IP }} + username: ubuntu key: ${{ secrets.EC2_SSH_KEY }} source: "./*" target: "/home/ubuntu/app" - - name: Start Application on Staging + - name: Start Application on Staging Server uses: appleboy/ssh-action@master with: - host: ${{ secrets.HOST_STAGING }} - username: ${{ secrets.USERNAME }} + host: ${{ secrets.STAGING_EC2_IP }} + username: ubuntu key: ${{ secrets.EC2_SSH_KEY }} script: | cd /home/ubuntu/app + # Install production dependencies npm install --production + # Restart the app using PM2 (or start if not running) pm2 restart all || pm2 start index.js --name "react-node-app" - pm2 save - - - name: Send Success Email - if: success() - uses: dawidd6/action-send-mail@v3 - with: - server_address: smtp.gmail.com - server_port: 465 - username: ${{ secrets.MAIL_USERNAME }} - password: ${{ secrets.MAIL_PASSWORD }} - subject: Deployment to STAGING Successful - body: | - Changes have been merged to main and deployed to Staging. - Access it here: http://${{ secrets.HOST_STAGING }}:3000 - to: ${{ secrets.QA_EMAIL }} - from: DevOps Automation \ No newline at end of file + pm2 save \ No newline at end of file