Compare commits

..

3 Commits

Author SHA1 Message Date
niyas 1992e967b5 Merge pull request 'added background video' (#4) from course into master
Reviewed-on: #4
2025-11-05 19:04:33 +00:00
niyas 103d79a472 Merge pull request 'course' (#3) from course into master
Reviewed-on: #3
2025-11-03 04:41:58 +00:00
niyas 76be77a2d5 Merge pull request 'course' (#2) from course into master
Reviewed-on: #2
2025-10-23 13:30:28 +00:00
37 changed files with 140 additions and 618 deletions

View File

@ -1,29 +1,29 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (8.0.4) actioncable (8.0.3)
actionpack (= 8.0.4) actionpack (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (8.0.4) actionmailbox (8.0.3)
actionpack (= 8.0.4) actionpack (= 8.0.3)
activejob (= 8.0.4) activejob (= 8.0.3)
activerecord (= 8.0.4) activerecord (= 8.0.3)
activestorage (= 8.0.4) activestorage (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
mail (>= 2.8.0) mail (>= 2.8.0)
actionmailer (8.0.4) actionmailer (8.0.3)
actionpack (= 8.0.4) actionpack (= 8.0.3)
actionview (= 8.0.4) actionview (= 8.0.3)
activejob (= 8.0.4) activejob (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
mail (>= 2.8.0) mail (>= 2.8.0)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (8.0.4) actionpack (8.0.3)
actionview (= 8.0.4) actionview (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
rack (>= 2.2.4) rack (>= 2.2.4)
rack-session (>= 1.0.1) rack-session (>= 1.0.1)
@ -31,35 +31,35 @@ GEM
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
useragent (~> 0.16) useragent (~> 0.16)
actiontext (8.0.4) actiontext (8.0.3)
actionpack (= 8.0.4) actionpack (= 8.0.3)
activerecord (= 8.0.4) activerecord (= 8.0.3)
activestorage (= 8.0.4) activestorage (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (8.0.4) actionview (8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
activejob (8.0.4) activejob (8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (8.0.4) activemodel (8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
activerecord (8.0.4) activerecord (8.0.3)
activemodel (= 8.0.4) activemodel (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activestorage (8.0.4) activestorage (8.0.3)
actionpack (= 8.0.4) actionpack (= 8.0.3)
activejob (= 8.0.4) activejob (= 8.0.3)
activerecord (= 8.0.4) activerecord (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (8.0.4) activesupport (8.0.3)
base64 base64
benchmark (>= 0.3) benchmark (>= 0.3)
bigdecimal bigdecimal
@ -78,14 +78,12 @@ GEM
base64 (0.3.0) base64 (0.3.0)
bcrypt (3.1.20) bcrypt (3.1.20)
bcrypt_pbkdf (1.1.1) bcrypt_pbkdf (1.1.1)
bcrypt_pbkdf (1.1.1-arm64-darwin) benchmark (0.4.1)
bcrypt_pbkdf (1.1.1-x86_64-darwin) bigdecimal (3.2.3)
benchmark (0.5.0)
bigdecimal (3.3.1)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.18.6) bootsnap (1.18.6)
msgpack (~> 1.2) msgpack (~> 1.2)
brakeman (7.1.1) brakeman (7.1.0)
racc racc
builder (3.3.0) builder (3.3.0)
capybara (3.40.0) capybara (3.40.0)
@ -100,7 +98,7 @@ GEM
concurrent-ruby (1.3.5) concurrent-ruby (1.3.5)
connection_pool (2.5.4) connection_pool (2.5.4)
crass (1.0.6) crass (1.0.6)
date (3.5.0) date (3.4.1)
debug (1.11.0) debug (1.11.0)
irb (~> 1.10) irb (~> 1.10)
reline (>= 0.3.8) reline (>= 0.3.8)
@ -113,22 +111,15 @@ GEM
dotenv (3.1.8) dotenv (3.1.8)
drb (2.2.3) drb (2.2.3)
ed25519 (1.4.0) ed25519 (1.4.0)
erb (5.1.3) erb (5.0.2)
erubi (1.13.1) erubi (1.13.1)
et-orbi (1.4.0) et-orbi (1.4.0)
tzinfo tzinfo
ffi (1.17.2-aarch64-linux-gnu)
ffi (1.17.2-aarch64-linux-musl)
ffi (1.17.2-arm-linux-gnu)
ffi (1.17.2-arm-linux-musl)
ffi (1.17.2-arm64-darwin)
ffi (1.17.2-x86_64-darwin)
ffi (1.17.2-x86_64-linux-gnu) ffi (1.17.2-x86_64-linux-gnu)
ffi (1.17.2-x86_64-linux-musl)
font-awesome-sass (5.15.1) font-awesome-sass (5.15.1)
sassc (>= 1.11) sassc (>= 1.11)
fugit (1.12.1) fugit (1.11.2)
et-orbi (~> 1.4) et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4) raabro (~> 1.4)
globalid (1.3.0) globalid (1.3.0)
activesupport (>= 6.1) activesupport (>= 6.1)
@ -142,15 +133,15 @@ GEM
activesupport (>= 6.0.0) activesupport (>= 6.0.0)
railties (>= 6.0.0) railties (>= 6.0.0)
io-console (0.8.1) io-console (0.8.1)
irb (1.15.3) irb (1.15.2)
pp (>= 0.6.0) pp (>= 0.6.0)
rdoc (>= 4.0.0) rdoc (>= 4.0.0)
reline (>= 0.4.2) reline (>= 0.4.2)
jbuilder (2.14.1) jbuilder (2.14.1)
actionview (>= 7.0.0) actionview (>= 7.0.0)
activesupport (>= 7.0.0) activesupport (>= 7.0.0)
json (2.15.2) json (2.15.0)
kamal (2.8.2) kamal (2.7.0)
activesupport (>= 7.0) activesupport (>= 7.0)
base64 (~> 0.2) base64 (~> 0.2)
bcrypt_pbkdf (~> 1.0) bcrypt_pbkdf (~> 1.0)
@ -167,8 +158,7 @@ GEM
loofah (2.24.1) loofah (2.24.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
mail (2.9.0) mail (2.8.1)
logger
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
net-imap net-imap
net-pop net-pop
@ -178,9 +168,9 @@ GEM
mini_magick (5.3.1) mini_magick (5.3.1)
logger logger
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.26.0) minitest (5.25.5)
msgpack (1.8.0) msgpack (1.8.0)
net-imap (0.5.12) net-imap (0.5.10)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
@ -194,33 +184,19 @@ GEM
net-smtp (0.5.1) net-smtp (0.5.1)
net-protocol net-protocol
net-ssh (7.3.0) net-ssh (7.3.0)
nio4r (2.7.5) nio4r (2.7.4)
nokogiri (1.18.10-aarch64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.10-aarch64-linux-musl)
racc (~> 1.4)
nokogiri (1.18.10-arm-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.10-arm-linux-musl)
racc (~> 1.4)
nokogiri (1.18.10-arm64-darwin)
racc (~> 1.4)
nokogiri (1.18.10-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.10-x86_64-linux-gnu) nokogiri (1.18.10-x86_64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.10-x86_64-linux-musl)
racc (~> 1.4)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ostruct (0.6.3) ostruct (0.6.3)
parallel (1.27.0) parallel (1.27.0)
parser (3.3.10.0) parser (3.3.9.0)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pp (0.6.3) pp (0.6.2)
prettyprint prettyprint
prettyprint (0.2.0) prettyprint (0.2.0)
prism (1.6.0) prism (1.5.1)
propshaft (1.3.1) propshaft (1.3.1)
actionpack (>= 7.0.0) actionpack (>= 7.0.0)
activesupport (>= 7.0.0) activesupport (>= 7.0.0)
@ -229,11 +205,11 @@ GEM
date date
stringio stringio
public_suffix (6.0.2) public_suffix (6.0.2)
puma (7.1.0) puma (7.0.4)
nio4r (~> 2.0) nio4r (~> 2.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.8.1) racc (1.8.1)
rack (3.2.4) rack (3.2.1)
rack-session (2.1.1) rack-session (2.1.1)
base64 (>= 0.1.0) base64 (>= 0.1.0)
rack (>= 3.0.0) rack (>= 3.0.0)
@ -241,20 +217,20 @@ GEM
rack (>= 1.3) rack (>= 1.3)
rackup (2.2.1) rackup (2.2.1)
rack (>= 3) rack (>= 3)
rails (8.0.4) rails (8.0.3)
actioncable (= 8.0.4) actioncable (= 8.0.3)
actionmailbox (= 8.0.4) actionmailbox (= 8.0.3)
actionmailer (= 8.0.4) actionmailer (= 8.0.3)
actionpack (= 8.0.4) actionpack (= 8.0.3)
actiontext (= 8.0.4) actiontext (= 8.0.3)
actionview (= 8.0.4) actionview (= 8.0.3)
activejob (= 8.0.4) activejob (= 8.0.3)
activemodel (= 8.0.4) activemodel (= 8.0.3)
activerecord (= 8.0.4) activerecord (= 8.0.3)
activestorage (= 8.0.4) activestorage (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 8.0.4) railties (= 8.0.3)
rails-dom-testing (2.3.0) rails-dom-testing (2.3.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
@ -262,9 +238,9 @@ GEM
rails-html-sanitizer (1.6.2) rails-html-sanitizer (1.6.2)
loofah (~> 2.21) loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (8.0.4) railties (8.0.3)
actionpack (= 8.0.4) actionpack (= 8.0.3)
activesupport (= 8.0.4) activesupport (= 8.0.3)
irb (~> 1.13) irb (~> 1.13)
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
@ -272,11 +248,10 @@ GEM
tsort (>= 0.2) tsort (>= 0.2)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.3.1) rake (13.3.0)
rdoc (6.15.1) rdoc (6.14.2)
erb erb
psych (>= 4.0.0) psych (>= 4.0.0)
tsort
regexp_parser (2.11.3) regexp_parser (2.11.3)
reline (0.6.2) reline (0.6.2)
io-console (~> 0.5) io-console (~> 0.5)
@ -284,7 +259,7 @@ GEM
actionpack (>= 7.0) actionpack (>= 7.0)
railties (>= 7.0) railties (>= 7.0)
rexml (3.4.4) rexml (3.4.4)
rubocop (1.81.7) rubocop (1.81.1)
json (~> 2.3) json (~> 2.3)
language_server-protocol (~> 3.17.0.2) language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0) lint_roller (~> 1.1.0)
@ -298,10 +273,10 @@ GEM
rubocop-ast (1.47.1) rubocop-ast (1.47.1)
parser (>= 3.3.7.2) parser (>= 3.3.7.2)
prism (~> 1.4) prism (~> 1.4)
rubocop-performance (1.26.1) rubocop-performance (1.26.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (>= 1.75.0, < 2.0) rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.47.1, < 2.0) rubocop-ast (>= 1.44.0, < 2.0)
rubocop-rails (2.33.4) rubocop-rails (2.33.4)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
@ -316,7 +291,7 @@ GEM
ruby-vips (2.2.5) ruby-vips (2.2.5)
ffi (~> 1.12) ffi (~> 1.12)
logger logger
rubyzip (3.2.2) rubyzip (3.1.1)
sassc (2.4.0) sassc (2.4.0)
ffi (~> 1.9) ffi (~> 1.9)
sassc-rails (2.1.2) sassc-rails (2.1.2)
@ -326,7 +301,7 @@ GEM
sprockets-rails sprockets-rails
tilt tilt
securerandom (0.4.1) securerandom (0.4.1)
selenium-webdriver (4.38.0) selenium-webdriver (4.35.0)
base64 (~> 0.2) base64 (~> 0.2)
logger (~> 1.4) logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5) rexml (~> 3.2, >= 3.2.5)
@ -337,15 +312,15 @@ GEM
activejob (>= 7.2) activejob (>= 7.2)
activerecord (>= 7.2) activerecord (>= 7.2)
railties (>= 7.2) railties (>= 7.2)
solid_cache (1.0.8) solid_cache (1.0.7)
activejob (>= 7.2) activejob (>= 7.2)
activerecord (>= 7.2) activerecord (>= 7.2)
railties (>= 7.2) railties (>= 7.2)
solid_queue (1.2.4) solid_queue (1.2.1)
activejob (>= 7.1) activejob (>= 7.1)
activerecord (>= 7.1) activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1) concurrent-ruby (>= 1.3.1)
fugit (~> 1.11) fugit (~> 1.11.0)
railties (>= 7.1) railties (>= 7.1)
thor (>= 1.3.1) thor (>= 1.3.1)
sprockets (4.2.2) sprockets (4.2.2)
@ -356,14 +331,7 @@ GEM
actionpack (>= 6.1) actionpack (>= 6.1)
activesupport (>= 6.1) activesupport (>= 6.1)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sqlite3 (2.8.0-aarch64-linux-gnu) sqlite3 (2.7.4-x86_64-linux-gnu)
sqlite3 (2.8.0-aarch64-linux-musl)
sqlite3 (2.8.0-arm-linux-gnu)
sqlite3 (2.8.0-arm-linux-musl)
sqlite3 (2.8.0-arm64-darwin)
sqlite3 (2.8.0-x86_64-darwin)
sqlite3 (2.8.0-x86_64-linux-gnu)
sqlite3 (2.8.0-x86_64-linux-musl)
sshkit (1.24.0) sshkit (1.24.0)
base64 base64
logger logger
@ -375,15 +343,11 @@ GEM
railties (>= 6.0.0) railties (>= 6.0.0)
stringio (3.1.7) stringio (3.1.7)
thor (1.4.0) thor (1.4.0)
thruster (0.1.16) thruster (0.1.15-x86_64-linux)
thruster (0.1.16-aarch64-linux)
thruster (0.1.16-arm64-darwin)
thruster (0.1.16-x86_64-darwin)
thruster (0.1.16-x86_64-linux)
tilt (2.6.1) tilt (2.6.1)
timeout (0.4.4) timeout (0.4.3)
tsort (0.2.0) tsort (0.2.0)
turbo-rails (2.0.20) turbo-rails (2.0.17)
actionpack (>= 7.1.0) actionpack (>= 7.1.0)
railties (>= 7.1.0) railties (>= 7.1.0)
tzinfo (2.0.6) tzinfo (2.0.6)
@ -391,7 +355,7 @@ GEM
unicode-display_width (3.2.0) unicode-display_width (3.2.0)
unicode-emoji (~> 4.1) unicode-emoji (~> 4.1)
unicode-emoji (4.1.0) unicode-emoji (4.1.0)
uri (1.1.1) uri (1.1.0)
useragent (0.16.11) useragent (0.16.11)
warden (1.2.9) warden (1.2.9)
rack (>= 2.0.9) rack (>= 2.0.9)
@ -410,15 +374,7 @@ GEM
zeitwerk (2.7.3) zeitwerk (2.7.3)
PLATFORMS PLATFORMS
aarch64-linux x86_64-linux
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
arm64-darwin
x86_64-darwin
x86_64-linux-gnu
x86_64-linux-musl
DEPENDENCIES DEPENDENCIES
bootsnap bootsnap
@ -449,4 +405,4 @@ DEPENDENCIES
web-console web-console
BUNDLED WITH BUNDLED WITH
2.5.7 2.4.20

View File

@ -2,6 +2,3 @@
//= link_directory ../stylesheets .css //= link_directory ../stylesheets .css
//= link_tree ../video .mp4 //= link_tree ../video .mp4
//= link just.mp4 //= link just.mp4
// Include all JavaScript files from app/javascript so importmap-pinned modules
// (e.g. dropdown.js, flash_messages.js) are available to the asset pipeline.
//= link_tree ../../javascript .js

View File

@ -9,8 +9,6 @@
* Consider organizing styles into separate files for maintainability. * Consider organizing styles into separate files for maintainability.
*/ */
@import "font-awesome"; @import "font-awesome";
@import "trix/dist/trix.css";
#flash-message { #flash-message {
position: fixed; position: fixed;

View File

@ -1,76 +0,0 @@
class CategoriesController < ApplicationController
before_action :set_category, only: %i[ show edit update destroy ]
# GET /categories or /categories.json
def index
@categories = Category.includes(:products).all
@categories.each do |category|
category.products = category.products || []
end
end
# GET /categories/1 or /categories/1.json
def show
# `set_category` before_action will load @category; expose associated products as @products
@products = @category.products
end
# GET /categories/new
def new
@category = Category.new
end
# GET /categories/1/edit
def edit
end
# POST /categories or /categories.json
def create
@category = Category.new(category_params)
respond_to do |format|
if @category.save
format.html { redirect_to @category, notice: "Category was successfully created." }
format.json { render :show, status: :created, location: @category }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /categories/1 or /categories/1.json
def update
respond_to do |format|
if @category.update(category_params)
format.html { redirect_to @category, notice: "Category was successfully updated.", status: :see_other }
format.json { render :show, status: :ok, location: @category }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @category.errors, status: :unprocessable_entity }
end
end
end
# DELETE /categories/1 or /categories/1.json
def destroy
@category.destroy!
respond_to do |format|
format.html { redirect_to categories_path, notice: "Category was successfully destroyed.", status: :see_other }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_category
@category = Category.find(params[:id])
end
# Only allow a list of trusted parameters through.
def category_params
params.require(:category).permit(:name, :description, :image)
end
end

View File

@ -33,24 +33,19 @@ class ExpensesController < ApplicationController
# GET /expenses/report # GET /expenses/report
def report def report
# Daily expenses set_summary
@daily_expense_items = Expense.where(date: Date.today) render :report
@daily_expense = @daily_expense_items.sum(:amount) @daily_expense_items = Expense.where(date: Date.today.all_day)
# Weekly expenses
@weekly_expense_items = Expense.where(date: Date.today.beginning_of_week..Date.today.end_of_week) @weekly_expense_items = Expense.where(date: Date.today.beginning_of_week..Date.today.end_of_week)
@weekly_expense = @weekly_expense_items.sum(:amount)
# Monthly expenses
@monthly_expense_items = Expense.where(date: Date.today.beginning_of_month..Date.today.end_of_month) @monthly_expense_items = Expense.where(date: Date.today.beginning_of_month..Date.today.end_of_month)
@monthly_expense = @monthly_expense_items.sum(:amount)
# For chart - last 7 days @daily_expenses = @daily_expense_items.sum(:amount)
@chart_labels = (0..6).map { |i| (Date.today - i).strftime("%d %b") }.reverse @weekly_expenses = @weekly_expense_items.sum(:amount)
@chart_data = @chart_labels.map { |date_str| @monthly_expenses = @monthly_expense_items.sum(:amount)
date = Date.parse(date_str)
Expense.where(date: date).sum(:amount) # For chart
} @chart_labels = @monthly_expense_items.pluck(:date).map { |d| d.strftime("%d %b") }
@chart_data = @monthly_expense_items.pluck(:amount)
end end
# GET /expenses/new # GET /expenses/new

View File

@ -8,8 +8,6 @@ class ProductsController < ApplicationController
# GET /products/1 or /products/1.json # GET /products/1 or /products/1.json
def show def show
@category = Category.find_by(id: params[:id])
@product = Product.find_by(id: params[:id])
end end
# GET /products/new # GET /products/new
@ -67,6 +65,6 @@ class ProductsController < ApplicationController
# Only allow a list of trusted parameters through. # Only allow a list of trusted parameters through.
def product_params def product_params
params.require(:product).permit(:name, :category_id, :description, :price, images: []) params.expect(product: [ :name, :description, :price, images: [] ])
end end
end end

View File

@ -1,2 +0,0 @@
module CategoriesHelper
end

View File

@ -1,11 +0,0 @@
// migrated from app/assets/javascripts/application.js
document.addEventListener("DOMContentLoaded", () => {
const flash = document.getElementById("flash-message");
if (flash) {
setTimeout(() => {
flash.style.transition = "opacity 0.5s ease";
flash.style.opacity = "0";
setTimeout(() => flash.remove(), 500);
}, 3000);
}
});

View File

@ -1,6 +0,0 @@
class Category < ApplicationRecord
has_rich_text :description
has_one_attached :image
# Use lowercase association name so ActiveRecord sets up `category.products`
has_many :products, dependent: :destroy
end

View File

@ -1,6 +1,4 @@
class Product < ApplicationRecord class Product < ApplicationRecord
has_rich_text :description has_rich_text :description
has_many_attached :images has_many_attached :images
belongs_to :category
end end

View File

@ -1,24 +0,0 @@
<div id="<%= dom_id category %>">
<h1><%= category.name %></h1>
<p>
<strong>Description:</strong>
<%= category.description %>
</p>
<p>
<strong>Image:</strong>
<%= link_to category.image.filename, category.image if category.image.attached? %>
</p>
<% if products.present? %>
<h2>Products in this Category</h2>
<ul>
<% products.each do |product| %>
<li><%= product.name %> - $<%= product.price %></li>
<% end %>
</ul>
<% else %>
<p>No products available in this category.</p>
<% end %>
</div>

View File

@ -1,4 +0,0 @@
json.extract! category, :id, :name, :description, :image, :created_at, :updated_at
json.url category_url(category, format: :json)
json.description category.description.to_s
json.image url_for(category.image)

View File

@ -1,32 +0,0 @@
<%= form_with(model: category) do |form| %>
<% if category.errors.any? %>
<div style="color: red">
<h2><%= pluralize(category.errors.count, "error") %> prohibited this category from being saved:</h2>
<ul>
<% category.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.label :name, style: "display: block" %>
<%= form.text_field :name %>
</div>
<div>
<%= form.label :description, style: "display: block" %>
<%= form.rich_textarea :description %>
</div>
<div>
<%= form.label :image, style: "display: block" %>
<%= form.file_field :image %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>

View File

@ -1,12 +0,0 @@
<% content_for :title, "Editing category" %>
<h1>Editing category</h1>
<%= render "form", category: @category %>
<br>
<div>
<%= link_to "Show this category", @category %> |
<%= link_to "Back to categories", categories_path %>
</div>

View File

@ -1,16 +0,0 @@
<p style="color: green"><%= notice %></p>
<% content_for :title, "Categories" %>
<h1>Categories</h1>
<div id="categories">
<% @categories.each do |category| %>
<%= render partial: "category", locals: {category: category, products: category.products} %>
<p>
<%= link_to "Show this category", category %>
</p>
<% end %>
</div>
<%= link_to "New category", new_category_path %>

View File

@ -1 +0,0 @@
json.array! @categories, partial: "categories/category", as: :category

View File

@ -1,11 +0,0 @@
<% content_for :title, "New category" %>
<h1>New category</h1>
<%= render "form", category: @category %>
<br>
<div>
<%= link_to "Back to categories", categories_path %>
</div>

View File

@ -1,10 +0,0 @@
<p style="color: green"><%= notice %></p>
<%= render partial: "category", locals: { category: @category, products: @products } %>
<div>
<%= link_to "Edit this category", edit_category_path(@category) %> |
<%= link_to "Back to categories", categories_path %>
<%= button_to "Destroy this category", @category, method: :delete %>
</div>

View File

@ -1 +0,0 @@
json.partial! "categories/category", category: @category

View File

@ -202,7 +202,7 @@
<tr> <tr>
<td><%= expense.title %></td> <td><%= expense.title %></td>
<td><%= number_to_currency(expense.amount, unit: "₹") %></td> <td><%= number_to_currency(expense.amount, unit: "₹") %></td>
<td><%= expense.date.strftime("%d %b %Y") %></td> <td><%= expense.created_at.strftime("%d %b %Y") %></td>
<td><%= expense.description %></td> <td><%= expense.description %></td>
</tr> </tr>
<% end %> <% end %>
@ -233,7 +233,7 @@
<tr> <tr>
<td><%= expense.title %></td> <td><%= expense.title %></td>
<td><%= number_to_currency(expense.amount, unit: "₹") %></td> <td><%= number_to_currency(expense.amount, unit: "₹") %></td>
<td><%= expense.date.strftime("%d %b %Y") %></td> <td><%= expense.created_at.strftime("%d %b %Y") %></td>
<td><%= expense.description %></td> <td><%= expense.description %></td>
</tr> </tr>
<% end %> <% end %>
@ -264,7 +264,7 @@
<tr> <tr>
<td><%= expense.title %></td> <td><%= expense.title %></td>
<td><%= number_to_currency(expense.amount, unit: "₹") %></td> <td><%= number_to_currency(expense.amount, unit: "₹") %></td>
<td><%= expense.date.strftime("%d %b %Y") %></td> <td><%= expense.created_at.strftime("%d %b %Y") %></td>
<td><%= expense.description %></td> <td><%= expense.description %></td>
</tr> </tr>
<% end %> <% end %>

View File

@ -53,8 +53,8 @@ html, body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: "Poppins", sans-serif; font-family: "Poppins", sans-serif;
background: #181a1b !important; background: linear-gradient(135deg, #0f1724, #1e293b);
color: #0f1724; color: #e6eef6;
} }
.page-wrapper { .page-wrapper {
@ -65,7 +65,7 @@ html, body {
} }
.container { .container {
max-width: 100%; max-width: 1900px;
margin: 0 auto; margin: 0 auto;
padding-top: 20px; padding-top: 20px;
flex: 1; flex: 1;

View File

@ -5,16 +5,13 @@
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= csp_meta_tag %> <%= csp_meta_tag %>
<!-- Include compiled application CSS (includes Trix/ActionText styles) -->
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<!-- Importmap / application JS (Turbo, Stimulus, Trix, ActionText, etc.) -->
<%= javascript_importmap_tags %>
<%= yield :head %>
<%= yield :head %>
<%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
<%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>
@ -150,50 +147,10 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
.navbar { .navbar {
position: fixed; position: fixed;
top: 0; top: 0;
width: 88%; width: 100%;
margin-left: 12%;
} }
</style>
/* Sidebar styles */
.sidebar {
position: fixed;
top: 0; /* align under navbar */
left: 0;
bottom: 0;
width: 240px;
padding: 18px;
background: rgba(28,30,33,0.95);
color: #e6eef0;
border-right: 1px solid rgba(255,255,255,0.03);
z-index: 1040;
transition: transform .28s ease, width .2s ease;
overflow-y: auto;
}
.sidebar .side-logo { width:44px; height:44px; border-radius:8px; object-fit:cover; }
.sidebar .sidebar-brand { display:flex; align-items:center; gap:12px; margin-bottom:12px; }
.sidebar .brand-text { font-weight:700; color:#bfe6c8; font-size:1rem }
.sidebar .sidebar-toggle { margin-left:auto; background:transparent; border:none; color: #cfe9d8; font-size:1.1rem; cursor:pointer; }
.sidebar-nav ul { list-style:none; padding:0; margin:6px 0; }
.sidebar-nav li { margin:8px 0; }
.sidebar-nav a { color: #e6eef0; text-decoration:none; display:flex; gap:10px; align-items:center; padding:8px 10px; border-radius:8px; }
.sidebar-nav a:hover { background: rgba(30,136,229,0.12); color: #fff; }
/* Main content shift */
.main-container { margin-left: 0; transition: margin-left .28s ease; }
@media (min-width: 992px) {
.main-container { margin-left: 260px; }
}
/* Collapsed state */
.sidebar.collapsed { transform: translateX(-100%); }
@media (max-width: 991px) {
.sidebar { transform: translateX(-100%); }
.sidebar.open { transform: translateX(0); }
.main-container { margin-left: 0; }
}
</style>
<%# Includes all stylesheet files in app/assets/stylesheets %> <%# Includes all stylesheet files in app/assets/stylesheets %>
@ -218,6 +175,27 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
<!-- Nav Links --> <!-- Nav Links -->
<div class="collapse navbar-collapse" id="mainNav"> <div class="collapse navbar-collapse" id="mainNav">
<ul class="navbar-nav ms-auto mb-2 mb-lg-0"> <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item">
<%= link_to "🏠 Home", root_path, class: "nav-link active" %>
</li>
<li class="nav-item">
<%= link_to "🎓 Programs", programs_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "🕌 Ziyara", ziyaras_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "📚 All Students", students_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "💰 Income", incomes_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "📊 Expenses", expenses_path, class: "nav-link" %>
</li>
<li class="nav-item">
<%= link_to "🏫 Records", exclusive_traditional_records_path, class: "nav-link" %>
</li>
<li class="nav-item"> <li class="nav-item">
<%= link_to "📞 Contact", contact_path, class: "nav-link" %> <%= link_to "📞 Contact", contact_path, class: "nav-link" %>
</li> </li>
@ -300,29 +278,9 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
<% content_for :title, "Institutions & Programs" %> <% content_for :title, "Institutions & Programs" %>
<!-- LEFT SIDEBAR -->
<aside class="sidebar" id="appSidebar" aria-label="Main navigation">
<div class="sidebar-brand">
<%= image_tag("unnamed.jpg", alt: "Logo", class: "side-logo") %>
<div class="brand-text">Badar Madeena</div>
<button class="sidebar-toggle" id="sidebarToggle" aria-label="Toggle sidebar">☰</button>
</div>
<nav class="sidebar-nav">
<ul>
<li><%= link_to "🏠 Home", root_path %></li>
<li><%= link_to "🎓 Programs", programs_path %></li>
<li><%= link_to "🕌 Ziyara", ziyaras_path %></li>
<li><%= link_to "📚 Students", students_path %></li>
<li><%= link_to "💰 Income", incomes_path %></li>
<li><%= link_to "📊 Expenses", expenses_path %></li>
<li><%= link_to "🏫 Records", exclusive_traditional_records_path %></li>
<li><%= link_to "📞 Products", products_path %></li>
</ul>
</nav>
</aside>
<% if flash.any? %> <% if flash.any? %>
<% flash.each do |name, message| %> <% flash.each do |name, message| %>
<% if name.to_s == 'notice' || name.to_s == 'alert' %> <% if name.to_s == 'notice' || name.to_s == 'alert' %>
<div class="alert alert-<%= name.to_s == 'notice' ? 'success' : 'danger' %>"> <div class="alert alert-<%= name.to_s == 'notice' ? 'success' : 'danger' %>">
@ -332,31 +290,13 @@ background: linear-gradient(-45deg, #1e88e5, #43a047, #6a1b9a, #d81b60);
<% end %> <% end %>
<% end %> <% end %>
<div class="main-container"> <div class="container shadow rounded p-4 bg-white mt-4">
<div class="container shadow rounded p-4 bg-white mt-4"> <%= yield %>
<%= yield %>
</div>
</div> </div>
<footer class="footer text-center mt-5 mb-3 text-muted"> <footer class="footer text-center mt-5 mb-3 text-muted">
&copy; <%= Time.current.year %> Badar Madeena &copy; <%= Time.current.year %> Badar Madeena
</footer> </footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Sidebar toggle behavior
document.addEventListener('DOMContentLoaded', function () {
const toggle = document.getElementById('sidebarToggle');
const sidebar = document.getElementById('appSidebar');
if (toggle && sidebar) {
toggle.addEventListener('click', function () {
// For small screens toggle open class
if (window.innerWidth < 992) {
sidebar.classList.toggle('open');
} else {
sidebar.classList.toggle('collapsed');
}
});
}
});
</script>
</body> </body>
</html> </html>

View File

@ -16,11 +16,6 @@
<%= form.text_field :name %> <%= form.text_field :name %>
</div> </div>
<div>
<%= form.label :category_id, "Category", style: "display: block" %>
<%= form.collection_select :category_id, Category.all, :id, :name, prompt: "Select Category" %>
</div>
<div> <div>
<%= form.label :description, style: "display: block" %> <%= form.label :description, style: "display: block" %>
<%= form.rich_textarea :description %> <%= form.rich_textarea :description %>

View File

@ -8,12 +8,7 @@
<strong>Description:</strong> <strong>Description:</strong>
<%= product.description %> <%= product.description %>
</p> </p>
<p>
<strong>Category:</strong>
<%= product.category.name if product.category %>
</p>
<p> <p>
<strong>Images:</strong> <strong>Images:</strong>
<% product.images.each do |image| %> <% product.images.each do |image| %>

View File

@ -24,8 +24,6 @@ module BadarMadeena
# config.time_zone = "Central Time (US & Canada)" # config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras") # config.eager_load_paths << Rails.root.join("extras")
config.assets.enabled = true config.assets.enabled = true
config.assets.paths << Rails.root.join("app/assets")
# Set the URL options for ActiveStorage # Set the URL options for ActiveStorage
config.active_storage.service_urls_expire_in = 5.minutes # Optional: You can set the expiration time for URLs here if you need config.active_storage.service_urls_expire_in = 5.minutes # Optional: You can set the expiration time for URLs here if you need

View File

@ -1,9 +1,5 @@
# Load the Rails application. # Load the Rails application.
require_relative "application" require_relative "application"
# If you're using Propshaft, ensure it's correctly initialized
require "propshaft"
# Initialize the Rails application. # Initialize the Rails application.
Rails.application.initialize! Rails.application.initialize!

View File

@ -87,11 +87,4 @@ Rails.application.configure do
# #
# Skip DNS rebinding protection for the default health check endpoint. # Skip DNS rebinding protection for the default health check endpoint.
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } } # config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
config.assets.compile = false # Do not compile assets on the fly in production
config.assets.digest = true # Generate digests for asset URLs
config.assets.js_compressor = :uglifier # Optional for JavaScript minification
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? || ENV['RAILS_ENV'] == 'production'
end end

View File

@ -9,5 +9,5 @@ pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/core@2.11.8/lib/inde
pin_all_from "app/javascript/controllers", under: "controllers" pin_all_from "app/javascript/controllers", under: "controllers"
pin "dropdown", to: "dropdown.js" pin "dropdown", to: "dropdown.js"
pin "flash_messages", to: "flash_messages.js" pin "flash_messages", to: "flash_messages.js"
pin "trix", to: "trix.js" pin "trix"
pin "@rails/actiontext", to: "actiontext.esm.js" pin "@rails/actiontext", to: "actiontext.esm.js"

View File

@ -1,5 +1,4 @@
Rails.application.routes.draw do Rails.application.routes.draw do
resources :categories
resources :products resources :products
devise_for :users devise_for :users
@ -23,10 +22,6 @@ Rails.application.routes.draw do
resources :students resources :students
end end
resources :categories do
resources :products
end
get "up" => "rails/health#show", as: :rails_health_check get "up" => "rails/health#show", as: :rails_health_check
get 'contact', to: 'institutions#contact' get 'contact', to: 'institutions#contact'

View File

@ -1,9 +0,0 @@
class CreateCategories < ActiveRecord::Migration[8.0]
def change
create_table :categories do |t|
t.string :name
t.timestamps
end
end
end

View File

@ -1,5 +0,0 @@
class AddCategoryToProducts < ActiveRecord::Migration[8.0]
def change
add_reference :products, :category, null: true, foreign_key: true
end
end

11
db/schema.rb generated
View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_11_06_132715) do ActiveRecord::Schema[8.0].define(version: 2025_11_05_180728) do
create_table "action_mailbox_inbound_emails", force: :cascade do |t| create_table "action_mailbox_inbound_emails", force: :cascade do |t|
t.integer "status", default: 0, null: false t.integer "status", default: 0, null: false
t.string "message_id", null: false t.string "message_id", null: false
@ -58,12 +58,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_06_132715) do
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end end
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "exclusive_traditional_records", force: :cascade do |t| create_table "exclusive_traditional_records", force: :cascade do |t|
t.string "name" t.string "name"
t.string "author" t.string "author"
@ -115,8 +109,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_06_132715) do
t.decimal "price" t.decimal "price"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.integer "category_id"
t.index ["category_id"], name: "index_products_on_category_id"
end end
create_table "programs", force: :cascade do |t| create_table "programs", force: :cascade do |t|
@ -161,6 +153,5 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_06_132715) do
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "products", "categories"
add_foreign_key "students", "institutions" add_foreign_key "students", "institutions"
end end

View File

@ -1,48 +0,0 @@
require "test_helper"
class CategoriesControllerTest < ActionDispatch::IntegrationTest
setup do
@category = categories(:one)
end
test "should get index" do
get categories_url
assert_response :success
end
test "should get new" do
get new_category_url
assert_response :success
end
test "should create category" do
assert_difference("Category.count") do
post categories_url, params: { category: { name: @category.name } }
end
assert_redirected_to category_url(Category.last)
end
test "should show category" do
get category_url(@category)
assert_response :success
end
test "should get edit" do
get edit_category_url(@category)
assert_response :success
end
test "should update category" do
patch category_url(@category), params: { category: { name: @category.name } }
assert_redirected_to category_url(@category)
end
test "should destroy category" do
assert_difference("Category.count", -1) do
delete category_url(@category)
end
assert_redirected_to categories_url
end
end

View File

@ -1,7 +0,0 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
name: MyString
two:
name: MyString

View File

@ -1,7 +0,0 @@
require "test_helper"
class CategoryTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

View File

@ -1,41 +0,0 @@
require "application_system_test_case"
class CategoriesTest < ApplicationSystemTestCase
setup do
@category = categories(:one)
end
test "visiting the index" do
visit categories_url
assert_selector "h1", text: "Categories"
end
test "should create category" do
visit categories_url
click_on "New category"
fill_in "Name", with: @category.name
click_on "Create Category"
assert_text "Category was successfully created"
click_on "Back"
end
test "should update Category" do
visit category_url(@category)
click_on "Edit this category", match: :first
fill_in "Name", with: @category.name
click_on "Update Category"
assert_text "Category was successfully updated"
click_on "Back"
end
test "should destroy Category" do
visit category_url(@category)
click_on "Destroy this category", match: :first
assert_text "Category was successfully destroyed"
end
end