diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..c99d2e73 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/Gemfile b/Gemfile index 2bcbdd0c..2a7867cb 100644 --- a/Gemfile +++ b/Gemfile @@ -56,7 +56,11 @@ group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem 'debug', platforms: %i[mri windows] # 處理機密 放在測試跟開發: + gem 'database_cleaner-active_record' gem 'dotenv-rails', '~> 2.8' + gem 'factory_bot_rails' + gem 'rails-controller-testing' + gem 'rspec-rails' end group :development do @@ -113,4 +117,3 @@ gem 'geocoder', '~> 1.8' gem 'httparty', '~> 0.21.0' # 下載 AWS S3 gem 'aws-sdk-s3', require: false - diff --git a/Gemfile.lock b/Gemfile.lock index c7aaa756..fabe8dd5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -117,6 +117,10 @@ GEM crass (1.0.6) cssbundling-rails (1.3.3) railties (>= 6.0.0) + database_cleaner-active_record (2.1.0) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) date (3.3.4) debug (1.9.0) irb (~> 1.10) @@ -127,6 +131,7 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) + diff-lcs (1.5.0) dotenv (2.8.1) dotenv-rails (2.8.1) dotenv (= 2.8.1) @@ -134,6 +139,11 @@ GEM drb (2.2.0) ruby2_keywords erubi (1.12.0) + factory_bot (6.4.5) + activesupport (>= 5.0.0) + factory_bot_rails (6.4.3) + factory_bot (~> 6.4) + railties (>= 5.0.0) faker (3.2.2) i18n (>= 1.8.11, < 2) ffi (1.16.3) @@ -246,6 +256,10 @@ GEM activesupport (= 7.1.2) bundler (>= 1.15.0) railties (= 7.1.2) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -284,6 +298,23 @@ GEM railties (>= 5.2) rexml (3.2.6) rouge (4.2.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.6) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-rails (6.1.0) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.12) + rspec-expectations (~> 3.12) + rspec-mocks (~> 3.12) + rspec-support (~> 3.12) + rspec-support (3.12.1) rubocop (1.59.0) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -359,9 +390,11 @@ DEPENDENCIES bootsnap capybara cssbundling-rails + database_cleaner-active_record debug devise (~> 4.9) dotenv-rails (~> 2.8) + factory_bot_rails faker (~> 3.2) foreman (~> 0.87.2) friendly_id (~> 5.4.0) @@ -378,11 +411,13 @@ DEPENDENCIES puma (>= 5.0) pundit (~> 2.3) rails (~> 7.1.2) + rails-controller-testing ranked-model (~> 0.4.9) ransack (~> 4.1) redcarpet (~> 3.6) redis (>= 4.0.1) rouge (~> 4.2) + rspec-rails rubocop (~> 1.59) selenium-webdriver sprockets-rails diff --git a/README.md b/README.md index 9b9bea88..547c3da4 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,112 @@ -# README +# SyncSquad 同步小隊 -- run bundle install -- run yarn install -- run rails db:setup -- run bin/dev, and check http://localhost:5000 -- Starting Redis -- Install ImageMagick and/or libvips: - In a Mac terminal: $ brew install imagemagick vips - In a debian/ubuntu terminal: $ sudo apt install imagemagick libvips +► [Visit the website](https://www.syncsquad.online/en)|[瀏覽網站](https://www.syncsquad.online/tw) -# Set Steps +SyncSquad is designed to make project collaboration easy and efficient for teams of businesses. With a user-friendly design and practical features, our aim is to help you manage projects effortlessly, improve team efficiency, and achieve successful project outcomes. -- If run db:migrate failed run rails active_storage:install than run db:migrate +SyncSquad 為團隊及企業提供友善的操作體驗,以及高效率的協作環境,協助您輕鬆管理專案、提升團隊效能,順利實現專案理想成果。 + +image + +![image](https://github.com/astrocamp/15th-SyncSquad/assets/136299906/8be375cc-326f-4ef7-9c1a-2092d6792f44) + +► [Demo video | 展示影片](https://www.youtube.com/watch?v=fhR7VEXZubE) +[![影片示範](https://img.youtube.com/vi/fhR7VEXZubE/0.jpg)](https://www.youtube.com/watch?v=fhR7VEXZubE) + +## Features ── 特色功能 + +### 1. CSV Import CSV 匯入 + +Our website has two types of members: company accounts and employee accounts. The ability to manage employee data is granted exclusively to company accounts and employee accounts with the role of "HR". In addition to creating individual employee profiles, multiple employee accounts can be efficiently established by importing a CSV file. We use Sidekiq for asynchronous processing during the import of multiple employee records, addressing potential webpage delays and ensuring a seamless data management experience. + +本網站的會員分為兩種,一種是公司帳號,一種是員工帳號,並且唯有公司帳號和身份為「人資」的員工帳號能夠管理員工資料。除了基本的單一員工資料建立,也能透過匯入 CSV 檔案建立多個員工帳號。透過 Sidekiq 進行非同步處理,在匯入多筆員工資料時進行非同步處理,解決資料寫入時可能的網頁延遲問題。 + +CSV 匯入定建立員工資料 + +### 2. Project Management 專案管理 + +When accessing the project list, you can quickly locate specific projects through the search feature and view the highlighted keyword positions marked with a highlighter, allow users can find the keyword easily. Upon entering a project or creating a new one, you can categorize tasks within a "List" for more effective organization. Additionally, you have the ability to record relevant data such as time, location, and priority for individual tasks. Whether in "Board Mode" or "Calendar Mode" when viewing project details, you can easily modify task details through a drag-and-drop interface. All of these capabilities are made possible by integrating open-source packages, including Sortable, Ranked-model, and Full Calendar, providing an excellent user experience. + +進入專案列表時,能夠經由搜尋列表快速查找特定專案,並且查看有標示螢光筆的關鍵字位置,讓使用者可以視覺感上更輕易的找到關鍵字內容。進入專案或是建立專案後,可以「任務」在「列表」內,以便進行更有效的分類。此外,你還有能為單一任務記錄相關的時間、地點和優先級等數據。在「看板模式」或「行事曆模式」查看專案資料時,你可以輕鬆透過拖拉方式修改任務的細節。這一切皆得益於結合了開源套件,包括 Sortable、Ranked-model 以及 Full Calendar,提供優秀的操作體驗。 + +專案卡片 +專案行事曆 + +### 3. Communication Chatroom 即時聊天室 + +In our multifunctional chat environment, we provide private group chat rooms, one-on-one chat rooms for confidential discussions, and public group chat rooms for open conversations. These options cater to various communication needs, allowing users to engage in private group discussions, have one-on-one conversations securely, or participate in public group chats for more open interactions. Through the integration of Turbo and Action Cable, users can enjoy real-time updates, receive notifications for unread messages, and stay informed with the latest discussions, whether accessing the platform via a web browser or a mobile device. Our responsive design interface ensures that instant communication meets the synchronization requirements of teams, regardless of the device used. + +多功能的聊天環境中,包含私人聊天室,用於保密的一對一對話,以及公開聊天室。以上功能得以滿足使用者不同的溝通需求,讓使用者參與私密的群組討論,進行保有隱私的一對一談話,或者在公開聊天室發表開放的言論。透過 Turbo 和 Action Cable,使用者能夠獲得聊天室的即時更新,收到未讀訊息通知,並隨時掌握最新的討論內容。不論是使用網頁瀏覽器還是手機,透過我們的響應式設計介面設計,都能確實滿足團隊的資訊同步需求。 + +即時聊天室 + +## Technologies ── 技術運用及設定 + +### Technical 使用技術 + +- Back-end 後端:Ruby on Rails +- Front-end 前端:HTML, CSS, JS, Tailwind CSS, Stimulus, Turbo +- Deployment 部署:Render +- Version Control 版本控制:Git, GitHub +- Database 資料庫:PostgreSQL, Redis, AWS S3 +- Third-Party APIs 第三方服務:Google Maps, Line Pay +- Other Tools 其他工具:Figma + +### Requirements 環境需求 + +- Ruby 3.2.2 +- Rails 7.1.2 +- PostgreSQL 14 +- Redis +- Sidekiq +- imagemagick +- libvips 7 + +### Setup Steps 設定步驟 + +``` +$ bundle install +$ yarn install +$ rails db:setup +$ redis-server +$ bundle exec sidekiq +$ bin/dev +``` + +## Contributor ── 開發團隊 + +### 劉昀瑄 (Willa Liu) + +GitHub Icon GitHub:[Liu-Yun-Syuan](https://github.com/Liu-Yun-Syuan) + +- Project Management 專案管理 +- Permission Settings 權限設定 +- Calendar Integration 行事曆串接 +- Responsive Web Design (RWD) 響應式網頁設計 + +### 劉怡萍 (Arance Liu) + +GitHub Icon GitHub:[AranceLiu](https://github.com/AranceLiu) + +- Calendar Features 行事曆功能 +- CSV Import CSV 匯入 +- Project Search 專案搜尋 +- Map Integration 地圖串接 + +### 趙奕寰 (Tim Chao) + +GitHub Icon GitHub:[TimChaoTW](https://github.com/TimChaoTW) + +- Communication Chatroom 即時聊天室 +- Text Styles 文字樣式 +- Avatar Upload 頭像上傳 +- Payment Integration 金流串接 + +### 林韋如 (Ruby Lin) + +GitHub Icon GitHub:[ryoma510260](https://github.com/ryoma510260) + +- Multilingual Support 支援多國語言 +- Member System 會員系統 +- Website Deployment 網站部署 +- AWS S3 Integration AWS S3 串接 diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index 1b1506dc..88dcf011 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -23,10 +23,10 @@ html { } .form-text { - @apply block mb-2 text-sm font-medium text-gray-900 dark:text-white; + @apply block mb-2 text-sm font-medium text-white text-gray-900; } .form-input { - @apply bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500; + @apply bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5; } .form-toggle-layer-1 { @@ -34,15 +34,15 @@ html { } .form-toggle-layer-3 { - @apply text-sm font-medium text-gray-900 ms-3 dark:text-gray-300; + @apply text-sm font-medium text-gray-900 ms-3; } .form-btn { - @apply inline-flex items-center px-5 py-2.5 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800; + @apply inline-flex items-center px-5 py-2.5 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300; } .form-d-btn { - @apply block py-2.5 px-5 text-white text-sm font-medium focus:outline-none bg-gray-600 rounded-lg border border-gray-200 hover:bg-gray-900 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700; + @apply block py-2.5 px-5 text-white text-sm font-medium focus:outline-none bg-gray-600 rounded-lg border border-gray-200 hover:bg-gray-900 focus:z-10 focus:ring-4 focus:ring-gray-200; } .msg-form { diff --git a/app/controllers/hrs_controller.rb b/app/controllers/hrs_controller.rb index 85aa420b..c8c3ea81 100644 --- a/app/controllers/hrs_controller.rb +++ b/app/controllers/hrs_controller.rb @@ -8,33 +8,48 @@ def index authorize current_company, policy_class: HrsPolicy @users = User.where(company: current_company).order(id: :desc) @user = User.new + respond_to do |format| + format.html { render :index } + format.json { render json: @user, status: :ok } + end end def create @user = User.new(user_params) - if @user.save - project = Project.create(title: I18n.t('template.project'), owner_id: @user.id) - @user.affiliated_projects << project - list = project.lists.create(title: I18n.t('template.list'), color: '#4299E1') - list.tasks.create(title: I18n.t('template.task1'), started_at: Date.current, ended_at: Date.current + 1) - list.tasks.create(title: I18n.t('template.task2'), started_at: Date.current, ended_at: Date.current + 1) - redirect_to hrs_path, success: t('hrs.creation_success') - else - redirect_to hrs_path, alert: t('hrs.creation_failed') + + respond_to do |format| + if @user.save + project = Project.create(title: I18n.t('template.project'), owner_id: @user.id) + @user.affiliated_projects << project + list = project.lists.create(title: I18n.t('template.list'), color: '#4299E1') + list.tasks.create(title: I18n.t('template.task1'), started_at: Date.current, ended_at: Date.current + 1) + list.tasks.create(title: I18n.t('template.task2'), started_at: Date.current, ended_at: Date.current + 1) + format.html { redirect_to hrs_path, success: t('hrs.creation_success') } + format.json { render json: @user, status: :ok } + else + format.html { redirect_to hrs_path, alert: t('hrs.creation_failed') } + format.json { render json: @user.errors, status: :unprocessable_entity } + end end end def update - if @user.update(user_params) - redirect_to hrs_path, success: t('hrs.update_success') - else - redirect_to hrs_path, alert: t('hrs.update_failed') + @user = User.find(params[:id]) + + respond_to do |format| + if @user.update(user_params) + format.html { redirect_to hrs_path, success: t('hrs.update_success') } + format.json { render json: @user, status: :ok } + else + format.html { redirect_to hrs_path, alert: t('hrs.update_failed') } + format.json { render json: @user.errors, status: :unprocessable_entity } + end end end def destroy @user.destroy - redirect_to hrs_path, success: t('hrs.delete_staff') + respond_to.html { redirect_to hrs_path, success: t('hrs.update_success') } end private diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index 8121a1f2..12009f5c 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -2,37 +2,37 @@ // Run that command whenever you add a new controller or create them with // ./bin/rails generate stimulus controllerName -import { application } from "./application" +import { application } from "./application"; -import CalendarController from "./calendar_controller" -application.register("calendar", CalendarController) +import CalendarController from "./calendar_controller"; +application.register("calendar", CalendarController); -import ColorPickerController from "./color_picker_controller" -application.register("color-picker", ColorPickerController) +import ColorPickerController from "./color_picker_controller"; +application.register("color-picker", ColorPickerController); -import DatepickerController from "./datepicker_controller" -application.register("datepicker", DatepickerController) +import DatepickerController from "./datepicker_controller"; +application.register("datepicker", DatepickerController); -import EventController from "./event_controller" -application.register("event", EventController) +import EventController from "./event_controller"; +application.register("event", EventController); -import MapController from "./map_controller" -application.register("map", MapController) +import MapController from "./map_controller"; +application.register("map", MapController); -import NotificationController from "./notification_controller" -application.register("notification", NotificationController) +import NotificationController from "./notification_controller"; +application.register("notification", NotificationController); -import ResetFormController from "./reset_form_controller" -application.register("reset-form", ResetFormController) +import ResetFormController from "./reset_form_controller"; +application.register("reset-form", ResetFormController); -import SlimselectController from "./slimselect_controller" -application.register("slimselect", SlimselectController) +import SlimselectController from "./slimselect_controller"; +application.register("slimselect", SlimselectController); -import SortableController from "./sortable_controller" -application.register("sortable", SortableController) +import SortableController from "./sortable_controller"; +application.register("sortable", SortableController); -import TurbomodalController from "./turbomodal_controller" -application.register("turbomodal", TurbomodalController) +import TurbomodalController from "./turbomodal_controller"; +application.register("turbomodal", TurbomodalController); import ChatroomListController from "./chatroom_list_controller"; application.register("chatroom_list", ChatroomListController); diff --git a/app/javascript/lib/fontawesome.js b/app/javascript/lib/fontawesome.js index 8c807ee2..1fbd6224 100644 --- a/app/javascript/lib/fontawesome.js +++ b/app/javascript/lib/fontawesome.js @@ -1,31 +1,32 @@ -import { library, dom } from '@fortawesome/fontawesome-svg-core' -import { faEllipsis } from '@fortawesome/free-solid-svg-icons/faEllipsis' -import { faBuilding } from '@fortawesome/free-solid-svg-icons/faBuilding' -import { faUser } from '@fortawesome/free-solid-svg-icons/faUser' -import { faPlus } from '@fortawesome/free-solid-svg-icons/faPlus' -import { faAngleRight } from '@fortawesome/free-solid-svg-icons/faAngleRight' -import { faAngleLeft } from '@fortawesome/free-solid-svg-icons/faAngleLeft' -import { faChartSimple } from '@fortawesome/free-solid-svg-icons/faChartSimple' -import { faLocationDot } from '@fortawesome/free-solid-svg-icons/faLocationDot' -import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck' -import { faAnglesUp } from '@fortawesome/free-solid-svg-icons/faAnglesUp' -import { faPen } from '@fortawesome/free-solid-svg-icons/faPen' -import { faPenToSquare as faPenToSquareSolid } from '@fortawesome/free-solid-svg-icons/faPenToSquare' -import { faCalendar } from '@fortawesome/free-regular-svg-icons/faCalendar' -import { faTrashCan } from '@fortawesome/free-regular-svg-icons/faTrashCan' -import { faPenToSquare as faPenToSquareRegular } from '@fortawesome/free-regular-svg-icons/faPenToSquare' -import { faCircleChevronLeft } from '@fortawesome/free-solid-svg-icons/faCircleChevronLeft' -import { faCrown } from '@fortawesome/free-solid-svg-icons/faCrown' -import { faAlignJustify } from '@fortawesome/free-solid-svg-icons/faAlignJustify' -import { faHourglassStart } from '@fortawesome/free-solid-svg-icons/faHourglassStart' -import { faMessage } from '@fortawesome/free-solid-svg-icons/faMessage' -import { faLock } from '@fortawesome/free-solid-svg-icons/faLock' -import { faSquarePlus } from '@fortawesome/free-solid-svg-icons/faSquarePlus' -import { faUsers } from '@fortawesome/free-solid-svg-icons/faUsers' -import { faBackward } from '@fortawesome/free-solid-svg-icons/faBackward' -import { faCommentDots } from '@fortawesome/free-regular-svg-icons/faCommentDots' -import { faXmark } from '@fortawesome/free-solid-svg-icons/faXmark' -import { faArrowRightToBracket } from '@fortawesome/free-solid-svg-icons/faArrowRightToBracket' +import { library, dom } from "@fortawesome/fontawesome-svg-core"; +import { faEllipsis } from "@fortawesome/free-solid-svg-icons/faEllipsis"; +import { faBuilding } from "@fortawesome/free-solid-svg-icons/faBuilding"; +import { faUser } from "@fortawesome/free-solid-svg-icons/faUser"; +import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus"; +import { faAngleRight } from "@fortawesome/free-solid-svg-icons/faAngleRight"; +import { faAngleLeft } from "@fortawesome/free-solid-svg-icons/faAngleLeft"; +import { faChartSimple } from "@fortawesome/free-solid-svg-icons/faChartSimple"; +import { faLocationDot } from "@fortawesome/free-solid-svg-icons/faLocationDot"; +import { faCheck } from "@fortawesome/free-solid-svg-icons/faCheck"; +import { faAnglesUp } from "@fortawesome/free-solid-svg-icons/faAnglesUp"; +import { faPen } from "@fortawesome/free-solid-svg-icons/faPen"; +import { faPenToSquare as faPenToSquareSolid } from "@fortawesome/free-solid-svg-icons/faPenToSquare"; +import { faCalendar } from "@fortawesome/free-regular-svg-icons/faCalendar"; +import { faTrashCan } from "@fortawesome/free-regular-svg-icons/faTrashCan"; +import { faPenToSquare as faPenToSquareRegular } from "@fortawesome/free-regular-svg-icons/faPenToSquare"; +import { faCircleChevronLeft } from "@fortawesome/free-solid-svg-icons/faCircleChevronLeft"; +import { faCrown } from "@fortawesome/free-solid-svg-icons/faCrown"; +import { faAlignJustify } from "@fortawesome/free-solid-svg-icons/faAlignJustify"; +import { faMessage } from "@fortawesome/free-solid-svg-icons/faMessage"; +import { faLock } from "@fortawesome/free-solid-svg-icons/faLock"; +import { faSquarePlus } from "@fortawesome/free-solid-svg-icons/faSquarePlus"; +import { faUsers } from "@fortawesome/free-solid-svg-icons/faUsers"; +import { faBackward } from "@fortawesome/free-solid-svg-icons/faBackward"; +import { faCommentDots } from "@fortawesome/free-regular-svg-icons/faCommentDots"; +import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark"; +import { faArrowRightToBracket } from "@fortawesome/free-solid-svg-icons/faArrowRightToBracket"; +import { faHourglassStart } from "@fortawesome/free-solid-svg-icons/faHourglassStart"; +import { faFileImport } from "@fortawesome/free-solid-svg-icons/faFileImport"; library.add({ faEllipsis, @@ -55,6 +56,7 @@ library.add({ faCommentDots, faXmark, faArrowRightToBracket, -}) + faFileImport, +}); -dom.watch() +dom.watch(); diff --git a/app/views/companies/new.html.erb b/app/views/companies/new.html.erb index 8be694e1..dce77265 100644 --- a/app/views/companies/new.html.erb +++ b/app/views/companies/new.html.erb @@ -1,35 +1,31 @@ -
-
- -
-
-

- <%= t('company.company_sign_up') %> -

- <%= form_with model: @company, data: { turbo: false } do |form| %> -
- <%= form.label :name, t('company.name'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - - <%= form.text_field :name, class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> -
-
- <%= form.label :email, t('company.email'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - <%= form.email_field :email, placeholder: "example@company.com", class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> -
-
- <%= form.label :password, t('company.password'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - <%= form.password_field :password, placeholder: "••••••", class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> -
-
- <%= form.label :password_confirmation, t('company.password_confirmation'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - <%= form.password_field :password_confirmation, placeholder: "••••••", class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> - -
-
- <%= form.submit class: "cursor-pointer w-full bg-gradient-to-b from-[#18376c] form-20% to-[#3779eaa3] hover:bg-blue-900 text-white font-medium rounded-lg text-sm px-5 py-2.5 text-center" %> -
- <% end %> -
+
+
+
+ +

<%= t('company.company_sign_up') %>

+
+ <%= form_with model: @company, data: { turbo: false } do |form| %> +
+
+ <%= form.label :name, t('company.name'), class: "form-text" %> + <%= form.text_field :name, placeholder: t('company.enter_name'), class: 'form-input' %> +
+
+ <%= form.label :email, t('company.email'), class: "form-text" %> + <%= form.email_field :email, placeholder: t('company.enter_email'), class: 'form-input' %> +
+
+ <%= form.label :password, t('company.password'), class: "form-text" %> + <%= form.password_field :password, placeholder: t('company.enter_password'), class: 'form-input' %> +
+
+ <%= form.label :password_confirmation, t('company.password_confirmation'), class: "form-text" %> + <%= form.password_field :password_confirmation, placeholder: t('company.enter_password_confirmation'), class: 'form-input' %> +
+
+ <%= form.submit class: "w-full px-4 py-2 font-bold text-center text-white bg-blue-500 rounded-lg cursor-pointer hover:bg-blue-700" %> +
+ <% end %>
\ No newline at end of file diff --git a/app/views/companies/sign_in.html.erb b/app/views/companies/sign_in.html.erb index df35409d..597fa324 100644 --- a/app/views/companies/sign_in.html.erb +++ b/app/views/companies/sign_in.html.erb @@ -1,31 +1,25 @@ -
-
- -
-
-

- <%= t('company.company_sign_in') %> -

- <%= form_with(url: sessions_path, scope: 'company', data: {turbo: false}) do |form| %> - -
- <%= form.label :email, t('company.email'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - <%= form.email_field :email, placeholder: "example@company.com", class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> -
-
- <%= form.label :password, t('company.password'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - <%= form.password_field :password, placeholder: "••••••", class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> -
- -
- <%= form.submit t('company.login'), class: "cursor-pointer w-full bg-gradient-to-b from-[#18376c] form-20% to-[#3779eaa3] hover:bg-blue-900 text-white font-medium rounded-lg text-sm px-5 py-2.5 text-center" %> -
-
- <%= t('company.not_registered') %>? <%= t('company.please') %><%= link_to t('company.create_account'), new_company_path, class: "text-blue-600 hover:font-bold active:bg-blue-300 focus:outline-none focus:ring" %> -
- <% end %> -
+
+
+
+ +

<%= t('company.company_sign_in') %>

+
+ <%= form_with(url: sessions_path, scope: 'company', data: {turbo: false}) do |form| %> +
+
+ <%= form.label :email, t('company.email'), class: "form-text" %> + <%= form.email_field :email, placeholder: t('company.your_email'), class: 'form-input' %> +
+
+ <%= form.label :password, t('company.password'), class: "form-text" %> + <%= form.password_field :password, placeholder: t('company.your_password'), class: 'form-input' %> +
+ <%= form.submit t('company.login'), class: "w-full my-4 px-4 py-2 font-bold text-center text-white bg-blue-500 rounded-lg cursor-pointer hover:bg-blue-700" %> +
+ <%= t('company.not_registered') %>? <%= t('company.please') %><%= link_to t('company.create_account'), new_company_path, class: "text-blue-600 hover:font-bold active:bg-blue-300 focus:outline-none focus:ring" %> +
+ <% end %>
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index 5462b7b5..93edbcbb 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -1,123 +1,46 @@ -
+
+
+

<%= t('devise.registrations.edit_user_title') %>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> - <%= render "devise/shared/error_messages", resource: resource %> -
- -
- -
- <%= image_tag(resource.avatar_thumbnail) if resource.avatar.attached? %> -
- -
-
<% end %> +
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index c72dd8e5..6ea77b69 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -1,29 +1,19 @@ -
-
- -
-
-

- <%= t('devise.user_sign_in') %> -

- <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> - -
- <%= f.label :email, t('devise.email'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - <%= f.email_field :email, placeholder: "YOUR_EMAIL", class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> -
-
- <%= f.label :password, t('devise.password'), class: "block mb-2 text-sm font-medium text-gray-900 dark:text-white" %> - <%= f.password_field :password, placeholder: "••••••", class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500' %> -
- -
- <%= f.submit t('devise.login'), class: "cursor-pointer w-full block py-2.5 px-5 word-wrap text-sm text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-200" %> -
- - <% end %> -
+
+
+

<%= t('devise.user_sign_in') %>

+ <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> +
+ <%= f.label :email, t('devise.email'), class: "form-text" %> + <%= f.email_field :email, placeholder: t('devise.session_new.your_email'), class: 'form-input' %>
+
+ <%= f.label :password, t('devise.password'), class: "form-text" %> + <%= f.password_field :password, placeholder: t('devise.session_new.your_password'), class: 'form-input' %> +
+
+ <%= f.submit t('devise.login'), class: "w-full px-4 py-2 font-bold text-center text-white bg-blue-500 rounded-lg cursor-pointer hover:bg-blue-700" %> +
+ <% end %>
diff --git a/app/views/events/_form.html.erb b/app/views/events/_form.html.erb index 65bcd783..3fe70561 100644 --- a/app/views/events/_form.html.erb +++ b/app/views/events/_form.html.erb @@ -26,7 +26,7 @@
<%= form.label :all_day_event, class: 'form-toggle-layer-1' do %> <%= form.check_box :all_day_event, class: "sr-only peer", checked: event.all_day_event, data:{ datepicker_target:"allDay", action:"click->datepicker#clickedAllDay"} %> -
+
<%=t('calender.all_day_event')%> <% end %>
diff --git a/app/views/events/index.html.erb b/app/views/events/index.html.erb index 37503920..bc1e7278 100644 --- a/app/views/events/index.html.erb +++ b/app/views/events/index.html.erb @@ -3,4 +3,4 @@ data-locale="<%= locale_full_calendar %>" data-new-event-url="<%= new_event_path %>" class="w-full lg:w-2/3 mx-auto" id="event"> -
\ No newline at end of file +
diff --git a/app/views/hrs/index.html.erb b/app/views/hrs/index.html.erb index 6101bb4b..3ece7e48 100644 --- a/app/views/hrs/index.html.erb +++ b/app/views/hrs/index.html.erb @@ -1,111 +1,71 @@ -
- - -
-
-
-
- -
- + <% end %> +
+ <%= form_with(model: @user, url: hrs_path, data: {turbo:false, method: :post}) do |f| %> +

+ <%= t('hrs.new_user') %> +

+
+
+ <%= f.label :name, t('hrs.name_label') , class: 'form-text mt-2' %> + <%= f.text_field :name, placeholder: t('hrs.name_placeholder'), class: 'form-input' %> + <%= f.label :email, t('hrs.email_label'), class: 'form-text mt-2' %> + <%= f.email_field :email, placeholder: t('hrs.email_placeholder'), class: 'form-input' %> +
+
+ <%= f.label :password, t('hrs.password_label'), class: 'form-text mt-2' %> + <%= f.password_field :password, placeholder: t('hrs.password_placeholder'), class: 'form-input' %> + <%= f.label :password_confirmation, t('hrs.password_confirmation_label'), class: 'form-text mt-2' %> + <%= f.password_field :password_confirmation, placeholder: t('hrs.password_confirmation_placeholder'), class: 'form-input mt-4 sm:absolute sm:bottom-0' %> +
+
+ <%= f.label t('hrs.role'), class: "form-text mt-2" %> + <%= f.select :role, User.roles.keys.map { |w| [w.humanize, w]}, {}, { class: 'form-input' } %> + <%= f.submit t('hrs.new_user'), class: " mt-4 sm:absolute sm:bottom-0 w-full px-4 py-2 font-bold text-center text-white bg-blue-500 rounded-lg cursor-pointer hover:bg-blue-700" %>
-
-
- - - - - - + <% end %> + + +
+
<%= t('hrs.user_lists') %>
+ + + + + + + + + + + + <% @users.each do |user| %> + <%= form_for(user, url: hr_path(user), data:{turbo: false, method: :patch}) do |f| %> +
- - - - - - + + + + + +
+
+ - <% @users.each do |user| %> - <%= form_for(user, url: hr_path(user), remote: true, method: :patch) do |f| %> -
-
- - - - - -
-
- - - - <% end %> - <% end %> -
<%= t('hrs.user_lists') %>
<%= t('hrs.name') %><%= t('hrs.email') %><%= t('hrs.role') %><%= t('hrs.update_column') %><%= t('hrs.delete_column') %>
<%= t('hrs.name') %><%= t('hrs.email') %><%= t('hrs.role') %><%= t('hrs.update_column') %><%= t('hrs.delete_column') %><%= f.text_field :name, class: 'bg-gray-50 border border-gray-300 w-full text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 mt-3 mx-1' %><%= f.text_field :email, class: 'bg-gray-50 border border-gray-300 w-full text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 mt-3 mx-1' %><%= f.select(:role, User.roles.keys.map { |w| [w.humanize, w]}, {}, { class: 'bg-gray-50 border border-gray-300 w-full text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 mt-3 mx-1' }) %> + <%= f.submit t('hrs.update'), class: "cursor-pointer bg-blue-500 hover:bg-blue-700 text-white font-bold rounded px-3 py-1.5 mt-3 mx-1 text-2xl rotate-90" %> + <%= link_to t('hrs.delete'), hr_path(user), class: "bg-white hover:bg-red-200 hover:border-red-400 text-gray-400 border hover:text-red-600 font-bold rounded inline-block mt-3 mx-1 py-2.5 px-4", data: {turbo_method: 'delete', turbo_confirm: t('hrs.delete_confirm') } %>
<%= f.text_field :name, class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 mt-3 mx-1' %><%= f.text_field :email, class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 mt-3 mx-1' %><%= f.select(:role, User.roles.keys.map { |w| [w.humanize, w]}, {}, { class: 'bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 mt-3 mx-1' }) %><%= f.submit t('hrs.update'), class: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded px-4 py-2.5 mt-3 mx-1" %><%= link_to t('hrs.delete'), hr_path(user), class: "bg-red-500 hover:bg-red-700 text-white font-bold rounded inline-block mt-3 mx-1 py-2.5 px-4", data: {turbo_method: 'delete', turbo_confirm: t('hrs.delete_confirm') } %>
-
-
-
-
+
+ <% end %> + <% end %> + +
diff --git a/app/views/layouts/_app_navbar.html.erb b/app/views/layouts/_app_navbar.html.erb index 77e9fc42..a9c8a36b 100644 --- a/app/views/layouts/_app_navbar.html.erb +++ b/app/views/layouts/_app_navbar.html.erb @@ -1,20 +1,20 @@ -