diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..1d5c207add --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,59 @@ +name: 'Lint Code' + +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] + +jobs: + lint_python: + name: Lint Python Files + runs-on: ubuntu-latest + + steps: + + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.12 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 + + - name: Print working directory + run: pwd + + - name: Run Linter + run: | + pwd + # This command finds all Python files recursively and runs flake8 on them + find . -name "*.py" -exec flake8 {} + + echo "Linted all the python files successfully" + + lint_js: + name: Lint JavaScript Files + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 14 + + - name: Install JSHint + run: npm install jshint --global + + - name: Run Linter + run: | + # This command finds all JavaScript files recursively and runs JSHint on them + find ./server/database -name "*.js" -exec jshint {} + + echo "Linted all the js files successfully" diff --git a/server/database/app.js b/server/database/app.js index 00f52b2008..1389c20911 100644 --- a/server/database/app.js +++ b/server/database/app.js @@ -59,16 +59,34 @@ app.get('/fetchReviews/dealer/:id', async (req, res) => { // Express route to fetch all dealerships app.get('/fetchDealers', async (req, res) => { //Write your code here +try { + const documents = await Dealerships.find(); + res.json(documents); + } catch (error) { + res.status(500).json({ error: 'Error fetching documents' }); + } }); // Express route to fetch Dealers by a particular state app.get('/fetchDealers/:state', async (req, res) => { //Write your code here +try { + const documents = await Dealerships.find({state: req.params.state}); + res.json(documents); + } catch (error) { + res.status(500).json({ error: 'Error fetching documents' }); + } }); // Express route to fetch dealer by a particular id app.get('/fetchDealer/:id', async (req, res) => { //Write your code here +try { + const documents = await Dealerships.find({id: req.params.id}); + res.json(documents); + } catch (error) { + res.status(500).json({ error: 'Error fetching documents' }); + } }); //Express route to insert review diff --git a/server/djangoapp/.env b/server/djangoapp/.env index 01822e542a..b654dee401 100644 --- a/server/djangoapp/.env +++ b/server/djangoapp/.env @@ -1,2 +1,2 @@ -backend_url =your backend url -sentiment_analyzer_url=your code engine deployment url +backend_url =https://joeperkinspt-3030.theiadockernext-0-labs-prod-theiak8s-4-tor01.proxy.cognitiveclass.ai/ +sentiment_analyzer_url=https://sentianalyzer.1sz97p1eisbw.us-south.codeengine.appdomain.cloud/ \ No newline at end of file diff --git a/server/djangoapp/admin.py b/server/djangoapp/admin.py index 433657fc64..67fa0e8cdc 100644 --- a/server/djangoapp/admin.py +++ b/server/djangoapp/admin.py @@ -1,5 +1,27 @@ -# from django.contrib import admin -# from .models import related models +from django.contrib import admin +from .models import CarMake, CarModel + + +class CarModelInline(admin.StackedInline): + model = CarModel + extra = 1 + + +class CarModelAdmin(admin.ModelAdmin): + list_display = ['name', 'dealer_id', 'car_make', 'car_type', 'year'] + search_fields = ['name', 'car_type'] + list_filter = ['car_make', 'car_type', 'year'] + + +class CarMakeAdmin(admin.ModelAdmin): + inlines = [CarModelInline] + list_display = ['name', 'description'] + search_fields = ['name'] + + +# Register models with their respective admin classes +admin.site.register(CarMake, CarMakeAdmin) +admin.site.register(CarModel, CarModelAdmin) # Register your models here. diff --git a/server/djangoapp/models.py b/server/djangoapp/models.py index eb101a68c8..194240adbb 100644 --- a/server/djangoapp/models.py +++ b/server/djangoapp/models.py @@ -1,8 +1,8 @@ # Uncomment the following imports before adding the Model code -# from django.db import models -# from django.utils.timezone import now -# from django.core.validators import MaxValueValidator, MinValueValidator +from django.db import models +from django.utils.timezone import now +from django.core.validators import MaxValueValidator, MinValueValidator # Create your models here. @@ -13,6 +13,14 @@ # - Any other fields you would like to include in car make model # - __str__ method to print a car make object +class CarMake(models.Model): + name = models.CharField(max_length=100) + description = models.TextField() + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.name # <HINT> Create a Car Model model `class CarModel(models.Model):`: # - Many-To-One relationship to Car Make model (One Car Make has many @@ -23,3 +31,30 @@ # - Year (IntegerField) with min value 2015 and max value 2023 # - Any other fields you would like to include in car model # - __str__ method to print a car make object + +class CarModel(models.Model): + CAR_TYPES = [ + ('SEDAN', 'Sedan'), + ('SUV', 'SUV'), + ('WAGON', 'Wagon'), + ('SPORT', 'Sport'), + ('COUPE', 'Coupe'), + ('MINIVAN', 'Minivan'), + ('PICKUP', 'Pickup'), + ] + + car_make = models.ForeignKey(CarMake, on_delete=models.CASCADE) + dealer_id = models.IntegerField() + name = models.CharField(max_length=100) + car_type = models.CharField(max_length=10, choices=CAR_TYPES) + year = models.IntegerField( + validators=[ + MinValueValidator(2015), + MaxValueValidator(2023) + ] + ) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return f"{self.car_make.name} {self.name} ({self.year})" diff --git a/server/djangoapp/populate.py b/server/djangoapp/populate.py index 1927e09e18..18e5affdb5 100644 --- a/server/djangoapp/populate.py +++ b/server/djangoapp/populate.py @@ -1,2 +1,39 @@ +from .models import CarMake, CarModel + def initiate(): - print("Populate not implemented. Add data manually") + car_make_data = [ + {"name": "NISSAN", "description": "Great cars. Japanese technology"}, + {"name": "Mercedes", "description": "Great cars. German technology"}, + {"name": "Audi", "description": "Great cars. German technology"}, + {"name": "Kia", "description": "Great cars. Korean technology"}, + {"name": "Toyota", "description": "Great cars. Japanese technology"}, + ] + car_make_instances = [] + for data in car_make_data: + car_make_instances.append(CarMake.objects.create(name=data['name'], description=data['description'])) + + car_model_data = [ + {"name": "Pathfinder", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[0]}, + {"name": "Qashqai", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[0]}, + {"name": "XTRAIL", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[0]}, + {"name": "A-Class", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[1]}, + {"name": "C-Class", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[1]}, + {"name": "E-Class", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[1]}, + {"name": "A4", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[2]}, + {"name": "A5", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[2]}, + {"name": "A6", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[2]}, + {"name": "Sorrento", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[3]}, + {"name": "Carnival", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[3]}, + {"name": "Cerato", "car_type": "Sedan", "year": 2023, "car_make": car_make_instances[3]}, + {"name": "Corolla", "car_type": "Sedan", "year": 2023, "car_make": car_make_instances[4]}, + {"name": "Camry", "car_type": "Sedan", "year": 2023, "car_make": car_make_instances[4]}, + {"name": "Kluger", "car_type": "SUV", "year": 2023, "car_make": car_make_instances[4]}, + ] + for data in car_model_data: + CarModel.objects.create( + name=data['name'], + car_make=data['car_make'], + car_type=data['car_type'], + year=data['year'], + dealer_id=1 # Adding a default dealer_id since it's required + ) \ No newline at end of file diff --git a/server/djangoapp/restapis.py b/server/djangoapp/restapis.py index 90709d9e3b..bdeeaa2b6d 100644 --- a/server/djangoapp/restapis.py +++ b/server/djangoapp/restapis.py @@ -1,8 +1,9 @@ # Uncomment the imports below before you add the function code -# import requests +import requests import os from dotenv import load_dotenv + load_dotenv() backend_url = os.getenv( @@ -12,11 +13,43 @@ default="http://localhost:5050/") # def get_request(endpoint, **kwargs): +def get_request(endpoint, **kwargs): + params = "" + if(kwargs): + for key,value in kwargs.items(): + params=params+key+"="+value+"&" + + request_url = backend_url+endpoint+"?"+params + + print("GET from {} ".format(request_url)) + try: + # Call get method of requests library with URL and parameters + response = requests.get(request_url) + return response.json() + except: + # If any error occurs + print("Network exception occurred") # Add code for get requests to back end # def analyze_review_sentiments(text): +def analyze_review_sentiments(text): + request_url = sentiment_analyzer_url+"analyze/"+text + try: + # Call get method of requests library with URL and parameters + response = requests.get(request_url) + return response.json() + except Exception as err: + print(f"Unexpected {err=}, {type(err)=}") + print("Network exception occurred") # request_url = sentiment_analyzer_url+"analyze/"+text # Add code for retrieving sentiments # def post_review(data_dict): -# Add code for posting review +def post_review(data_dict): + request_url = backend_url+"/insert_review" + try: + response = requests.post(request_url,json=data_dict) + print(response.json()) + return response.json() + except: + print("Network exception occurred") diff --git a/server/djangoapp/urls.py b/server/djangoapp/urls.py index 0edc274f90..348857bd12 100644 --- a/server/djangoapp/urls.py +++ b/server/djangoapp/urls.py @@ -1,18 +1,30 @@ # Uncomment the imports before you add the code -# from django.urls import path +from django.urls import path from django.conf.urls.static import static from django.conf import settings -# from . import views +from . import views app_name = 'djangoapp' urlpatterns = [ - # # path for registration - + # path for registration + path(route='register', view=views.registration, name='register'), # path for login - # path(route='login', view=views.login_user, name='login'), - - # path for dealer reviews view + path(route='login', view=views.login_user, name='login'), + #logout + path(route='logout', view=views.logout_request, name='logout'), + # path for dealer + path(route='get_dealers/', view=views.get_dealerships, name='get_dealers'), + # + path(route='get_dealers/<str:state>', view=views.get_dealerships, name='get_dealers_by_state'), # path for add a review view - + + # dealer id + path(route='dealer/<int:dealer_id>', view=views.get_dealer_details, name='dealer_details'), + # dealer reviews + path(route='reviews/dealer/<int:dealer_id>', view=views.get_dealer_reviews, name='dealer_reviews'), + # add review + path(route='add_review', view=views.add_review, name='add_review'), + # path get cars + path(route='get_cars', view=views.get_cars, name='getcars'), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/server/djangoapp/views.py b/server/djangoapp/views.py index b16409f419..00d24db9a0 100644 --- a/server/djangoapp/views.py +++ b/server/djangoapp/views.py @@ -1,19 +1,21 @@ # Uncomment the required imports before adding the code -# from django.shortcuts import render -# from django.http import HttpResponseRedirect, HttpResponse -# from django.contrib.auth.models import User -# from django.shortcuts import get_object_or_404, render, redirect -# from django.contrib.auth import logout -# from django.contrib import messages -# from datetime import datetime +from django.shortcuts import render +from django.http import HttpResponseRedirect, HttpResponse +from django.contrib.auth.models import User +from django.shortcuts import get_object_or_404, render, redirect +from django.contrib.auth import logout +from django.contrib import messages +from datetime import datetime from django.http import JsonResponse from django.contrib.auth import login, authenticate import logging import json from django.views.decorators.csrf import csrf_exempt -# from .populate import initiate +from .populate import initiate +from .models import CarMake, CarModel +from .restapis import get_request, analyze_review_sentiments, post_review # Get an instance of a logger @@ -39,27 +41,93 @@ def login_user(request): return JsonResponse(data) # Create a `logout_request` view to handle sign out request -# def logout_request(request): -# ... +def logout_request(request): + data = {"userName": ""} + return JsonResponse(data) # Create a `registration` view to handle sign up request -# @csrf_exempt -# def registration(request): -# ... +@csrf_exempt +def registration(request): + context = {} -# # Update the `get_dealerships` view to render the index page with -# a list of dealerships -# def get_dealerships(request): -# ... + data = json.loads(request.body) + username = data['userName'] + password = data['password'] + first_name = data['firstName'] + last_name = data['lastName'] + email = data['email'] + username_exist = False + email_exist = False + try: + # Check if user already exists + User.objects.get(username=username) + username_exist = True + except: + # If not, simply log this is a new user + logger.debug("{} is new user".format(username)) + + # If it is a new user + if not username_exist: + # Create user in auth_user table + user = User.objects.create_user(username=username, first_name=first_name, last_name=last_name,password=password, email=email) + # Login the user and redirect to list page + login(request, user) + data = {"userName":username,"status":"Authenticated"} + return JsonResponse(data) + else : + data = {"userName":username,"error":"Already Registered"} + return JsonResponse(data) + +#Update the `get_dealerships` render list of dealerships all by default, particular state if state is passed +def get_dealerships(request, state="All"): + if(state == "All"): + endpoint = "/fetchDealers" + else: + endpoint = "/fetchDealers/"+state + dealerships = get_request(endpoint) + return JsonResponse({"status":200,"dealers":dealerships}) # Create a `get_dealer_reviews` view to render the reviews of a dealer -# def get_dealer_reviews(request,dealer_id): -# ... +def get_dealer_reviews(request, dealer_id): + if dealer_id: + endpoint = "/fetchReviews/dealer/"+str(dealer_id) + reviews = get_request(endpoint) + for review_detail in reviews: + response = analyze_review_sentiments(review_detail['review']) + print(response) + review_detail['sentiment'] = response['sentiment'] + return JsonResponse({"status": 200, "reviews": reviews}) + else: + return JsonResponse({"status": 400, "message": "Bad Request"}) # Create a `get_dealer_details` view to render the dealer details -# def get_dealer_details(request, dealer_id): -# ... +def get_dealer_details(request, dealer_id): + if(dealer_id): + endpoint = "/fetchDealer/"+str(dealer_id) + dealership = get_request(endpoint) + return JsonResponse({"status":200,"dealer":dealership}) + else: + return JsonResponse({"status":400,"message":"Bad Request"}) # Create a `add_review` view to submit a review -# def add_review(request): -# ... +def add_review(request): + if(request.user.is_anonymous == False): + data = json.loads(request.body) + try: + response = post_review(data) + return JsonResponse({"status":200}) + except: + return JsonResponse({"status":401,"message":"Error in posting review"}) + else: + return JsonResponse({"status":403,"message":"Unauthorized"}) + +def get_cars(request): + count = CarMake.objects.filter().count() + print(count) + if count == 0: + initiate() + car_models = CarModel.objects.select_related('car_make') + cars = [] + for car_model in car_models: + cars.append({"CarModel": car_model.name, "CarMake": car_model.car_make.name}) + return JsonResponse({"CarModels": cars}) diff --git a/server/djangoproj/settings.py b/server/djangoproj/settings.py index e0b1092a5c..f6d4ac501a 100644 --- a/server/djangoproj/settings.py +++ b/server/djangoproj/settings.py @@ -28,8 +28,8 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] -CSRF_TRUSTED_ORIGINS = [] +ALLOWED_HOSTS=['localhost','https://joeperkinspt-8000.theiadockernext-1-labs-prod-theiak8s-4-tor01.proxy.cognitiveclass.ai'] +CSRF_TRUSTED_ORIGINS=['https://joeperkinspt-8000.theiadockernext-1-labs-prod-theiak8s-4-tor01.proxy.cognitiveclass.ai'] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [], @@ -61,7 +61,11 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [ + os.path.join(BASE_DIR, 'frontend/static'), + os.path.join(BASE_DIR, 'frontend/build'), + os.path.join(BASE_DIR, 'frontend/build/static'), + ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -134,5 +138,10 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -STATICFILES_DIRS = [] +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, 'frontend/static'), + os.path.join(BASE_DIR, 'frontend/build'), + os.path.join(BASE_DIR, 'frontend/build/static'), +] + diff --git a/server/djangoproj/urls.py b/server/djangoproj/urls.py index 6808da9141..6aadc77007 100644 --- a/server/djangoproj/urls.py +++ b/server/djangoproj/urls.py @@ -23,4 +23,13 @@ path('admin/', admin.site.urls), path('djangoapp/', include('djangoapp.urls')), path('', TemplateView.as_view(template_name="Home.html")), + path('about/', TemplateView.as_view(template_name="About.html")), + path('contact/', TemplateView.as_view(template_name="Contact.html")), + path('login/', TemplateView.as_view(template_name="index.html")), + path('register/', TemplateView.as_view(template_name="index.html")), + path('dealers/', TemplateView.as_view(template_name="index.html")), + path('dealer/', TemplateView.as_view(template_name="index.html")), + path('dealer/<int:dealer_id>',TemplateView.as_view(template_name="index.html")), + path('postreview/<int:dealer_id>', TemplateView.as_view(template_name="index.html")), + ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/server/frontend/package-lock.json b/server/frontend/package-lock.json index 0797425307..bdb21fad35 100644 --- a/server/frontend/package-lock.json +++ b/server/frontend/package-lock.json @@ -16,6 +16,9 @@ "react-router-dom": "^6.19.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -646,9 +649,18 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { "node": ">=6.9.0" }, @@ -1891,6 +1903,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", diff --git a/server/frontend/src/App.js b/server/frontend/src/App.js index aceac6974d..25315f94bd 100644 --- a/server/frontend/src/App.js +++ b/server/frontend/src/App.js @@ -1,10 +1,19 @@ import LoginPanel from "./components/Login/Login" import { Routes, Route } from "react-router-dom"; +import RegisterPanel from "./components/Register/Register"; +import Dealers from './components/Dealers/Dealers'; +import Dealer from "./components/Dealers/Dealer" +import PostReview from "./components/Dealers/PostReview" + function App() { return ( <Routes> <Route path="/login" element={<LoginPanel />} /> + <Route path="/register" element={<RegisterPanel />} /> + <Route path="/dealers" element={<Dealers/>} /> + <Route path="/dealer/:id" element={<Dealer/>} /> + <Route path="/postreview/:id" element={<PostReview/>} /> </Routes> ); } diff --git a/server/frontend/src/components/Register/Register.jsx b/server/frontend/src/components/Register/Register.jsx new file mode 100644 index 0000000000..9f1a290327 --- /dev/null +++ b/server/frontend/src/components/Register/Register.jsx @@ -0,0 +1,98 @@ +import React, { useState } from "react"; +import "./Register.css"; +import user_icon from "../assets/person.png" +import email_icon from "../assets/email.png" +import password_icon from "../assets/password.png" +import close_icon from "../assets/close.png" + +const Register = () => { + + const [userName, setUserName] = useState(""); + const [password, setPassword] = useState(""); + const [email, setEmail] = useState(""); + const [firstName, setFirstName] = useState(""); + const [lastName, setlastName] = useState(""); + + + const gohome = ()=> { + window.location.href = window.location.origin; + } + + const register = async (e) => { + e.preventDefault(); + + let register_url = window.location.origin+"/djangoapp/register"; + + const res = await fetch(register_url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + "userName": userName, + "password": password, + "firstName":firstName, + "lastName":lastName, + "email":email + }), + }); + + const json = await res.json(); + if (json.status) { + sessionStorage.setItem('username', json.userName); + window.location.href = window.location.origin; + } + else if (json.error === "Already Registered") { + alert("The user with same username is already registered"); + window.location.href = window.location.origin; + } +}; + + return( + <div className="register_container" style={{width: "50%"}}> + <div className="header" style={{display: "flex",flexDirection: "row", justifyContent: "space-between"}}> + <span className="text" style={{flexGrow:"1"}}>SignUp</span> + <div style={{display: "flex",flexDirection: "row", justifySelf: "end", alignSelf: "start" }}> + <a href="/" onClick={()=>{gohome()}} style={{justifyContent: "space-between", alignItems:"flex-end"}}> + <img style={{width:"1cm"}} src={close_icon} alt="X"/> + </a> + </div> + <hr/> + </div> + + <form onSubmit={register}> + <div className="inputs"> + <div className="input"> + <img src={user_icon} className="img_icon" alt='Username'/> + <input type="text" name="username" placeholder="Username" className="input_field" onChange={(e) => setUserName(e.target.value)}/> + </div> + <div> + <img src={user_icon} className="img_icon" alt='First Name'/> + <input type="text" name="first_name" placeholder="First Name" className="input_field" onChange={(e) => setFirstName(e.target.value)}/> + </div> + + <div> + <img src={user_icon} className="img_icon" alt='Last Name'/> + <input type="text" name="last_name" placeholder="Last Name" className="input_field" onChange={(e) => setlastName(e.target.value)}/> + </div> + + <div> + <img src={email_icon} className="img_icon" alt='Email'/> + <input type="email" name="email" placeholder="email" className="input_field" onChange={(e) => setEmail(e.target.value)}/> + </div> + + <div className="input"> + <img src={password_icon} className="img_icon" alt='password'/> + <input name="psw" type="password" placeholder="Password" className="input_field" onChange={(e) => setPassword(e.target.value)}/> + </div> + + </div> + <div className="submit_panel"> + <input className="submit" type="submit" value="Register"/> + </div> + </form> + </div> + ) +} + +export default Register; \ No newline at end of file diff --git a/server/frontend/static/About.html b/server/frontend/static/About.html index 484efd960f..3c53408d7d 100644 --- a/server/frontend/static/About.html +++ b/server/frontend/static/About.html @@ -1,6 +1,8 @@ <html> <head> - <!-- Link the style sheet here --> + <!-- Link the style sheet here done--> + <link rel="stylesheet" href="/static/style.css"> + <link rel="stylesheet" href="/static/bootstrap.min.css"> </head> <div> <nav class="navbar navbar-expand-lg navbar-light" style="background-color:darkturquoise; height: 1in;"> @@ -27,36 +29,38 @@ <h2 style="padding-right: 5%;">Dealerships</h2> <div class="card" style="width: 80%;margin: auto; margin-top:5%;"> <div class="banner" name="about-header"> - <!-- Insert header information here --> + <!-- Insert header information here Done--> + <h1>About Us</h1> + Welcome to Best Cars dealership, home to the best cars in North America. We deal in sale of domestic and imported cars at reasonable prices. </div> <div style="display: flex;flex-direction: row; margin:auto"> <div class="card" style="width: 30%;"> <img class="card-img-top" src="/static/person.png" alt="Card image"> <div class="card-body"> - <p class="title">Person1</p> - <p>Person1 Title</p> - <p class="card-text">Some text that explains the person1 in about 2 short sentences</p> - <p>person1@example.com</p> + <p class="title">Hercules</p> + <p>Hercules</p> + <p class="card-text">Strong Enough to get you going</p> + <p>H@olympus.com</p> </div> </div> <div class="card" style="width: 30%;"> <img class="card-img-top" src="/static/person.png" alt="Card image"> <div class="card-body"> - <p class="title">Person2</p> - <p>Person2 Title</p> - <p class="card-text">Some text that explains the person2 in about 2 short sentences</p> - <p>person2@example.com</p> + <p class="title">Achilles</p> + <p>Achilles</p> + <p class="card-text">Ancient who deals in Wheels</p> + <p>A@olympus.com</p> </div> </div> <div class="card" style="width: 30%;"> <img class="card-img-top" src="/static/person.png" alt="Card image"> <div class="card-body"> - <p class="title">Person3</p> - <p>Person3 Title</p> - <p class="card-text">Some text that explains the person3 in about 2 short sentences</p> - <p>person3@example.com</p> + <p class="title">Zeus</p> + <p>Zeus</p> + <p class="card-text">Godly</p> + <p>Daddy@olympus.com</p> </div> </div> </div> diff --git a/server/frontend/static/Contact.html b/server/frontend/static/Contact.html new file mode 100644 index 0000000000..87ccb6dad3 --- /dev/null +++ b/server/frontend/static/Contact.html @@ -0,0 +1,95 @@ +<html> +<head> + <!-- Link the style sheet here done--> + <link rel="stylesheet" href="/static/style.css"> + <link rel="stylesheet" href="/static/bootstrap.min.css"> +</head> +<div> + <nav class="navbar navbar-expand-lg navbar-light" style="background-color:darkturquoise; height: 1in;"> + <div class="container-fluid"> + <h2 style="padding-right: 5%;">Dealerships</h2> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> + <div class="collapse navbar-collapse" id="navbarText"> + <ul class="navbar-nav me-auto mb-2 mb-lg-0"> + <li class="nav-item"> + <a class="nav-link" style="font-size: larger;" aria-current="page" href="/">Home</a> + </li> + <li class="nav-item"> + <a class="nav-link active" style="font-size: larger;" href="/about">About Us</a> + </li> + <li class="nav-item"> + <a class="nav-link" style="font-size: larger;" href="/contact">Contact Us</a> + </li> + </ul> + </div> + </div> + </nav> + + <h1>Contact Us</h1> + + <img class="banner" src="/static/beetle temp.png" alt="Car" width ="300" height ="600"> + <div class="contact-info"> + <p><strong>Email:</strong> info@olympus.com</p> + <p><strong>Phone:</strong> (123) 456-7890</p> + </div> + + <html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Contact Us</title> + <style> + body { + font-family: Arial, sans-serif; + line-height: 1.6; + margin: 0; + padding: 20px; + } + form { + max-width: 500px; + margin: auto; + } + label { + display: block; + margin-bottom: 5px; + } + input, textarea { + width: 100%; + padding: 8px; + margin-bottom: 10px; + box-sizing: border-box; + } + button { + background-color: #4CAF50; + color: white; + padding: 10px 15px; + border: none; + cursor: pointer; + } + button:hover { + background-color: #45a049; + } + </style> + </head> + <body> + + <form action="#" method="post"> + <label for="name">Name:</label> + <input type="text" id="name" name="name" required> + + <label for="email">Email:</label> + <input type="email" id="email" name="email" required> + + <label for="subject">Subject:</label> + <input type="text" id="subject" name="subject" required> + + <label for="message">Message:</label> + <textarea id="message" name="message" rows="5" required></textarea> + + <button type="submit">Send</button> + </form> + +</body> +</html> \ No newline at end of file diff --git a/server/frontend/static/Home.html b/server/frontend/static/Home.html index fb0c3fb617..a4070803ea 100644 --- a/server/frontend/static/Home.html +++ b/server/frontend/static/Home.html @@ -7,7 +7,22 @@ <script> const logout = async (e) => { -//Include the code for logout here. + let logout_url = window.location.origin+"/djangoapp/logout"; + const res = await fetch(logout_url, { + method: "GET", + }); + + const json = await res.json(); + if (json) { + let username = sessionStorage.getItem('username'); + sessionStorage.removeItem('username'); + window.location.href = window.location.origin; + window.location.reload(); + alert("Logging out "+username+"...") + } + else { + alert("The user could not be logged out.") + } }; let checkSession = ()=>{ diff --git a/server/frontend/static/beetle temp.png b/server/frontend/static/beetle temp.png new file mode 100644 index 0000000000..e7568fa81e Binary files /dev/null and b/server/frontend/static/beetle temp.png differ diff --git a/server/frontend/static/person copy.png b/server/frontend/static/person copy.png new file mode 100644 index 0000000000..72ce98a965 Binary files /dev/null and b/server/frontend/static/person copy.png differ diff --git a/server/frontend/static/person.png b/server/frontend/static/person.png index 72ce98a965..89c3914743 100644 Binary files a/server/frontend/static/person.png and b/server/frontend/static/person.png differ