diff --git a/app/views/components/_footer.html.erb b/app/views/components/_footer.html.erb new file mode 100644 index 0000000..00f3466 --- /dev/null +++ b/app/views/components/_footer.html.erb @@ -0,0 +1,83 @@ + diff --git a/app/views/components/_header.html.erb b/app/views/components/_header.html.erb index 7dce183..ef47c74 100644 --- a/app/views/components/_header.html.erb +++ b/app/views/components/_header.html.erb @@ -32,50 +32,57 @@ - - + <% else %> + + + <% end %>
@@ -98,27 +105,33 @@
-
-
Test
-
Test
-
+ <% if user_signed_in? %> +
+
<%= current_user.email %>
+
<%= current_user.email %>
+
-
- <%= link_to "Mon profil", "#", class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> - <%= link_to "Mes réservations", "#", class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> +
+ <%= link_to "Mon profil", edit_user_registration_path, class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> + <%= link_to "Mes réservations", "#", class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> - - <%= link_to "Déconnexion", destroy_user_session_path, - data: { - controller: "logout", - action: "click->logout#signOut", - logout_url_value: destroy_user_session_path, - login_url_value: new_user_session_path, - turbo: false - }, - class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out" %> - -
+ + <%= link_to "Déconnexion", destroy_user_session_path, + data: { + controller: "logout", + action: "click->logout#signOut", + logout_url_value: destroy_user_session_path, + login_url_value: new_user_session_path, + turbo: false + }, + class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> +
+ <% else %> +
+ <%= link_to "S'inscrire", new_user_registration_path, class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> + <%= link_to "Se connecter", new_user_session_path, class: "block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-400 hover:text-white hover:bg-gray-800 hover:border-white focus:outline-none focus:text-white focus:bg-gray-800 focus:border-white transition duration-150 ease-in-out" %> +
+ <% end %>
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 5ede964..c5bf1f1 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -1,26 +1,68 @@ -

Log in

- -<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> -
- <%= f.label :email %>
- <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
- -
- <%= f.label :password %>
- <%= f.password_field :password, autocomplete: "current-password" %> -
- - <% if devise_mapping.rememberable? %> -
- <%= f.check_box :remember_me %> - <%= f.label :remember_me %> +
+
+
+ <%= link_to "/" do %> + Aperonight + <% end %> +

+ Connexion à votre compte +

+

+ Ou + + créez un nouveau compte + +

- <% end %> -
- <%= f.submit "Log in" %> + <%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "mt-8 space-y-6" }) do |f| %> + <%= devise_error_messages! %> + +
+
+ <%= f.label :email, class: "sr-only" %> + <%= f.email_field :email, autofocus: true, autocomplete: "email", + class: "appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-700 placeholder-gray-500 text-gray-100 bg-gray-800 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm", + placeholder: "Adresse email" %> +
+ +
+ <%= f.label :password, class: "sr-only" %> + <%= f.password_field :password, autocomplete: "current-password", + class: "appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-700 placeholder-gray-500 text-gray-100 bg-gray-800 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm", + placeholder: "Mot de passe" %> +
+
+ + <% if devise_mapping.rememberable? %> +
+
+ <%= f.check_box :remember_me, class: "h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-700 rounded bg-gray-800" %> + +
+ +
+ <%= link_to "Mot de passe oublié?", new_password_path(resource_name), class: "font-medium text-indigo-400 hover:text-indigo-300" %> +
+
+ <% end %> + +
+ <%= f.submit "Se connecter", class: "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-500" %> +
+ <% end %> + +
+
+
+
+
+
+ Ou continuer avec +
+
+ + <%= render "devise/shared/links" %> +
-<% end %> - -<%= render "devise/shared/links" %> +
diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb index 7a75304..b4d28a7 100644 --- a/app/views/devise/shared/_links.html.erb +++ b/app/views/devise/shared/_links.html.erb @@ -1,25 +1,39 @@ -<%- if controller_name != 'sessions' %> - <%= link_to "Log in", new_session_path(resource_name) %>
-<% end %> - -<%- if devise_mapping.registerable? && controller_name != 'registrations' %> - <%= link_to "Sign up", new_registration_path(resource_name) %>
-<% end %> - -<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> - <%= link_to "Forgot your password?", new_password_path(resource_name) %>
-<% end %> - -<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> - <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
-<% end %> - -<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> - <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
-<% end %> - -<%- if devise_mapping.omniauthable? %> - <%- resource_class.omniauth_providers.each do |provider| %> - <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
+
+ <%- if controller_name != "sessions" %> +
+ <%= link_to "Se connecter", new_session_path(resource_name), class: "block" %> +
<% end %> -<% end %> + + <%- if devise_mapping.registerable? && controller_name != "registrations" %> +
+ <%= link_to "S'inscrire", new_registration_path(resource_name), class: "" %> +
+ <% end %> + + <%- if devise_mapping.recoverable? && controller_name != "passwords" && controller_name != "registrations" %> +
+ <%= link_to "Mot de passe oublié ?", new_password_path(resource_name), class: "" %> +
+ <% end %> + + <%- if devise_mapping.confirmable? && controller_name != "confirmations" %> +
+ <%= link_to "Vous n'avez pas reçu les instructions de confirmation ?", new_confirmation_path(resource_name), class: "" %> +
+ <% end %> + + <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != "unlocks" %> +
+ <%= link_to "Vous n'avez pas reçu les instructions de déverrouillage?", new_unlock_path(resource_name), class: "" %> +
+ <% end %> + + <%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> +
+ <%= button_to "Se connecter avec #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: "" %> +
+ <% end %> + <% end %> +
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 6115481..1c7cda4 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -28,6 +28,12 @@ <%= render "components/header" %>
- <%= yield %> +
+ <%= yield %> +
+ + diff --git a/config/routes.rb b/config/routes.rb index c65ec18..51f88eb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,7 +15,7 @@ Rails.application.routes.draw do # Routes for devise authentication Gem # Bind devise to user # devise_for :users - devise_for :users, path: "authentications", path_names: { + devise_for :users, path: "auth", path_names: { sign_up: "register", # Route for user registration sign_in: "login", # Route for user login sign_out: "logout", # Route for user logout diff --git a/docs/architecture.txt b/docs/architecture.txt deleted file mode 100644 index 8e4188b..0000000 --- a/docs/architecture.txt +++ /dev/null @@ -1,1055 +0,0 @@ -Cette conversation a été générée avec Duck.ai (https://duck.ai) à l'aide du modèle Mistral Small 3 d'Mistral AI. Les chats IA peuvent afficher des informations inexactes ou offensantes (voir https://duckduckgo.com/duckai/privacy-terms pour en savoir plus). - -==================== - -Message 1 sur 6 de l'utilisateur - 16/08/2025, 08:29:15: -For a git Ruby on Rails web project with the the goal to propose night parties in Paris and allow party maker to create their own parties. - -The application for customers must: -* shows parties (upcoming and past) -* permit user to book one or many tickets for a party (choosing their bundle : simple entry, 4 people pass with bottle, VIP, etc) -* accept credit cards, paypal, bank account payments -* generate unique tickets (per person or per order -* be able to be used on mobile to permit promotors to scan tickets using phone - -For promotors: -* allow them to create and program parties -* aggregate parties from other website (shogun, bizouk, weezevent) - -Give advices on this application and give the arhitecture to implement. - -Mistral Small 3: -Creating a Ruby on Rails web application for proposing night parties in Paris and allowing party makers to create their own parties is an exciting project. Below are some advices and an architecture to implement this application. - -### Advices - -1. **User Authentication and Authorization**: - - Use Devise for user authentication. - - Use Pundit or CanCanCan for authorization to manage different roles (customers, promoters). - -2. **Payment Integration**: - - Use Stripe for credit card payments. - - Use PayPal for PayPal payments. - - For bank account payments, consider integrating with a service like Plaid or directly with a banking API. - -3. **Ticket Generation**: - - Generate unique tickets using a combination of UUIDs and QR codes. - - Use a library like `rufus-scheduler` to handle ticket expiration and validation. - -4. **Mobile Compatibility**: - - Ensure the application is responsive and mobile-friendly. - - Use a library like `qrcode` to generate QR codes for tickets. - - For scanning tickets, use a mobile-friendly QR code scanner library like `zxing` or `html5-qrcode`. - -5. **Aggregation of Parties**: - - Use web scraping or APIs provided by other websites (Shogun, Bizouk, Weezevent) to aggregate parties. - - Consider using a background job processor like Sidekiq for periodic data aggregation. - -6. **Performance and Scalability**: - - Use caching mechanisms like Redis or Memcached to improve performance. - - Consider using a CDN for static assets. - - Implement background jobs for time-consuming tasks like sending emails or processing payments. - -### Architecture - -#### 1. **Database Schema** - -```ruby -# User -create_table :users do |t| - t.string :email - t.string :password_digest - t.string :role # customer or promoter - t.timestamps -end - -# Party -create_table :parties do |t| - t.string :name - t.text :description - t.datetime :start_time - t.datetime :end_time - t.string :location - t.integer :promoter_id - t.timestamps -end - -# Ticket -create_table :tickets do |t| - t.string :uuid - t.string :qr_code - t.integer :party_id - t.integer :user_id - t.string :bundle_type # simple entry, 4 people pass with bottle, VIP, etc - t.boolean :used, default: false - t.timestamps -end - -# Payment -create_table :payments do |t| - t.string :payment_method # credit_card, paypal, bank_account - t.string :transaction_id - t.integer :user_id - t.integer :ticket_id - t.decimal :amount - t.timestamps -end -``` - -#### 2. **Models** - -```ruby -class User < ApplicationRecord - devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :validatable - has_many :tickets - has_many :payments -end - -class Party < ApplicationRecord - belongs_to :promoter, class_name: 'User' - has_many :tickets -end - -class Ticket < ApplicationRecord - belongs_to :party - belongs_to :user - has_one :payment - - before_create :generate_uuid_and_qr_code - - private - - def generate_uuid_and_qr_code - self.uuid = SecureRandom.uuid - self.qr_code = RQRCode::QRCode.new(self.uuid).as_svg - end -end - -class Payment < ApplicationRecord - belongs_to :user - belongs_to :ticket -end -``` - -#### 3. **Controllers** - -```ruby -class PartiesController < ApplicationController - before_action :authenticate_user! - before_action :set_party, only: [:show, :edit, :update, :destroy] - - def index - @parties = Party.all - end - - def show - end - - def new - @party = Party.new - end - - def create - @party = current_user.parties.build(party_params) - if @party.save - redirect_to @party, notice: 'Party was successfully created.' - else - render :new - end - end - - def edit - end - - def update - if @party.update(party_params) - redirect_to @party, notice: 'Party was successfully updated.' - else - render :edit - end - end - - def destroy - @party.destroy - redirect_to parties_url, notice: 'Party was successfully destroyed.' - end - - private - - def set_party - @party = Party.find(params[:id]) - end - - def party_params - params.require(:party).permit - --------------------- - -Message 2 sur 6 de l'utilisateur - 16/08/2025, 08:30:32: -For the bundles, promotors must be able to define their own for party they craete - -Mistral Small 3: -To allow promoters to define their own bundles for the parties they create, you need to introduce a `Bundle` model that will be associated with the `Party` model. This will enable promoters to create custom bundles for each party, specifying details like the bundle type, price, and any additional perks. - -### Updated Database Schema - -```ruby -# Bundle -create_table :bundles do |t| - t.string :name - t.text :description - t.decimal :price - t.integer :party_id - t.timestamps -end -``` - -### Updated Models - -```ruby -class User < ApplicationRecord - devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :validatable - has_many :tickets - has_many :payments - has_many :parties, foreign_key: 'promoter_id' -end - -class Party < ApplicationRecord - belongs_to :promoter, class_name: 'User' - has_many :tickets - has_many :bundles -end - -class Ticket < ApplicationRecord - belongs_to :party - belongs_to :user - belongs_to :bundle - has_one :payment - - before_create :generate_uuid_and_qr_code - - private - - def generate_uuid_and_qr_code - self.uuid = SecureRandom.uuid - self.qr_code = RQRCode::QRCode.new(self.uuid).as_svg - end -end - -class Payment < ApplicationRecord - belongs_to :user - belongs_to :ticket -end - -class Bundle < ApplicationRecord - belongs_to :party - has_many :tickets -end -``` - -### Updated Controllers - -#### PartiesController - -```ruby -class PartiesController < ApplicationController - before_action :authenticate_user! - before_action :set_party, only: [:show, :edit, :update, :destroy] - - def index - @parties = Party.all - end - - def show - @bundles = @party.bundles - end - - def new - @party = Party.new - @party.bundles.build - end - - def create - @party = current_user.parties.build(party_params) - if @party.save - redirect_to @party, notice: 'Party was successfully created.' - else - render :new - end - end - - def edit - @bundles = @party.bundles - end - - def update - if @party.update(party_params) - redirect_to @party, notice: 'Party was successfully updated.' - else - render :edit - end - end - - def destroy - @party.destroy - redirect_to parties_url, notice: 'Party was successfully destroyed.' - end - - private - - def set_party - @party = Party.find(params[:id]) - end - - def party_params - params.require(:party).permit(:name, :description, :start_time, :end_time, :location, bundles_attributes: [:id, :name, :description, :price, :_destroy]) - end -end -``` - -#### BundlesController - -```ruby -class BundlesController < ApplicationController - before_action :authenticate_user! - before_action :set_bundle, only: [:show, :edit, :update, :destroy] - - def index - @bundles = Bundle.all - end - - def show - end - - def new - @bundle = Bundle.new - end - - def create - @bundle = Bundle.new(bundle_params) - if @bundle.save - redirect_to @bundle, notice: 'Bundle was successfully created.' - else - render :new - end - end - - def edit - end - - def update - if @bundle.update(bundle_params) - redirect_to @bundle, notice: 'Bundle was successfully updated.' - else - render :edit - end - end - - def destroy - @bundle.destroy - redirect_to bundles_url, notice: 'Bundle was successfully destroyed.' - end - - private - - def set_bundle - @bundle = Bundle.find(params[:id]) - end - - def bundle_params - params.require(:bundle).permit(:name, :description, :price, :party_id) - end -end -``` - -### Views - -#### parties/_form.html.erb - -```erb -<%= form_with(model: party, local: true) do |form| %> - <% if party.errors.any? %> -
-

<%= pluralize(party.errors.count, "error") %> prohibited this party from being saved:

-