Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
adeeb2024 committed Feb 18, 2025
2 parents 5cf562d + 702d16b commit f955ef1
Show file tree
Hide file tree
Showing 86 changed files with 3,550 additions and 1,587 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/laravel.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Laravel

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
laravel-tests:

runs-on: ubuntu-latest

steps:
- uses: shivammathur/setup-php@15c43e89cdef867065b0213be354c2841860869e
with:
php-version: '8.3'
- uses: actions/checkout@v4
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Generate key
run: php artisan key:generate
- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
- name: Create Database
run: |
mkdir -p database
touch database/database.sqlite
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ yarn-error.log
/.vscode
/.zed
/.vs
**/.DS_Store
.DS_Store
43 changes: 43 additions & 0 deletions app/Charts/StockSalesChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace App\Charts;

use App\Models\IndividualOrder;
use App\Models\Product;
use marineusde\LarapexCharts\Charts\LineChart AS OriginalLineChart;
use marineusde\LarapexCharts\Options\XAxisOption;

// class for creating a stock sales chart for a specified product
class StockSalesChart
{
public function build(Product $product): OriginalLineChart
{
// an array for storing the date of the last 14 days
$last14days = [now()->day];
for ($i = 1; $i < 14; $i++) {
$last14days[] = now()->subDays($i)->day;
} // [14,13,12,11,10,9,8,7,6,5,4,3,2,1]
$last14days = array_reverse($last14days); // [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
// get number of sales from each of the last 14 days
$salesPerDay = [];
foreach ($last14days as $day) {
$salesPerDay[] = IndividualOrder::all()->where('product_id', $product->id)->where('created_at', $day)->count();
} // [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
// now roughly calculate the stock level for each of the last 14 days
$salesPerDay = array_reverse($salesPerDay); // [14,13,12,11,10,9,8,7,6,5,4,3,2,1]
$stockCount = $product->stock;
$stockLevel = [$stockCount];
foreach ($salesPerDay as $sales) {
$stockCount += $sales;
$stockLevel[] = $stockCount;
} // [14,13,12,11,10,9,8,7,6,5,4,3,2,1]
$stockLevel = array_reverse($stockLevel); // [1,2,3,4,5,6,7,8,9,10,11,12,13,14]

// returns the built chart with the required data
return (new OriginalLineChart)
->setTitle('Daily Stock levels for ' . $product->name)
->setSubtitle('Last 14 days')
->addData('Stock level', $stockLevel)
->setXAxisOption(new XAxisOption($last14days));
}
}
Binary file added app/Http/Controllers/.DS_Store
Binary file not shown.
89 changes: 89 additions & 0 deletions app/Http/Controllers/Admin/ProductManagementController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Product;
use App\Models\Category;
use Illuminate\Support\Str;
use App\Models\ProductImage;




class ProductManagementController extends Controller
{
public function index()
{
$products = Product::paginate(10);
return view('pages.admin.admin_product_page', compact('products'));
}

public function create()
{
$categories = Category::all(); // Fetch all categories
return view('pages.admin.create_product', compact('categories'));
}

public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'category_id' => 'required|exists:categories,id',
'colour' => 'nullable|string',
'description' => 'nullable|string',
'mens' => 'required|boolean',
'stock' => 'required|integer|min:0',
'images.*' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
]);

$product = Product::create($request->except('images'));

if ($request->hasFile('images')) {
foreach ($request->file('images') as $image) {
// Generate a unique file name using UUID
$imageName = Str::uuid() . '.' . $image->getClientOriginalExtension();
$image->move(public_path('images/productImage'), $imageName);

// Store the image in `product_images` table
ProductImage::create([
'product_id' => $product->id,
'image_name' => $imageName,
]);
}
}

return redirect()->route('admin.products.index')->with('success', 'Product created successfully.');
}

public function edit(Product $product)
{
return view('pages.admin.edit_product', compact('product'));
}



public function update(Request $request, Product $product)
{
$request->validate([
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'category_id' => 'required|exists:categories,id',
]);

$product->update($request->all());

return redirect()->route('admin.products.index')->with('success', 'Product updated successfully.');
}

public function destroy(Product $product)
{
ProductImage::where('product_id', $product->id)->delete();

$product->delete();

return redirect()->route('admin.products.index')->with('success', 'Product deleted successfully.');
}
}
36 changes: 20 additions & 16 deletions app/Http/Controllers/Auth/LoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class LoginController extends Controller
{
Expand All @@ -19,23 +20,22 @@ public function authenticate(Request $request)
'password' => 'required|string',
'redirect' => 'string|nullable',
]);
// get the redirect from the request
if(isset($credentials['redirect'])) {
$redirect = "/" . $credentials['redirect'];
} else {
$redirect = '/home';
}
// remove redirect from credentials before auth check

$redirect = isset($credentials['redirect']) ? "/" . $credentials['redirect'] : '/home';

unset($credentials['redirect']);
// Attempt to log the user in

if (Auth::attempt($credentials)) {
$request->session()->regenerate();
// redirect to specified page

Log::info('User Logged In:', ['id' => Auth::id(), 'email' => Auth::user() ? Auth::user()->email : 'N/A']);

session(['user_id' => Auth::id()]);
session()->save();

return redirect()->intended($redirect)->with('success', 'Login successful!');

}

// Return back with an error if authentication fails
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
])->withInput();
Expand All @@ -47,20 +47,24 @@ public function authenticate(Request $request)
public function logout(Request $request)
{
Auth::logout();


session()->forget('user_id');

$request->session()->invalidate();
$request->session()->regenerateToken();

return redirect('/login')->with('success', 'Logged out successfully!');
}

// controller to get the login page
public function show($redirect = 'account') {
// just redirect if already logged in
/**
* Controller to get the login page.
*/
public function show($redirect = 'account')
{
if (Auth::check()) {
return redirect($redirect);
}
// return the login page with redirect in session

return view('pages.login', ['redirect' => $redirect]);
}
}
8 changes: 8 additions & 0 deletions app/Http/Controllers/CheckoutController.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ public function checkout(Request $request)
}

foreach ($basket as $basketItem) {
// to reduce the stock level of hte given item
$product = $basketItem->product;
$product['quantity'] = $product['quantity'] - $basketItem->quantity;
// add to popularity count (5 for each order)
$product['popularity'] = $product['popularity'] + (5 * $basketItem->quantity);
// save the product
$product->save();
// then delete the item from the basket
$basketItem->delete();
}

Expand Down
4 changes: 4 additions & 0 deletions app/Http/Controllers/ContactController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers;

use App\Http\Emailers\ContactEmailer;
use App\Models\ContactItem;
use Illuminate\Http\Request;

Expand Down Expand Up @@ -29,6 +30,9 @@ public function store(Request $request) {
'message' => $contactForm['message']
]);
$contactItem->save();
// sends a confirmation email
$contactEmailer = new ContactEmailer();
$contactEmailer->sendConfirmation($contactItem);
}
return redirect('/home')->with('message', 'Thanks for contacting us!');
}
Expand Down
6 changes: 3 additions & 3 deletions app/Http/Controllers/FeaturedProductController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

class FeaturedProductController extends Controller
{
// function which returns a list of 12 featured products
// function which returns a list of 8 featured products
static function getFeaturedProducts(): \Illuminate\Database\Eloquent\Collection {
// returns a random selection of 12 products
return Product::all()->random(12);
// returns a random selection of 8 products
return Product::all()->random(8);
//TODO: in future could use different logic for selecting featured products
//TODO: if never think of something delete ↑
}
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/PreviousOrders.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function show() {
}
return view('pages.previous-orders');
}
function getPreviousOrders(User $user) {
public static function getPreviousOrders($user){
$orders = Order::all()->where('user_id', $user["id"]);
return $orders;
}
Expand Down
7 changes: 6 additions & 1 deletion app/Http/Controllers/ProductSearcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ function stringSearch(String $searchTerm, String $subject): bool
return true;
}
}
// also check for substrings
if (str_contains(strtolower($subject), strtolower($searchWord))) {
return true;
}
}

// return false if nothing is found
return false;

Expand All @@ -52,7 +57,7 @@ function stringSearch(String $searchTerm, String $subject): bool

function show(String $searchTerm="") {
// converts the # back to spaces
$searchTerm = str_replace("#", " ", $searchTerm);
$searchTerm = str_replace("%20", " ", $searchTerm);
$products = self::search($searchTerm);
if (!$products) {
return view('pages.products', ['products' => $products, 'message' => "No products found"]);
Expand Down
25 changes: 25 additions & 0 deletions app/Http/Emailers/ContactEmailer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace App\Http\Emailers;

use App\Models\ContactItem;

// a class for sending the confirmation email for contact form
class ContactEmailer extends Emailer
{
public function __construct()
{
$this->name = 'support';
}
// constructs and sends the confirmation email based on provided contactItem
public function sendConfirmation(ContactItem $contactItem): bool
{
// set all the details for the email
$to = $contactItem->email;
$subject = 'SportsWear - Thanks for contacting us!';
$message = 'Hello ' . $contactItem->name . ', we have received your message and will get back to you as soon as possible. Your message: ' . $contactItem->message;
// send the email
return $this->sendEmail($to, $subject, $message);
}

}
33 changes: 33 additions & 0 deletions app/Http/Emailers/Emailer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace App\Http\Emailers;

use Mailgun\Mailgun;

// a class for sending emails
class Emailer
{
public string $name;
// name goes to the sender address {name}@something
public function __construct($name)
{
$this->name = $name;
}
public function sendEmail($to, $subject, $message): bool
{
try {
// connect to mailgun API (need to put api key in the .env file)
$mg = Mailgun::create(env('MAILGUN_SECRET'), "https://api.eu.mailgun.net");
// send email
$mg->messages()->send('mail.thesportswear.website', [
'from' => $this->name . "@mail.thesportswear.website",
'to' => $to,
'subject' => $subject,
'text' => $message
]);
return true;
} catch (\Exception $e) {
return false;
}
}
}
Loading

0 comments on commit f955ef1

Please sign in to comment.